webpack v2升级踩坑笔记

0xinhua 发布于

从 Grunt -> gulp -> webpack, 再到目前当红明星 rollup,前端模块打包技术日新月异,webpack 在今年 1 月份和 6 月份左右接连更新了 v2 和 v3 版本,为了减少冗余模块,缩减bundle 文件大小,webpack v2 中也加入了 tree-shacking 特征, 关于 tree-shacking 的介绍,可以查看知乎如何评价 Webpack 2 新引入的 Tree-shaking 代码优化技术?的讨论。

webpack 在推出 v2 之后迅速推出了 v3 版本,前段时间在知乎看到 webpack 作者LarkInn(他已经入驻sf)说后续会维持一个更快、一致和更稳定的发布周期点这,难道要步 Angular 的后尘,作为吃瓜群众表示很震惊,因为目前自己这边项目 webpack 还停留在 1.x 版本,鉴于减少日后升级难度的想法,包括后续要做代码和流程优化,我将 webpack 升级到了 v2 版本,在这主要把这个升级过程遇到的一些问题分享出来,也方便大家踩坑。

1. 更新版本号

我能想到最简单粗暴的做法就是直接把版本号改了下载新包看下会发生什么。使用 npm info webpack 查看了一下版本的发布信息,我更新到 2.6.1 版本,也是 3.0 前的最后一个版本, 期待看到一大堆报错,但发现 webpack 仍然使用 1.x 版本工作,也就是说包并没有更新到,查了一下发现可能缓存造成的,使用npm cache clean 但貌似也不管用,索性直接把 node_module 删除了,重新安装了一下模块,打包,果然报错了:

2.resolve

报错信息:

js
1throw new WebpackOptionsValidationError 2configuration.resolve.extensions[0] should not be empty 3...

提示是 resolve.extensions 写法有问题,查看了一下 extensions文档

This option no longer requires passing an empty string. 不再支持空字符的写法了。

webpack1.x写法:

js
1resolve: { 2 root: .... 3 extensions: ['', '.js', '.jsx', '.json'] 4}

webpack2写法:

js
1resolve: { 2 root: .... 3 extensions: ['*', '.js', '.jsx', '.json'] 4}

报错信息:

sh
1configuration.resolve has an unknown property 'root'. These properties are valid: 2...

原来 root 写法也变了,root 放在 modules 里了。

javascript
1resolve: { 2 modules: [ 3 path.resolve(__dirname, 'src'), 'node_modules' 4 ] 5}

3.loaders to rules

接下来应该就是一堆 loader 写法有问题,loader已经全部改成 rules 的写法,并且为了更加严谨?之前省略的 loader 后缀也得加上。由于 webpack2 会自动给加载 json 文件,所以 json-loader 也就不再需要了,查看这里

javascript
1configuration.module.rules[0].use should be one of these: ...

webpack 1.x 写法:

javascript
1webpackConfig.module.loaders = [{ 2 test: /\.(js|jsx)$/, 3 exclude: /node_modules/, 4 loader: 'babel', 5 query: '' 6}, { 7 test: /\.json$/, 8 loader: 'json' 9}]

webpack 2.x 写法:

javascript
1webpackConfig.module.loaders = [{ 2 test: /\.(js|jsx)$/, 3 exclude: /node_modules/, 4 use: [{ 5 loader: 'babel-loader', 6 query: { 7 cacheDirectory: true, 8 plugins: [..plugins], 9 presets: [..presets] 10 } 11 }] 12}]

css-loader,style-loader 的配置:

webpack 1.x 写法:

javascript
1webpackConfig.module.loaders.push({ 2 test: /\.css$/, 3 exclude: null, 4 loaders: [ 5 'style', 6 'css?modules&importLoaders=1&sourceMap&minimize', 7 'postcss?pack=default' 8 ] 9})

webpack2.x 写法:

javascript
1webpackConfig.module.rules.push({ 2 test: /\.css$/, 3 exclude: null, 4 use: [ 5 'style-loader', 6 { 7 loader: 'css-loader', 8 opitions: { 9 modules: true, 10 sourceMap: true, 11 minimize: true, 12 importLoaders: 1 13 } 14 }, 15 'postcss-loader' 16 ] 17})

注意这里 css-loder 的 minimize 默认是不开启的,建议开启压缩可以缩小文件大小。babel-loader 的 cacheDirectory 开启缓存可以加速编译过程。

4.extract-text-webpack-plugin

修改原来的 ExtractTextPlugin 插件配置,对 css 文件进行处理,发现报如下错误:

报错如下:

sh
1throw new Error("Chunk.entry was removed. Use hasRuntime()"); 2

google 了一下发现是当前版本(1.0.1)已经不适用, 升级到 2.0。

javascript
1webpackConfig.module.rules.push({ 2 test: /\.css$/, 3 use: extractText.extract({ 4 use:[ 5 { loader: 'style-loader' }, 6 { 7 loader: 'css-loader', 8 options: { 9 sourceMap: true, 10 minimize: true, 11 importLoaders: 1, 12 modules: true 13 } 14 }, 15 { loader: 'postcss-loader' } 16 ] }) 17}) 18const extractText = new ExtractTextPlugin({ 19 filename: 'styles/[name].[contenthash].css', 20 allChunks: true, 21 disable: __DEV__ 22}) 23webpackConfig.plugins.push(extractStyles)

5.postcss-loader

postcss-loader 插件配置会麻烦一些,有两种方法:

新建postcss.config.js文件:

javascript
1module.exports = { 2 plugins: [ 3 require('autoprefixer')({ /* ...options */ }) 4 ] 5}

另一种在 webpack.config.js 使用 LoaderOptionsPlugin:

javascript
1webpackConfig.plugins.push( 2 new webpack.LoaderOptionsPlugin({ 3 options: { 4 postcssLoader: () => { 5 require('autoprefixer')(/* ...options */ ) 6 } 7 } 8 }9)

6.loaderUtils Warning

sh
1DeprecationWarning: loaderUtils.parseQuery() received a non-string value which can be problematic, see https://github.com/webpack/loader-utils/issues/56

貌似是 loader-utils 模块引起的,没有太明白问题出在哪,issues地址,我在 webpack.config.js 在加上下面代码解决了。

javascript
1process.noDeprecation = true

升级总结

v1.x 的时候大家都在吐槽 webpack 文档问题,v2 文档确实提升不少,包括这次的升级如果跟着指南走,基本不会出什么大问题,只是中途在配置 ExtractTextPlugin、postcss 插件时折腾了一些时间。完成这次的升级后,后续准备对流程再进一步的优化,缩减打包时间、减少 bundle 大小等。 这里推荐一款插件webpack-visualizer-plugin,可以将项目的打包情况可视化,清楚了解到每个模块的大小、占比,方便后续的优化。

如果对 v2 版配置还有问题的同学,可以查看我之前的一个 v3.1 版本的webpack.config.js

1.webpack v1 至 v2 升级指南

官方 webapck 1->2升级 guides
另一位同学翻译的升级指南中文版

2.几篇关于升级优化的好文章

Boost webpack build performance | Optimising webpack build performance | Webpack 构建性能优化探索
webpack2 终极优化

3.关于 webpack 的好文章集合(awesome-webpack)

搜罗一切webpack的好文章好工具

(ps:第一次写关于webpack的文章,不免有误,请及时斧正)