介绍 webpack-bundle-analyzer 这个插件来分析SPA应用。
使用
npm install --save-dev webpack-bundle-analyzer
在webpack的plugins中配置: new BundleAnalyzerPlugin()
在package.json 中增加: "analyz": "NODE_ENV=production npm_config_report=true npm run build"
npm run analyz 后会自动打开 http://127.0.0.1:8888/ ,视图如下:
vendor包属于工程基础包,里面包含了node_modules下的依赖模块,因为这些依赖是比较稳定的,所以可以配合ETag做http层的缓存。
use-repeat包属于业务基础包,里面包含业务场景常用到依赖和工具,打入此包的前提:在应用中重复使用大于等于3次。
为什么需要分出 工程基础包 和 业务基础包?
工程基础包是整个工程常用的node_modules的依赖,这里的内容不会经常变动,所以单独抽出来并且搭配ETag来实现缓存是常用的spa 优化方案。
业务基础包大部分不是node_modules的模块,例如我们在common中存放的一些基础组件,其次是一些三方的组件库(这些是在node_modules中的,但是因为经常变动所以不适宜放在vendor中)。如果业务基础包不进行提取会导致单chunk包重复打包相同模块,也增加了单chunk包的体积。
对应的webpack配置如下:
// 工程基础包
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
minChunks: function (module, count) {
return (module.resource && /\.js$/.test(module.resource) && module.resource.indexOf(path.join(__dirname, '../node_modules')) === 0)
}
})
// 业务基础包
new webpack
.optimize
.CommonsChunkPlugin({
async: 'use-repeat',
minChunks: (module, count) => (count >=3)
})
到此还不算结束,因为如果要配合ETag做缓存,需要保证打出来包hash不能改变,下面是常见的output 配置:
output: {
path: path.join(__dirname, '../dist'),
filename: '[name]-[chunkhash].js',
chunkFilename: '[name]-[chunkhash].chunk.js'
}
hash 是 build-specific ,即每次编译都不同——适用于开发阶段
chunkhash 是 chunk-specific,是根据每个 chunk 的内容计算出的 hash——适用于生产
使用chunkhash就保险了吗?
这里涉及到三个问题:1.webpack运行文件 2.module id 3.chunk id , 解决方案如下:
// 将webpack运行文件抽离出来,不然每次打包运营文件的hash都会改变
new webpack.optimize.CommonsChunkPlugin({
name: 'runtime'
})
// 固定module id
new webpack.HashedModuleIdsPlugin({
hashFunction: 'md5',
hashDigest: 'hex',
hashDigestLength: 8
})
// 固定chunk id
new webpack.NamedChunksPlugin((chunk) => {
// 解决异步模块打包的问题
if (chunk.name) {
return chunk.name;
}
return chunk.modules.map(m => path.relative(m.context, m.request)).join("_");
})