构建阶段:
- 开始编译:执行Compiler对象的run方法,创建Compilation对象。
- 确认编译入口:进入entryOption阶段,读取配置的Entries,递归遍历所有的入口文件,调用Compilation.addEntry将入口文件转换为Dependency对象。
- 编译模块(make):从entry文件开始,调用loader对模块进行转译处理,然后调用JS解释器(acorn)将内容转化为AST对象,然后递归分析依赖,依次处理全部文件。
- 完成模块编译:在上一步处理好所有模块后,得到模块编译产物和依赖关系图。
1. 使用动态加载,包括require.ensure方法和动态import方法,使用以后会按照模块分包打包
上面的Mysql,Redis等页面对应的是一个路由页面
2. Webpack插件plugin
2.1 从js中提取css插件:MiniCssExtractPlugin
如上图,除了Mysql**.js,还有Mysql**.css
2.2 OptimizeCssAssetsPlugin
优化css资源,压缩css文件
2.3 DefinePlugin
编译时创建全局变量,例如对于umi框架,先使用cross-nev注入环境变量到contig/contig.ts文件中,contig.ts中可以配置全局变量APP_ENV,API_ENV等,这样我们可以全局使用这些变量
2.4 webpack优化配置optimization拆包分包
optimization: {
splitChunks: {
chunks: "async",
minSize: 30000,
maxSize: 0,
minChunks: 3,
maxAsyncRequests: 5,
maxInitialRequests: 3,
automaticNameDelimiter: "~",
name: true,
cacheGroups: {
vendors: {
name: "vendor",
minChunks: 5,
test: /[\\/]node_modules[\\/]/,
priority: -20,
},
},
},
runtimeChunk: {
name: "manifest",
},
minimizer: [
new TerserPlugin({
cache: true,
parallel: true,
terserOptions: {
output: {
comments: false,
},
compress: {
drop_console: true,
},
safari10: true,
},
}),
new OptimizeCSSAssetsPlugin({}),
],
},
chunks: "async"参数会默认将异步的代码从app.[contenthash].js分离出来,但是cacheGroups配置中里对node_modules的代码分片可能会不生效,如果想要按照路由和node_modules拆分js,chunks: "initial":
- 0_chunk.[contenthash].js是react-router下的第一个页面,位于.src/views/Login/index.tsx
- antd_chunk.*.js和react_chunk.*.js是将第三方公共模块代码分离出来,配置如下:
- 另外我们把自己写的代码按照路由拆出来以后属于业务代码,放在了js目录下,而公共代码放在chunk目录下,这是因为配置了output输出位置:
2.5 TerserPlugin
压缩js,减少代码体积,放在optimization下面。
minimizer: [new TerserPlugin({
extractComments: false,
terserOptions: {
compress: {
drop_console: true,
},
output: {
comments: true,
},
},
})],
2.6 devserver
热更新,文件不能输出为[name].[contenthash].js使用hash替换
2.7 runtimeChunk
runtimeChunk: {
name: "manifest",
},
runtime部分的代码抽离出来单独打包。当一个文件没有修改,但是runtime那部分代码(runtime代码用来表示跟其他依赖包之间的依赖关系)改变了,文件会重新生成,这时候将untime部分的代码提取出来就可以做到文件不会重新生成。
2.8 contenthash和hash
hash在一个文件修改时,所以文件重新生成,contenthash只会重新生成修改的那些文件。