webpack 优化
一般我们谈的 webpack 优化 ,无非就是分为 打包时间 和 打包体积 的优化。
打包时间
优化打包时间,我们能想到的策略:减少需要读取和解析的文件 和 提高打包性能。
减少需要读取和解析的文件
1. 优化 loader
以 babel-loader 为例,如果可以,我们尽量规定 include exclude 的范围
如果像 babel-loader 一样有用于缓存的参数,那也可以用上
module: { rules: [ { test: /\.js$/, loader: 'babel-loader?cacheDirectory=true', include: [resolve('src')], exclude: /node_modules/ } ] }
2. 打 Dll
把一些不经常改动的代码(一般是第三方库),提前打成一个 dll,然后在项目打包的时候,就不需要每次都再重新打包这部分的代码。
dll 的 webpack 配置:
// 单独配置在一个文件中 // webpack.dll.conf.js const path = require('path') const webpack = require('webpack') module.exports = { entry: { // 想统一打包的类库 vendor: ['react', 'jquery'] }, output: { path: path.join(__dirname, 'dist'), filename: '[name].dll.js', library: '[name]-[hash]' }, plugins: [ new webpack.DllPlugin({ // name 必须和 output.library 一致 name: '[name]-[hash]', // 该属性需要与 DllReferencePlugin 中一致 context: __dirname, path: path.join(__dirname, 'dist', '[name]-manifest.json') }) ] }
项目的 webpack 配置:
// webpack.conf.js module.exports = { // ...省略其他配置 plugins: [ new webpack.DllReferencePlugin({ context: __dirname, // manifest 就是之前打包出来的 json 文件 manifest: require('./dist/vendor-manifest.json'), }) ] }
提高打包性能
1. HappyPack
突破单线程,实现多线程解析。
module: { loaders: [ { test: /\.js$/, include: [resolve('src')], exclude: /node_modules/, // id 后面的内容对应下面 loader: 'happypack/loader?id=happybabel' } ] }, plugins: [ new HappyPack({ id: 'happybabel', loaders: ['babel-loader?cacheDirectory'], // 开启 4 个线程 threads: 4 }) ]
2. webpack-parallel-uglify-plugin
我们一般会用 UglifyJS
来压缩代码,我们不妨用 webpack-parallel-uglify-plugin 来代替,让它突破单线程,实现多进程压缩代码。
幸运的是,webpack 官方在 4.x 版本,已经默认帮我们实现。不需要我们在使用这个插件。只要将 mode 设置成 production 就可以了。
一些小的优化点
我们还可以通过一些小的优化点来加快打包速度
resolve.extensions
:用来表明文件后缀列表,默认查找顺序是['.js', '.json']
,如果你的导入文件没有添加后缀就会按照这个顺序查找文件。我们应该尽可能减少后缀列表长度,然后将出现频率高的后缀排在前面resolve.alias
:可以通过别名的方式来映射一个路径,能让 Webpack 更快找到路径module.noParse
:如果你确定一个文件下没有其他依赖(就是没有import require其他文件),就可以使用该属性让 Webpack 不扫描该文件,这种方式对于大型的类库很有帮助
打包体积
优化打包体积,我们能想到的策略:压缩代码(上面提到的uglifyjs)、拆分文件、合并模块、减少需要打包进来的文件。
拆分文件 —— 按需加载
用es6的import()来实现动态按需加载,webpack会把这部分单独拆出来一个文件
import a from './a.js'; if (xxx) { a(); } /***************** 替换成 **********************/ // import a from './a.js'; if (xxx) { import(/*webpackChunkName: "haha233"*/'./a.js') .then(mod => { mod(); }) }
合并模块 —— Scope Hoisting
Scope Hoisting 会分析出模块之间的依赖关系,尽可能的把打包出来的模块合并到一个函数中去。
只要设置 optimization.concatenateModules
为 true,就可以开启。
幸运的是,在 webpack 4.x production mode 下会自动开启。
减少打包进来的文件 —— Tree Shaking
Tree Shaking 可以帮我们删除没有使用到的代码,例如:
// test.js export const a = 1 export const b = 2 // index.js import { a } from './test.js'
幸运的是,在 webpack 4.x production mode 下会自动开启。