Webpack2 升級指南和特性摘要

歷時多日,webpack2.2正式版終於趕在年前發佈了,這次更新相對於1.X版本有了諸多的升級優化改進,筆者也在第一時間查閱了官方的文檔,整理和翻譯了由webpack1升級到2所須要瞭解的API變動和注意事項,翻譯不足的地方也歡迎隨時交流指正。javascript

原文連接:Webpack2 Migrating
譯者:Abcat && 會飛的魚css

resolve.root, resolve.fallback, resolve.modulesDirectories

上述三個選項將被合併爲一個標準配置項:resolve.modules. 更多關於resolve的信息信息可查閱 resolving .前端

resolve: {
-   root: path.join(__dirname, "src")
+   modules: [
+     path.join(__dirname, "src"),
+     "node_modules"
+   ]
  }

resolve.extensions

該配置項將再也不要求強制轉入一個空字符串,而被改動到了resolve.enforceExtension下, 更多關於resolve的信息信息可查閱 resolving .java

resolve.*

更多相關改動和一些不經常使用的配置項在此不一一列舉,你們若是在實際項目中用到能夠到resolving 中進行查看.node

module.loaders 將變爲 module.rules

舊版本中loaders配置項將被功能更爲強大的rules取代,同時考慮到新舊版本的兼容,以前舊版本的module.loaders的相關寫法仍舊有效,loaders中的相關配置項也依舊能夠被識別。webpack

新的loader配置規則會變得更加通俗易用,所以官方也很是推薦用戶能及時按module.rules中的相關配置進行調整升級。git

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

同webpack1.X中相似,loaders繼續支持鏈式寫法,可將相關正則匹配到的文件資源數據在幾個loader之間進行共享傳遞,詳細使用說明可見 rule.usees6

在wepback2中,用戶可經過use項來指定須要用到的loaders列表(官方推薦),而在weback1中,若是須要配置多個loaders則須要依靠簡單的 !符來切分,這種語法出於新舊兼容的考慮,只會在module.loaders中生效。github

