webpack 慢的原因
- string -> ast -> string/buff,文件过多 n * string -> ast -> string/buff
- entry 过多 复杂 繁杂 fonts css js
- async import(/***/‘xxx.js’) entry
解决方案
- async 插件 speed-measure-webpack-plugin
- loader plugins cache-loader 开启线程
- optimize-css-assets-webpack-plguin 开启进程 require(‘os’).cups.leng - 1
- 去 entry 多线程编译 使用 scripty 使用 linux 命令 接管 集群编译
- 业务逻辑拆分,微前端的架构设计
- 准备几台机器,配置免密登录
- 通过远程机器 拉取 git 代码进行编译 让后推送回来(rsync 命令)
1
2
3
4ssh. xxx.xxx.xxx.deyploy.js
....
....
async 回来
webpack-bundle-analyzer 分析体积
1 | npm install webpack-bundle-analyzer -D |
构建完成后会在 8888 端口展示大小
一般推荐使用高版本的node和webpack,因为他们内部自己做了优化
使用 webpack4的原因
V8 带来的优化(for of 替代 forEach、Map 和 Set 替代 Object、includes 替代 indexOf)
默认使用更快的 md4 hash 算法
webpack AST 可以直接从 loader 传递给 AST,减少解析时间
使用字符串方法替代正则表达式
多进程/多实例构建:资源并行解析可选方案
1 | npm install cache-loader thread-loader -D |
使用 thread-loader 解析资源
原理:每次 webpack 解析一个模块,thread-loader 会将它及它的依赖分配给 worker 线程
1 |
|
多进程/多实例:并行压缩
方式一:使用 parallel-uglify-plugin 插件
1 | plugins:[ |
方式二:uglifyjs-webpack-plugin 开启 parallel 参数
1 | plugins:[ |
方法三:terser-webpack-plugin 开启 parallel 参数
optimization:{
minimizer:[
new TerserPlugin({
parallel:4
})
]
}
缩小构建目标
目的:尽可能的少构建模块
比如 babel-loader 不解析 node_modules
1 | rules: [ |
减少文件搜索范围
优化 resolve.extensions 配置
合理使用 alias
1 | resolve: { |
noParse
在 webpack 中,我们需要使用的 loader 是在 module.rules 下配置的,webpack 配置中的 module 用于控制如何处理项目中不同类型的模块。
除了 module.rules 字段用于配置 loader 之外,还有一个 module.noParse 字段,可以用于配置哪些模块文件的内容不需要进行解析。对于一些不需要解析依赖(即无依赖) 的第三方大型类库等,可以通过这个字段来配置,以提高整体的构建速度。
使用 noParse 进行忽略的模块文件中不能使用 import、require、define 等导入机制。
1 | module.exports = { |
图片压缩
使用:配置 image-webpack-loader
1 |
|
无用的 CSS 如何删除掉?
PurifyCSS: 遍历代码,识别已经用到的 CSS class 这个需要和 mini-css-extract-plugin 配合使用
也就是说先提取为css文件然后再使用PurifyCSS
1 | npm install purgecss-webpack-plugin |
构建体积优化
我们可以使用动态 Polyfill -> Polyfill Service
原理:识别 User Agent,下发不同的 Polyfill
如何使用动态 Polyfill service
polyfill.io
官方提供的服务:(引入到index.html中)
1 | <script src="https://cdn.polyfill.io/v2/polyfill.min.js"></script> |
体积优化总结
Scope Hoisting
Tree-shaking
公共资源分离
图片压缩
动态 Polyfill
基础库分离
思路:将 react、react-dom,axios,element-ui 基础包通过 cdn 引⼊,不打⼊ bundle 中
1 | npm install html-webpack-externals-plugin -D |
利⽤ SplitChunksPlugin 进⾏公共脚本分离
SplitChunksPlugin是Webpack4 内置的,替代webpack3的CommonsChunkPlugin插件
async 异步引⼊的库进⾏分离(默认)
initial 同步引⼊的库进⾏分离
all 所有引⼊的库进⾏分离(推荐)
1 | optimization: { |
treeShaking(摇树优化)
treeShaking(摇树优化)
概念:1 个模块可能有多个⽅法,只要其中的某个⽅法使⽤到了,则整个⽂件都会被打到bundle ⾥⾯去,tree shaking 就是只把⽤到的⽅法打⼊ bundle ,没⽤到的⽅法会在uglify 阶段被擦除掉。
使⽤:webpack4 默认⽀持,在 .babelrc ⾥设置 modules: false 即可
要求:必须是 ES6 的语法,CommonJS 的⽅式不⽀持.
production mode的情况下默认开启
treeShaking的情况:
1 | 代码执⾏的结果不会被⽤到 |
Tree-shaking 原理
利⽤ ES6 模块的特点:
只能作为模块顶层的语句出现
import 的模块名只能是字符串常量
import binding 是 immutable的
代码擦除: uglify
阶段删除⽆⽤代码
如果代码中有副作用则tree-shaking失效
可以在package.json中配置sideEffect:[] 比如babel-polyfill
使用scope hoisting消除大量闭包现象
原理:将所有模块的代码按照引⽤顺序放在⼀个函数作⽤域⾥,然后适当的重命名⼀些变量以防⽌变量名冲突
必须是 ES6 语法,CJS 不⽀持
1 | plugins: [ |
模块懒加载
webpack 有⼀个功能就是将你的代码库分割成chunks(语块),当代码运⾏到需要它们的时候再进⾏加载。
CommonJS:require.ensure
ES6:动态 import(⽬前还没有原⽣⽀持,需要 babel 转换)
如何使⽤动态 import?
安装 babel 插件 ES6:动态 import(⽬前还没有原⽣⽀持,需要 babel 转换)
1 | npm install @babel/plugin-syntax-dynamic-import --save-dev |
代码中的使用:
1 | loadComponent() { |
这样的话text.js在打包时就会被自动拆分为一个单独的文件,当我们调用这个方法时才进行加载,也算是一个优化手段