如何優雅的升級到webpack4

前言

如今距離2018年2月15號webpack4.0.0出來已經有一段時間了,如今已經出了 @vue/cli 3.0,可是樓主還沒試過,據說很強大,想要試水的能夠看文檔 @vue/cli,官方腳手架都用上webpack4了,你項目還停留在webpack3,甚至webpack2,是否是以爲落伍了。 受號稱0配置的parcel啓發,webpack4 增長了一些默認配置,摒棄掉了一些難懂的配置,對用戶更加友好,下面我來說一講比較大的一些變化javascript

環境

再也不支持 Node.js 4。css

默認出入口

在 Webpack 4 中,再也不強制要求指定 entry 和 output 路徑。webpack 4 會默認 entry 爲 ./src,output 爲 ./dist,固然了,這只是開胃菜。前端

mode 構建模式

webpack 提供了兩種構建模式可供選擇 development 和 productionvue

選項 描述
development 會將 process.env.NODE_ENV 的值設爲 development。啓用 NamedChunksPlugin(固化 runtime 內以及在使用動態加載時分離出的 chunk 的 chunk id) 和 NamedModulesPlugin(開啓 HMR[熱重載]的時候使用該插件會顯示模塊的相對路徑)。
production 會將 process.env.NODE_ENV 的值設爲 production。啓用 FlagDependencyUsagePlugin, FlagIncludedChunksPlugin, ModuleConcatenationPlugin, NoEmitOnErrorsPlugin, OccurrenceOrderPlugin, SideEffectsFlagPlugin 和 UglifyJsPlugin.

也就是說若是 mode 爲development 時候官方腳手架能夠砍掉的代碼java

// webpack.development.config.js
module.exports = {
+ mode: 'development'
- plugins: [
-   new webpack.NamedModulesPlugin(),
-   new webpack.DefinePlugin({
-     'process.env': require('../config/dev.env')
-   }),
- ]
}
複製代碼

若是 mode 爲production 時候官方腳手架能夠砍掉的代碼node

// webpack.production.config.js
module.exports = {
+  mode: 'production',
-  plugins: [
-    new UglifyJsPlugin(/* ... */),
-    new webpack.DefinePlugin({
-       'process.env': require('../config/dev.env')
-    }),
-    new webpack.optimize.ModuleConcatenationPlugin()
-  ]
}
複製代碼

import(): 動態導入

在 webpack 4 中,import() 會返回一個帶命名空間(namespace)的對象,這對 ES Module 不會有影響,但對於遵循 commonjs 規範的模塊則會加一層包裹:webpack

// webpack 2/3
import("./commonjs").then(exports => {
	// ...
})

// webpack 4
import("./commonjs").then({default: exports}=> {
	// ...
})
複製代碼

optimization 配置項

配置項新增了 optimization 選項,智能的根據所選模式mode爲作運行優化。git

使用這個配置的時候以前的一些插件可使用 optimization 裏的配置代替es6

  • NoEmitOnErrorsPlugin 替換爲 optimization.noEmitOnErrors (默認只在 production 模式)
  • ModuleConcatenationPlugin 替換爲 optimization.concatenateModules(默認只在 production 模式)
  • NamedModulesPlugin 替換爲 optimization.namedModules(默認只在 develoment 模式) CommonsChunkPlugin 插件被棄用,使用 optimization.splitChunks, optimization.runtimeChunk 代替
// webpack.prod.conf.js
const config = {
   // ...
   plugins: [
-    new webpack.NoEmitOnErrorsPlugin(),
-    new webpack.optimize.ModuleConcatenationPlugin(),    // 預編譯
-    new webpack.optimize.CommonsChunkPlugin({
-      name: 'vendor',
-      minChunks (module) {
-        // any required modules inside node_modules are extracted to vendor
-        return (
-          module.resource &&
-          /\.js$/.test(module.resource) &&
-          module.resource.indexOf(
-            path.join(__dirname, '../node_modules')
-          ) === 0
-        )
-      }
-    }),
-    new webpack.optimize.CommonsChunkPlugin({
-      name: 'manifest',
-      minChunks: Infinity
-    }),
   ],
+  optimization: {
+    noEmitOnErrors: true,
+    concatenateModules: true,
+    splitChunks: { 
+       chunks: 'all', 
+       name: 'common', 
+    }, 
+    runtimeChunk: { 
+        name: 'runtime'
+    }
+  }
};
複製代碼
// webpack.dev.conf.js
const config = {
   // ...
   plugins: [
-    new webpack.NamedModulesPlugin()
   ]
+  optimization: {
+    namedModules: true
+  }
};
複製代碼

optimization.splitChunks 默認是不用設置的。若是 mode 是 production,那 Webpack 4 就會開啓 Code Splitting。默認 Webpack 4 只會對按需加載的代碼作分割。若是咱們須要配置初始加載的代碼也加入到代碼分割中,能夠設置 splitChunks.chunks 爲 'all'github

壓縮

webpack4 的mode 設置成 production 時,默認開啓代碼壓縮,可是我要敲黑板,劃重點了,uglifyjs-webpack-plugin 終於到 v1.0.0 版本了,支持多進程壓縮,緩存以及es6語法,無需單獨安裝轉換器。感動不感動。想看的話能夠看這裏順風車。想要覆蓋配置能夠這樣