module: {
-   loaders: {
+   rules: {
      test: /\.less$/,
-     loader: "style-loader!css-loader!less-loader"
+     use: [
+       "style-loader",
+       "css-loader",
+       "less-loader"
+     ]
    }
  }

module名稱後自動自動補全 -loader的功能將被移除

在配置loader時,官方再也不容許省略-loader擴展名,loader的配置寫法上將逐步趨於嚴謹。web

module: {
    rules: [
      {
        use: [
-         "style", // 請勿再省略'-loader'
+         "style-loader",
-         "css",
+         "css-loader",
-         "less",
+         "less-loader",
        ]
      }
    ]
  }

固然,若是你想繼續保持以前的省略寫法,你寫能夠在resolveLoader.moduleExtensions中開啓默認擴展名配置,不過這種作法並不被推薦。

+ resolveLoader: {
+   moduleExtensions: ["-loader"]
+ }

能夠從這裏查看 #2986 這次變動的緣由;

json-loader 無須要獨立安裝

當咱們須要讀取json格式文件時,咱們再也不須要安裝任何loader,webpack2中將會內置 json-loader,自動支持json格式的讀取(喜大普奔啊)。

module: {
    rules: [
-     {
-       test: /\.json/,
-       loader: "json-loader"
-     }
    ]
  }

爲什麼須要默認支持json格式 官方的解釋是爲了在webpack, node.js and browserify三種構建環境下提供無差別的開發體驗。

loader配置項將默認從context中讀取

在webpack 1中的一些特殊的loader在讀取對應資源時,須要經過require.resolve指定後才能指定生效。從webpack 2後,配置loader在直接從context中進行讀取,這就解決了一些在使用「npm連接」或引用模塊以外的context形成的模塊重複導入的問題。

配置中能夠刪除以下代碼:

module: {
    rules: [
      {
        // ...
-       loader: require.resolve("my-loader")
+       loader: "my-loader"
      }
    ]
  },
  resolveLoader: {
-   root: path.resolve(__dirname, "node_modules")
  }

module.preLoadersmodule.postLoaders 將被移除

module: {
-   preLoaders: [
+   rules: [
      {
        test: /\.js$/,
+       enforce: "pre",
        loader: "eslint-loader"
      }
    ]
  }

以前須要用到preLoader的地方能夠改到rules的enfore中進行配置。

UglifyJsPlugin中的 sourceMap配置項將默認關閉

UglifyJsPlugin中的sourceMap 默認項將從 true變爲 false

這就意味着當你的js編譯壓縮後,須要繼續讀取原始腳本信息的行數,位置,警告等有效調試信息時,你須要手動開啓UglifyJsPlugin 的配置項:sourceMap: true

devtool: "source-map",
  plugins: [
    new UglifyJsPlugin({
+     sourceMap: true
    })
  ]

UglifyJsPlugin 的警告配置將默認關閉

UglifyJsPlugin中的 compress.warnings 默認項將從 true變爲 false

這就意味着當你想在編譯壓縮的時候查看一部分js的警告信息時,你須要將compress.warnings 手動設置爲 true

devtool: "source-map",
  plugins: [
    new UglifyJsPlugin({
+     compress: {
+       warnings: true
+     }
    })
  ]

UglifyJsPlugin 再也不支持讓 Loaders 最小化文件的模式了

UglifyJsPlugin 將再也不支持讓 Loaders 最小化文件的模式。debug 選項已經被移除。Loaders 不能從 webpack 的配置中讀取到他們的配置項。

loader的最小化文件模式將會在webpack 3或者後續版本中被完全取消掉.

爲了兼容部分舊式loader,你能夠經過 LoaderOptionsPlugin 的配置項來提供這些功能。

plugins: [
+   new webpack.LoaderOptionsPlugin({
+     minimize: true
+   })
  ]

BannerPlugin 配置項將有所改變

BannerPlugin 將再也不容許接受兩個參數,而是隻提供一個對象配置項

plugins: [
-    new webpack.BannerPlugin('Banner', {raw: true, entryOnly: true});
+    new webpack.BannerPlugin({banner: 'Banner', raw: true, entryOnly: true});
  ]

OccurrenceOrderPlugin將被內置加入

不須要再針對OccurrenceOrderPlugin進行配置

plugins: [
-   new webpack.optimize.OccurrenceOrderPlugin()
  ]

ExtractTextWebpackPlugin 配置項將有所改變

ExtractTextPlugin 1.0.0 在webpack v2將沒法使用,你須要從新指定安裝ExtractTextPlugin 的webpack2的適配版本.

npm install --save-dev extract-text-webpack-plugin@beta

更新後的ExtractTextPlugin版本會針對wepback2進行相應的調整。

ExtractTextPlugin.extract的配置書寫方式將調整

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})的配置書寫方式將調整

plugins: [
-  new ExtractTextPlugin("bundle.css", { allChunks: true, disable: false })
+  new ExtractTextPlugin({
+    filename: "bundle.css",
+    disable: false,
+    allChunks: true
+  })
]

全量動態加載資源將默認失效

只有使用一個表達式的資源依賴引用(i. e. require(expr)),如今將建立一個空的context,而不是一個context的完整目錄。

當在es2015的模塊化中沒法工做時,請最好重構這部分的代碼,若是沒法進行修改這部分代碼,你能夠在ContextReplacementPlugin中來提示編譯器作出正確處理。

Cli使用自定義參數做爲配置項傳入方式將作調整

若是你隨意將自定義參數經過cli傳入到配置項中,如:

webpack --custom-stuff

// webpack.config.js
var customStuff = process.argv.indexOf("--custom-stuff") >= 0;
/* ... */
module.exports = config;

你會發現這將不會被容許,cli的執行將會遵循更爲嚴格的標準。

取而代之的是用一個接口來作傳遞參數配置。這應該是新的代替方案,將來的工具開發也可能依賴於此。

webpack --env.customStuff

module.exports = function(env) {
  var customStuff = env.customStuff;
  /* ... */
  return config;
};

查看更多介紹 CLI.

require.ensure 和 AMD require將採用異步式調用

require.ensureamd require將默認採用異步的加載方式來調用,而非以前的當模塊請求加載完成後再在回調函數中同步觸發。

