webpack优化
webpack构建流程
- 初始化:启动构建,读取与合并配置参数,加载 Plugin,实例化 Compiler。
- 编译:从 Entry 发出,针对每个 Module 串行调用对应的 Loader 去翻译文件内容,再找到该 Module 依赖的 Module,递归地进行编译处理。
输出:对编译后的 Module 组合成 Chunk,把 Chunk 转换成文件,输出到本地。
_addModuleChain,其完成的第二件事构建模块又可以分为三部分:
- 调用loader处理模块之间的依赖
- 将loader处理后的文件通过acorn抽象成抽象语法树AST
- 遍历AST,构建该模块的所有依赖
流程细节
1. 参数处理
|
|
|
|
- WebpackOptionsApply.process根据选项apply对应的插件,如library/externals/devtool, 包括entry-option, 后面会调用addEntry123456789// webpack3写法//node_modules/webpack/lib/WebpackOptionsApply.js:234compiler.apply(new EntryOptionPlugin());compiler.applyPluginsBailResult("entry-option", options.context, options.entry);// webpack4写法//node_modules/webpack/lib/WebpackOptionsApply.js:306new EntryOptionPlugin().apply(compiler);compiler.hooks.entryOption.call(options.context, options.entry);
2. run 触发compile
- 在run的过程中,会触发了一些钩子:
beforeRun->run->beforeCompile->compile->make->seal
|
|
- 当 Webpack 以开发模式运行时,每当检测到文件变化,一次新的 Compilation 将被创建。
- compiler.watch监视依赖文件的修改
|
|
3. 参数处理
4. 参数处理
5. 参数处理
6. 参数处理
插件问题
日志屏蔽copy-webpack-plugin
- 这个插件每移动一个静态文件打一条日志, static下所有图片遮挡了module输出了.
- options.logLevel 提供以下选项
- warn (default)
- error
- silent
- options.debug 提供以下选项
- warning (default)
- info
- debug
note: debug option was renamed to logLevel in version 5.0, it only accepts string values: trace, debug, info, warn, error and silent
|
|
事实是:
这个插件的option配置只是显示插件打印的信息. 默认是没打印的, 所以不需要改动.
然后看到webpack有个配置是关于控制bundle打印的. stats: {assets: true}
. 但配置了不起作用. 因为那个默认是通过package.json的scripts配置去执行webpack调用的.
而通过node调用的要自己打印日志信息, 而这个stats的选项要另外传入.
然后发现只能配置assets不能配置excludeAssets, 看源码发现2.7版本不支持这选项.折腾了一天索然没解决问题, 但对webpack有更深入的理解.
|
|
耗时查看speed-measure-webpack-plugin
usage
|
|
其他webpack优化
- 合理配置resolve.extensions,减少文件查找
- module.noParse字段告诉Webpack不必解析哪些文件,可以用来排除对非模块化库文件的解析
- 使用DllPlugin减少基础模块编译次数
- DevServer刷新浏览器有两种方式:
- 向网页中注入代理客户端代码,通过客户端发起刷新
- 向网页装入一个iframe,通过刷新iframe实现刷新效果
- Tree Shaking启用要关闭babel模块转换功能
- 首屏按需加载提高首屏交互速度
import(/* webpackChunkName:show */ './show').then()
多个页面依赖的公共代码提取到common.js中
123456plugins:[new CommonsChunkPlugin({chunks:['base','common'],name:'base',//minChunks:2, 表示文件要被提取出来需要在指定的chunks中出现的最小次数,防止common.js中没有代码的情况})- 得到基础库代码base.js,不含基础库的公共代码common.js,和页面各自的代码文件xx.js。
- 页面引用顺序如下:base.js–> common.js–> xx.js
- 得到基础库代码base.js,不含基础库的公共代码common.js,和页面各自的代码文件xx.js。
HtmlWebpackPlugin优化,
bundleanalyze拆分公用模块
其他优化
- 使用Scope Hoisting,需要源码采用了ES6模块化的,否则Webpack会降级处理不采用Scope Hoisting。
- 配置babel-loader时,use: [‘babel-loader?cacheDirectory’] cacheDirectory用于缓存babel的编译结果,加快重新编译的速度。另外注意排除node_modules文件夹,因为文件都使用了ES5的语法,没必要再使用Babel转换。
- 配置externals,排除因为已使用
<script>
标签引入而不用打包的代码,noParse是排除没使用模块化语句的代码。 - 配置performance参数可以输出文件的性能检查配置。
- 配置profile:true,是否捕捉Webpack构建的性能信息,用于分析是什么原因导致构建性能不佳。
- 配置cache:true,是否启用缓存来提升构建速度。
- 可以使用url-loader把小图片转换成base64嵌入到JS或CSS中,减少加载次数。
- 通过imagemin-webpack-plugin压缩图片,通过webpack-spritesmith制作雪碧图。
- 开发环境下将devtool设置为cheap-module-eval-source-map,因为生成这种source map的速度最快,能加速构建。在生产环境下将devtool设置为hidden-source-map
参考
webpack源码之运行流程
Webpack-源码一,使用require加载并打包模块 webpack2~3
Webpack-源码二,整体调用流程与Tapable事件流
深入Webpack-编写Loader
干货!撸一个webpack插件(内含tapable详解+webpack流程)
compiler-hooks
Writing a Plugin
三十分钟掌握Webpack性能优化
理解webpack4.splitChunks之其余要点
浅析webpack源码系列