const UglifyJsPlugin = require('uglifyjs-webpack-plugin')

module.exports = {
  // ...
  optimization: {
    minimizer: [
      new UglifyJsPlugin() // 具體配置可看github
    ]
  }
}
複製代碼

##移除的功能 ## 移除了 module.loaders 移除了 loaderContext.options 移除了 Compilation.notCacheable 移除了 NoErrorsPlugin 移除了 Dependency.isEqualResource 移除了 NewWatchingPlugin 移除了 CommonsChunkPlugin

周邊

既然講了 webpack 作了比較大的更新,周邊的配套設施也不要不捨得,改換久換,因爲我平時項目中使用vue,若是你也使用vue的話,那麼針對vue的有幾個變化你要知道:

vue-loader

什麼?學不動了,只要用官網的腳手架不就行了?前端的知識不斷更新,固步自封,只會不進則退。可是你要相信,webpack也好,vue-loader 也好,api 會愈來愈好懂,性能也會更加高效,因此,扶我起來,我還能學。。。

Vue Loader v15 使用了一個不同的策略來推導語言塊使用的 loader。vue-loader v15 在 v14 或更低版本中,若是你想爲一個推導出來的 loader 定製選項,你不得不在 Vue Loader 本身的 loaders 選項中將它重複一遍。在 v15 中你再也沒有必要這麼作了。 拿官方腳手架來講, 能夠看到兩個函數,用來生成 vue-loader 的 options 還有 module.rule, 我把他們摘出來,就能夠看出來了。

// util.js
exports.cssLoaders = function (options) {
   // ...
}

// Generate loaders for standalone style files (outside of .vue)
exports.styleLoaders = function (options) {
  // ...
}

複製代碼
// vue-loader-conf.js
module.exports = {
  loaders: utils.cssLoaders({
    sourceMap: sourceMapEnabled,
    extract: isProduction
  }),
  ...
}
複製代碼
// webpack.dev.config
const devWebpackConfig = merge(baseWebpackConfig, {
  module: {
    rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS: true })
  },
  ...
}
複製代碼

我剛入腳手架的坑的時候都蒙了,爲何要這樣寫,爲了德瑪西亞麼?固然不是,是由於填 vue-loader v14 的坑 vue-loader v15版本只要寫一遍就行了,可是要注意請確保在你的 webpack 配置中添加 Vue Loader 的插件

// webpack.config.js
const VueLoaderPlugin = require('vue-loader/lib/plugin')

module.exports = {
  module: {
    rules: [
      {
        test: /\.vue$/,
        loader: 'vue-loader'
      },
      // ...
    ]
  },
  plugins: [
    // 請確保引入這個插件!
    new VueLoaderPlugin()
  ]
}
複製代碼

而後因爲生產和測試環境對 css 文件處理不一樣。在webpack.dev.config.js和webpack.prod.config.js裏分別配置 less/scss css 的loader就行了:

{
  module: {
    rules: [
      // ...
      {
        test: /\.less$/,
        use: [
          'vue-style-loader',
          'css-loader',
          'less-loader'
        ]
      }
    ]
  }
}
複製代碼

mini-css-extract-plugin css 抽取

webpack v4 官方不在推薦使用 extract-text-webpack-plugin 了,改換 mini-css-extract-plugin

// webpack4
npm install -D mini-css-extract-plugin

// webpack.config.js
var MiniCssExtractPlugin = require('mini-css-extract-plugin')

module.exports = {
  // 其它選項...
  module: {
    rules: [
      // ... 忽略其它規則
      {
        test: /\.css$/,
        use: [
          process.env.NODE_ENV !== 'production'
            ? 'vue-style-loader'
            : MiniCssExtractPlugin.loader,
          'css-loader'
        ]
      }
    ]
  },
  plugins: [
    // ... 忽略 vue-loader 插件
    new MiniCssExtractPlugin({
      filename: style.css
    })
  ]
}
複製代碼
// webpack3
npm install -D extract-text-webpack-plugin
// webpack.config.js
var ExtractTextPlugin = require("extract-text-webpack-plugin")
module.exports = {
  // 其它選項...
  module: {
    rules: [
      // ...其它規則忽略
      {
        test: /\.css$/,
        loader: ExtractTextPlugin.extract({
          use: 'css-loader',
          fallback: 'vue-style-loader'
        })
      }
    ]
  },
  plugins: [
    // ...vue-loader 插件忽略
    new ExtractTextPlugin("style.css")
  ]
}
複製代碼

福利

對webpack3官方腳手架還不是很瞭解的同窗能夠看我根據本身理解寫的註釋,詳情點這裏 以爲麻煩,不想本身搞?那也不要緊,我本身按照腳手架改了一套,感興趣的能夠試試點這裏 以爲不錯請star哦,另外,我準備在下一篇文章中將如何如優化webpack,喜歡的話可關注

參考

  1. webpack 文檔
  2. webpack github release
  3. Webpack 4 配置最佳實踐
相關文章
相關標籤/搜索