require.ensure將基於原生的Promise對象從新實現,當你在使用 require.ensure 時請確保你的運行環境默認支持Promise對象,若是缺乏則推薦使用安裝polyfill.

Loader的配置項將經過options來設置

webpack.config.js中將再也不容許使用自定義屬性來配置loder,這直接帶來的一個影響是:在ts配置項中的自定義屬性將沒法在被在webpack2中正確使用:

module.exports = { 
  ...
  module: { 
    rules: [{ 
      test: /\.tsx?$/,
      loader: 'ts-loader'
    }]
  },
  // does not work with webpack 2
  ts: { transpileOnly: false } 
}
什麼是options?

這是一個很是好的提問,嚴格意義上來講,custom propertyoptions均是用於webpack loader的配置方式,從更通俗的說法上看,options應該被稱做query,做爲一種相似字符串的形式被追加到每個loader的命名後面,很是相似咱們用於url中的查詢字符串,但在實際應用中功能要更爲強大

module.exports = { 
  ...
  module: { 
    rules: [{ 
      test: /\.tsx?$/,
      loader: 'ts-loader?' + JSON.stringify({ transpileOnly: false })
    }]
  }
}

options也可做爲一個獨立的字面對象量,在loader的配置中搭配使用。

module.exports = { 
  ...
  module: { 
    rules: [{ 
      test: /\.tsx?$/,
      loader: 'ts-loader'
      options:  { transpileOnly: false }
    }]
  }
}

LoaderOptionsPlugin context

部分loader須要配置context信息, 而且支持從配置文件中讀取。這須要loader經過用長選項傳遞進來,更多loader的明細配置項能夠查閱相關文檔。

爲了兼容部分舊式的loader配置,也能夠採用以下插件的形式來進行配置:

plugins: [
+   new webpack.LoaderOptionsPlugin({
+     options: {
+       context: __dirname
+     }
+   })
  ]

debug

debug做爲loader中的一個調試模式選項,能夠在webpack1的配置中靈活切換。在webpack2中,則須要loader經過用長選項傳遞進來,更多loader的明細配置項能夠查閱相關文檔。

loder的debug模式在webpack3.0或者後續版本中將會被移除。

爲了兼容部分舊式的loader配置,也能夠採用以下插件的形式來進行配置:

- debug: true,
  plugins: [
+   new webpack.LoaderOptionsPlugin({
+     debug: true
+   })
  ]

Code Splitting with ES2015

在webpack1中,你須要使用require.ensure實現chunks的懶加載,如:

require.ensure([], function(require) {
  var foo = require("./module");
});

在es2015的 loader中經過定義import()做爲資源加載方法,當讀取到符合ES2015規範的模塊時,可實現模塊中的內容在運行時動態加載。

webpack在處理import()時能夠實現按需提取開發中所用到的模塊資源,再寫入到各個獨立的chunk中。webpack2已經支持原生的 ES6 的模塊加載器了,這意味着 webpack 2 可以理解和處理 importexport了。

import()支持將模塊名做爲參數出入而且返回一個Promise對象。

function route(path, query) {
  return import(`./routes/${path}/route`)
    .then(route => new route.Route(query));
}
// This creates a separate chunk for each possible route

這樣作的還有一個額外的好處就是當咱們的模塊加載失敗時也能夠被捕獲到了,由於這些都會遵循Promise的標準來實現。

值得注意的地方:require.ensure的第三個參數選項容許使用簡單的chunk命名方式,可是import API中將不被支持,若是你但願繼續採用函數式的寫法,你能夠繼續使用require.ensure

require.ensure([], function(require) {
  var foo = require("./module");
}, "custom-chunk-name");

