使用 webpack 提取公共代码(多页应用)
作者:Seiya
时间:2019年07月09日
为什么要提取公共代码
我们都知道,目前前端开发中,主流的开发模式为模块化开发。为了减少代码冗余,提高加载速度,我们需要提取出公共代码。这里就用到了 optimization.splitChunks 配置。
注意:
4.0 版本用 optimization.splitChunks 配置替换了 3.0 版本的 CommonsChunkPlugin 插件。
基础库分离
思路
将第三方通过 CDN 进行引入,而不是打入 bundle 中。比如:将 react、react-dom 基础包通过 CDN 进行引入,而不是直接打包进去。
方法
使用 html-webpack-externals-plugin
插件,具体配置如下:
const HtmlWebpackExternalsPlugin = require('html-webpack-externals-plugin');
module.exports = {
...
plugins: [
new HtmlWebpackExternalsPlugin({
externals: [
{
module: 'react',
entry: 'https://11.url.cn/now/lib/16.2.0/react.min.js',
global: 'React',
},
{
module: 'react-dom',
entry: 'https://11.url.cn/now/lib/16.2.0/react-dom.min.js',
global: 'ReactDOM',
},
]
}),
]
}
编写完配置后,我们还需要在 html 中引入脚本,如下所示:
<script type="text/javascript" src="https://11.url.cn/now/lib/16.2.0/react.min.js"></script>
<script type="text/javascript" src="https://11.url.cn/now/lib/16.2.0/react-dom.min.js"></script>
利用 SplitChunksPlugin 进行公共脚本分离
准备
创建 pageA.js 和 pageB.js 分别作为两个入口文件。同时,这两个入口文件同时引用 subPageA.js 和 subPageB.js,而 subPageA.js 和 subPageB.js 又同时引用 module.js 文件。
module.js
export default "module";
subPageA.js
import "./module"; export default "subPageA";
subPageB.js
import "./module"; export default "subPageB";
最后,我们封装入口文件。为了让情况更真实,这两个入口文件又同时引用了 lodash 这个第三方库:
pageA.js
import "./subPageA"; import "./subPageB"; import * as _ from "lodash"; console.log("At page 'A' :", _); export default "pageA";
pageB.js
import "./subPageA"; import "./subPageB"; import * as _ from "lodash"; console.log("At page 'B' :", _); export default "pageB";
编写 webpack 配置
const path = require('path');
module.exports = {
mode: 'development',
entry: {
pageA: './src/pageA.js',
pageB: './src/pageB.js'
},
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist'), // 打包文件的输出目录
chunkFilename: '[name].chunk.js'
},
optimization: {
splitChunks: {
cacheGroups: {
/* 抽离自己写的公共代码,名字可以随意起 */
common: {
name: 'common',
/**
* chunks 参数说明:
* - async: 异步引入的库进行分离(默认)
* - initial: 同步引入的库进行分离
* - all: 所有引入的库进行分离(推荐)
*/
chunk: 'all',
minChunks: 2 // 设置最小引用次数
minSize: 30000, // 分离包体积的大小
priority: 0
},
/* 抽离第三方插件 */
vendor: {
name: 'vendor', // 打包后的文件名,任意命名
test: /[\\/]node_module[\\/]/, // 匹配出需要分离的包(在node_modules范围内进行匹配)
chunk: 'all',
/* 针对第三方库,通过设置 priority 来让其先被打包提取,最后再提取剩余代码 */
priority: 10 // 设置优先级,防止和自定义的公共代码提取时被覆盖,不进行打包
}
}
}
}
}
更多配置属性,请参考官方文档 optimization.splitChunks。