从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变更
报错信息:
throw new WebpackOptionsValidationError
configuration.resolve.extensions[0] should not be empty
...
提示是resolve.extensions写法有问题,查看了一下extensions文档
This option no longer requires passing an empty string. 不再支持空字符的写法了。
webpack1.x写法:
resolve: {
root: ....
extensions: ['', '.js', '.jsx', '.json']
},
webpack2写法:
resolve: {
root: ....
extensions: ['*', '.js', '.jsx', '.json']
},
报错信息:
configuration.resolve has an unknown property 'root'. These properties are valid:
...
原来root写法也变了,root放在modules里了。
resolve: {
modules: [
path.resolve(__dirname, 'src'), 'node_modules'
]
}
}
3.loaders => rules
configuration.module.rules[0].use should be one of these: ...
接下来应该就是一堆loader写法有问题,loader已经全部改成了rules的写法,并且为了更加严谨?之前省略的loader后缀也得加上。由于webpack2会自动给加载json文件,所以json-loader也就不再需要了,查看这里。
webpack1.x写法:
webpackConfig.module.loaders = [{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
loader: 'babel',
query: ''
}, {
test: /\.json$/,
loader: 'json'
}]
webpack2.x写法:
webpackConfig.module.loaders = [{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: [{
loader: 'babel-loader',
query: {
cacheDirectory: true,
plugins: [..plugins],
presets: [..presets]
}
}]
}]
css-loader,style-loader的配置:
webpack1.x写法:
webpackConfig.module.loaders.push({
test: /\.css$/,
exclude: null,
loaders: [
'style',
'css?modules&importLoaders=1&sourceMap&minimize',
'postcss?pack=default'
]
})
webpack2.x写法:
webpackConfig.module.rules.push({
test: /\.css$/,
exclude: null,
use: [
'style-loader',
{
loader: 'css-loader',
opitions: {
modules: true,
sourceMap: true,
minimize: true,
importLoaders: 1
}
},
'postcss-loader'
]
})
==注意== 这里css-loder的minimize默认是不开启的,建议开启压缩可以缩小文件大小。babel-loader的cacheDirectory开启缓存可以加速编译过程。
4.extract-text-webpack-plugin
修改原来的ExtractTextPlugin插件配置,对css文件进行处理,发现报如下错误:
报错:
throw new Error("Chunk.entry was removed. Use hasRuntime()");
google了一下发现是当前版本(1.0.1)已经不适用, 升级到2.0。
webpackConfig.module.rules.push({
test: /\.css$/,
use: extractText.extract({
use:[
{ loader: 'style-loader' },
{
loader: 'css-loader',
options: {
sourceMap: true,
minimize: true,
importLoaders: 1,
modules: true
}
},
{ loader: 'postcss-loader' }
] })
})
const extractText = new ExtractTextPlugin({
filename: 'styles/[name].[contenthash].css',
allChunks: true,
disable: __DEV__
})
webpackConfig.plugins.push(extractStyles)
5.postcss-loader
postcss-loader插件配置会麻烦一些,有两种方法:
一种是新建postcss.config.js文件
module.exports = {
plugins: [
require('autoprefixer')({ /* ...options */ })
]
}
另一种:
在webpack.config.js使用LoaderOptionsPlugin
webpackConfig.plugins.push(
new webpack.LoaderOptionsPlugin({
options: {
postcssLoader: () => {
require('autoprefixer')(/* ...options */ )
}
}
})
)
6.loaderUtils Warning
DeprecationWarning: loaderUtils.parseQuery() received a non-string value which can be problematic, see https://github.com/webpack/lo...
貌似是loader-utils模块引起的,没有太明白问题出在哪,issues地址,我在webpack.config.js在加上下面代码解决了。
process.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的文章,不免有误,请及时斧正)
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。