(注: System.import將會被棄用,webpack中將再也不推薦使用 System.import,官方也推薦使用import進行替換,詳見v2.1.0-beta.28

若是想要繼續使用Babel中提供的import,你須要獨立安裝 dynamic-import插件而且選擇babel的Stage 3來捕獲時的錯誤, 固然這也能夠根據實際狀況來操做而不作強制約束。

Dynamic expressions 動態表達式

如今import()中的傳參可支持部分表達式的寫法了,若是以前有接觸過CommonJS中require()表達式寫法,應該不會對此感到陌生,(它的操做其實和 CommonJS 是相似的,給全部可能的文件建立一個環境,當你傳遞那部分代碼的模塊還不肯定的時候,webpack 會自動生成全部可能的模塊,而後根據需求加載。這個特性在前端路由的時候頗有用,能夠實現按需加載資源)

import() 會針對每個讀取到的module建立獨立的separte chunk

function route(path, query) {
  return import(`./routes/${path}/route`)
    .then(route => new route.Route(query));
}
// This creates a separate chunk for each possible route

能夠混用 ES2015 和 AMD 和 CommonJS

在 AMD 和 CommonJS 模塊加載器中,你能夠混合使用全部(三種)的模塊類型(即便是在同一個文件裏面)。

// CommonJS consuming ES2015 Module
var book = require("./book");
book.currentPage;
book.readPage();
book.default === "This is a book";
// 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";

注:es2015 balel 的默認預處理會把 ES6 模塊加載器轉化成 CommonJS 模塊加載。要是想使用 webpack 新增的對原生 ES6 模塊加載器的支持,你須要使用 es2015-webpack 來代替,另外若是你但願繼續使用babel,則須要經過配置babel項,使其不會強制解析這部分的module symbols以便webpack能正確使用它們,babel的配置以下:

.babelrc

{
  "presets": [
    ["es2015", { "modules": false }]
  ]
}

Template strings 模板字符串

webpack中的資源參數已經開始支持模板字符串了,這意味着你可使用以下的配置寫法:

- require("./templates/" + name);
+ require(`./templates/${name}`);

配置支持項支持Promise

webpack如今在配置文件項中返回Promise了,這就容許你在配置中能夠進行一些異步的寫法了,以下所示:

webpack.config.js

module.exports = function() {
  // 異步讀取語言包
  return fetchLangs().then(lang => ({
    entry: "...",
    // ...
    plugins: [
      new DefinePlugin({ LANGUAGE: lang })
    ]
  }));
};

Loader匹配支持更多的高級寫法

webpack中的loader配置支持以下寫法:

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 能顯示每一個entry中的module的資源深度

--display-used-exports 能顯示每一個module中依賴使用了哪些資源.

--display-max-modules 能限制顯示output中引用到的資源數量 (默認顯示15個).

-p 指定當前的編譯環境爲生產環境,即修改:process.env.NODE_ENV"production"

Cacheable 緩存項

Loaders如今將默認開啓資源緩存了,若是你不但願loader讀緩存則須要在配置中指明:

// Cacheable loader
  module.exports = function(source) {
-   this.cacheable();
    return source;
  }
// Not cacheable loader
  module.exports = function(source) {
+   this.cacheable(false);
    return source;
  }

Complex options 複合參數項寫法

webpack1中的loader參數項中只支持JSON.stringify-able這種json字符串的寫法;

webpack2中的loader參數項中已經能夠支持任意的JS對象的寫法了。

使用複合選項時會有一個限制,你須要配置一個ident做爲項來保證能正確引用到其餘的loader,這意味着經過配置咱們能夠在內聯寫法中去調用對應依賴的加載器,以下:

require("some-loader??by-ident!resource")

{
  test: /.../,
  loader: "...",
  options: {
    ident: "by-ident",
    magic: () => return Math.random()
  }
}

這種寫法在日常開發中用的不算多,可是有一種場景下會比較有用,就是當咱們的loader須要去生成獨立的代碼片斷時,如,咱們在使用style-loader生成一個模塊時,須要依賴前面的loader計算的結果。

// style-loader generated code (simplified)
var addStyle = require("./add-style");
var css = require("-!css-loader?{"modules":true}!postcss-loader??postcss-ident");
addStyle(css);

在這種複雜選項的使用時ident就有用武之地了。

結尾

webpack2不管是從優化資源配置項,到向es6 module,Promise等新標準接軌,再到編譯環境和性能的優化,再到API設計的總體規範性上,相對V1的改進仍是很是顯著的,但願你們多多嘗試,及時反饋交流,讓webapck的生態圈變得日益活躍強大。

相關文章
相關標籤/搜索