resolve.root
, resolve.fallback
,resolve.modulesDirectories
上述配置項被一個單獨的配置項 resolve.modules
取代。詳見 resolving。
1 2 3 4 5 6 7 |
resolve: { - root: path.join(__dirname, "src") + modules: [ + path.join(__dirname, "src"), + "node_modules" + ] } |
resolve.extensions
此配置項不再需要傳一個空字串。此行為被遷移到 resolve.enforceExtension
。詳見 resolving。
resolve.*
還有更多的變化,由於不常用,不在這裡詳細列出。詳見 resolving。
module.loaders
改成了 module.rules
舊的 loader 配置被更強大的 rules 系統取代,後者允許配置 loader 以及其他更多項。為了相容舊版,module.loaders
語法被保留,舊的屬性名依然可以被解析。新的命名約定更易於理解並且是升級配置使用 module.rules
的好理由。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
module: { - loaders: [ + rules: [ { test: /\.css$/, - loaders: [ + use: [ { loader: "style-loader" }, { loader: "css-loader", - query: { + options: { modules: true } ] }, { test: /\.jsx$/, loader: "babel-loader", // Do not use "use" here options: { // ... } } ] } |
鏈式 loaders
與 v1 版本相同,loaders 可以鏈式呼叫,上一個 loader 的輸出被作為輸入傳給下一個 loader。使用 rule.use 配置項,use
可以設定為一個 loaders 的列表。在 v1 版本中,loaders 通常被用 !
連寫。這一寫法在新版中只在使用舊的 module.loaders
時有效。
1 2 3 4 5 6 7 8 9 10 11 12 |
module: { - loaders: { + rules: { test: /\.less$/, - loader: "style-loader!css-loader!less-loader" + use: [ + "style-loader", + "css-loader", + "less-loader" + ] } } |
取消了在模組名中自動新增 -loader
字尾
現在在指定 loader 的時候不能再省略 -loader
字尾了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
module: { rules: [ { use: [ - "style", + "style-loader", - "css", + "css-loader", - "less", + "less-loader", ] } ] } |
你仍然可以啟用這一舊行為,方法是通過配置 resolveLoader.moduleExtensions
項,但是我們不推薦這麼做。
1 2 3 |
+ resolveLoader: { + moduleExtensions: ["-loader"] + } |
瞭解這一改變背後的原因,請參閱 #2986。
json-loader
不再需要手動新增
如果沒有為 JSON 檔案配置 loader,webpack 將自動嘗試通過 載入 json-loader JSON 檔案。
1 2 3 4 5 6 7 8 |
module: { rules: [ - { - test: /\.json/, - loader: "json-loader" - } ] } |
我們決定這麼做 以消弭 webpack、 node.js 和 browserify 之間的環境差異。
loader 預設的 resolve 配置是相對於 context 的
在 webpack 1 中,loader 預設配置下 resolve 相對於被匹配的檔案。而在 webpack 2 中預設配置的 resolve 相對於 context
配置項。
這解決了一些問題,比如使用 npm link
或引用 context
之外的模組時導致重複載入。
你可以不再需要使用一些變通方案了:
1 2 3 4 5 6 7 8 9 10 11 12 |
module: { rules: [ { // ... - loader: require.resolve("my-loader") + loader: "my-loader" } ] }, resolveLoader: { - root: path.resolve(__dirname, "node_modules") } |
取消了 module.preLoaders
以及 module.postLoaders
1 2 3 4 5 6 7 8 9 10 |
module: { - preLoaders: [ + rules: [ { test: /\.js$/, + enforce: "pre", loader: "eslint-loader" } ] } |
UglifyJsPlugin
sourceMap
UglifyJsPlugin
的 sourceMap
配置項現在預設為 false
而不是 true
。
這意味著如果你在壓縮程式碼時啟用了 source map,或者想要讓 uglifyjs 的警告能夠對應到正確的程式碼行,你需要將 UglifyJsPlugin
的 sourceMap
設為 true
。
1 2 3 4 5 6 |
devtool: "source-map", plugins: [ new UglifyJsPlugin({ + sourceMap: true }) ] |
UglifyJsPlugin
warnings
UglifyJsPlugin
的 compress.warnings
配置項現在預設為 false
而不是 true
。
這意味著如果你想要看到 uglifyjs 的警告資訊,你需要將 compress.warnings
設為 true
。
1 2 3 4 5 6 7 8 |
devtool: "source-map", plugins: [ new UglifyJsPlugin({ + compress: { + warnings: true + } }) ] |
UglifyJsPlugin
壓縮 loaders
UglifyJsPlugin
不再壓縮 loaders。在未來很長一段時間裡,需要通過設定 minimize:true
來壓縮 loaders。參考 loader 文件裡的相關配置項。
loaders 的壓縮模式將在 webpack 3 或更高的版本中被取消。
為了相容舊的 loaders,loaders 可以通過外掛來切換到壓縮模式:
1 2 3 4 5 |
plugins: [ + new webpack.LoaderOptionsPlugin({ + minimize: true + }) ] |
OccurrenceOrderPlugin
被預設載入
我們不再需要在配置裡指定它:
1 2 3 |
plugins: [ - new webpack.optimize.OccurrenceOrderPlugin() ] |
ExtractTextWebpackPlugin
大變化
ExtractTextPlugin 1.0.0 不能在 webpack v2 下工作。 你需要明確地安裝 ExtractTextPlugin v2。
npm install --save-dev extract-text-webpack-plugin@beta
這一外掛的配置變化主要體現在語法上。
ExtractTextPlugin.extract
1 2 3 4 5 6 7 8 9 10 11 |
module: { rules: [ test: /.css$/, - loader: ExtractTextPlugin.extract("style-loader", "css-loader", { publicPath: "/dist" }) + loader: ExtractTextPlugin.extract({ + fallbackLoader: "style-loader", + loader: "css-loader", + publicPath: "/dist" + }) ] } |
new ExtractTextPlugin({options})
1 2 3 4 5 6 7 8 |
plugins: [ - new ExtractTextPlugin("bundle.css", { allChunks: true, disable: false }) + new ExtractTextPlugin({ + filename: "bundle.css", + disable: false, + allChunks: true + }) ] |
全動態 requires 現在預設會失敗
只有一個表示式的依賴(例如 require(expr)
)將建立一個空的 context 而不是一個完整目錄的 context。
如果有上面那樣的程式碼,最好把它重構了,因為在 ES2015 模組下它不可以用。如果你確定不會有 ES2015 模組,你可以使用 ContextReplacementPlugin
來提示編譯器進行正確的處理。
此處欠一篇關於動態依賴的文章。
在 CLI 和配置中使用自定義引數
如果你之前濫用 CLI 來傳自定義引數到配置中,比如:
webpack --custom-stuff
1 2 3 4 |
// webpack.config.js var customStuff = process.argv.indexOf("--custom-stuff") >= 0; /* ... */ module.exports = config; |
你將會發現新版中不再允許這麼做。CLI 現在更加嚴格了。
替代地,現在提供了一個介面來傳遞引數給配置。我們應該採用這種新方式,在未來許多工具將可能依賴它。
webpack --env.customStuff
1 2 3 4 5 |
module.exports = function(env) { var customStuff = env.customStuff; /* ... */ return config; }; |
詳見 CLI。
require.ensure
以及 AMD require
的非同步
現在這些函式總是非同步的,而不是當 chunk 已經載入過的時候同步呼叫它們的 callback。
注意 require.ensure
現在依賴於原生的 Promise
。如果在不支援 Promise 的環境裡使用require.ensure
,你需要新增 polyfill。
通過 options
配置 loader
你不能再通過 webpack.config.js
的自定義屬性來配置 loader。只能通過 options
來配置。下面配置的 ts
屬性在 webpack 2 下不再有效:
1 2 3 4 5 6 7 8 9 10 11 |
module.exports = { ... module: { use: [{ test: /\.tsx?$/, loader: 'ts-loader' }] }, // does not work with webpack 2 ts: { transpileOnly: false } } |
什麼是 options
?
好問題。嚴格來說,有兩種辦法,都可以用來配置 webpack 的 loader。典型的 options
被稱為query
,是一個可以被新增到 loader 名之後的字串。它比較像一個 query string,但是實際上有更強大的能力:
1 2 3 4 5 6 7 8 9 |
module.exports = { ... module: { use: [{ test: /\.tsx?$/, loader: 'ts-loader?' + JSON.stringify({ transpileOnly: false }) }] } } |
不過它也可以分開來,寫成一個單獨的物件,緊跟在 loader 屬性後面:
1 2 3 4 5 6 7 8 9 10 |
module.exports = { ... module: { use: [{ test: /\.tsx?$/, loader: 'ts-loader' options: { transpileOnly: false } }] } } |
LoaderOptionsPlugin
context
有的 loader 需要從配置中讀取一些 context 資訊。在未來很長一段時間裡,這將需要通過 loader options 傳入。詳見 loader 文件的相關選項。
為了保持對舊 loaders 的相容,這些資訊可以通過外掛傳進來:
1 2 3 4 5 6 7 |
plugins: [ + new webpack.LoaderOptionsPlugin({ + options: { + context: __dirname + } + }) ] |
debug
在 webpack 1 中 debug
配置項切換 loaders 到 debug 模式。在未來很長一段時間裡,這將需要通過 loader 配置項傳遞。詳見 loader 文件的相關選項。
loaders 的 debug 模式將在 webpack 3 或後續版本中取消。
為了保持對舊 loaders 的相容,loader 可以通過外掛來切換到 debug 模式。
1 2 3 4 5 6 |
- debug: true, plugins: [ + new webpack.LoaderOptionsPlugin({ + debug: true + }) ] |
ES2015 的程式碼分割
在 webpack v1 中,你能使用 require.ensure
作為方法來懶載入 chunks 到你的應用中:
1 2 3 |
require.ensure([], function(require) { var foo = require("./module"); }); |
ES2015 模組載入規範定義了 import()
方法來執行時動態地載入 ES2015 模組。
webpack 將 import()
作為分割點並將被請求的模組放到一個單獨的 chunk 中。
import()
接收模組名作為引數,並返回一個 Promise。
1 2 3 4 5 6 7 |
function onClick() { import("./module").then(module => { return module.default; }).catch(err => { console.log("Chunk loading failed"); }); } |
好訊息是:如果載入 chunk 失敗,我們可以進行處理,因為現在它基於 Promise
。
警告:require.ensure
允許用可選的第三個引數為 chunk 簡單命名,但是 import
API 還未提供這個能力。如果你想要保留這個功能,你可以繼續使用 require.ensure
。
1 2 3 |
require.ensure([], function(require) { var foo = require("./module"); }, "custom-chunk-name"); |
(注意廢棄的 System.import
:Webpack 對 System.import
的使用不符合新提出的標準,所以它在v2.1.0-beta.28 版本中被廢棄,轉向支援 import()
)
由於這個建議還在 Stage 3,如果你想要同時使用 import
和 Babel,你需要安裝/新增 dynamic-import 語法外掛來繞過解析錯誤。當建議被新增到規範之後,就不再需要這個語法外掛了。
動態表示式
可以傳遞部分表示式給 import()
。這與 CommonJS 對錶達式的處理方式一致(webpack 為所有可能匹配的檔案建立 context)。
import()
為每一個可能的模組建立獨立的 chunk。
1 2 3 4 5 |
function route(path, query) { return import(`./routes/${path}/route`) .then(route => new route.Route(query)); } // 上面程式碼為每個可能的路由建立獨立的 chunk |
混合使用 ES2015、AMD 和 CommonJS
你可以自由混合使用三種模組型別(甚至在同一個檔案中)。在這個情況中 webpack 的行為和 babel 以及 node-eps 一致:
1 2 3 4 5 6 |
// CommonJS consuming ES2015 Module var book = require("./book"); book.currentPage; book.readPage(); book.default === "This is a book"; |
1 2 3 4 5 6 |
// ES2015 Module consuming CommonJS import fs from "fs"; // module.exports map to default import { readFileSync } from "fs"; // named exports are read from returned object+ typeof fs.readFileSync === "function"; typeof readFileSync === "function"; |
值得注意的是,你需要讓 Babel 不解析這些模組符號,從而讓 webpack 可以使用它們。你可以通過設定如下配置到 .babelrc
或 babel-loader 來實現這一點。
.babelrc
1 2 3 4 5 |
{ "presets": [ ["es2015", { "modules": false }] ] } |
Hints
不需要改變什麼,不過也可以改變。
模板字串
webpack 現在支援表示式中的模板字串了。這意味著你可以在 webpack 構建中使用它們:
1 2 |
- require("./templates/" + name); + require(`./templates/${name}`); |
配置中使用 Promise
webpack 現在支援在配置檔案中返回 Promise
了。這讓你能在配置檔案中做非同步處理。
webpack.config.js
1 2 3 4 5 6 7 8 9 |
module.exports = function() { return fetchLangs().then(lang => ({ entry: "...", // ... plugins: [ new DefinePlugin({ LANGUAGE: lang }) ] })); }; |
高階 loader 匹配
webpack 現在支援對 loader 進行更多方式的匹配。
1 2 3 4 5 6 7 8 9 |
module: { rules: [ { resource: /filename/, // matches "/path/filename.js" resourceQuery: /querystring/, // matches "/filename.js?querystring" issuer: /filename/, // matches "/path/something.js" if requested from "/path/filename.js" } ] } |
更多的 CLI 引數項
你可以使用一些新的 CLI 引數項:
--define process.env.NODE_ENV="production"
見 DefinePlugin
.
--display-depth
顯示每個模組到入口的距離。
--display-used-exports
顯示一個模組中被使用的 exports 資訊。
--display-max-modules
設定輸出時顯示的模組數量(預設是 15)。
-p
能夠定義 process.env.NODE_ENV
為 "production"
。
Loader 變化
僅與 loader 作者有關的改變。
Cacheable
Loaders 現在預設可被快取。Loaders 如果不想被快取,需要選擇不被快取。
1 2 3 4 5 |
// Cacheable loader module.exports = function(source) { - this.cacheable(); return source; } |
1 2 |
複合 options
webpack 1 只支援能夠 JSON.stringify
的物件作為配置項。webpack 2 現在支援任意 JS 物件作為 loader 配置項。
使用複合 options 只有一個附加條件。你需要在 options 物件上新增一個 ident
,讓它能夠被其他 loader 引用。
options 物件上有了 ident
,內聯的 loader 就可以引用這個 options 物件。下面是個例子:
require("some-loader??by-ident!resource")
1 2 3 4 5 6 7 8 |
{ test: /.../, loader: "...", options: { ident: "by-ident", magic: () => return Math.random() } } |
這種內聯風格在常規的程式碼裡一般用不著,但是在 loader 生成的程式碼裡比較常見。比如,style-loader 生成一個模組,通過 require
載入其餘的請求(它們輸出 CSS)。
1 2 3 4 5 |
// style-loader generated code (simplified) var addStyle = require("./add-style"); var css = require("-!css-loader?{"modules":true}!postcss-loader??postcss-ident"); addStyle(css); |
所以如果你使用複合 options,告訴你的使用者你使用的 ident
。