实现webpack打包优化,有两个优化点:
- 如何减少打包时间
- 如何减少打包大小
减少打包时间
1.优化Loader
对于Loader来说,首先优化的当是babel了,babel会将代码转成字符串并生成AST,然后继续转化成新的代码,转换的代码越多,效率就越低。
首先可以优化Loader的搜索范围
module.exports = {module: {rules: [test: /\.js$/, // 对js文件使用babelloader: 'babel-loader',include: [resolve('src')],// 只在src文件夹下查找// 不去查找的文件夹路径,node_modules下的代码是编译过得,没必要再去处理一遍exclude: /node_modules/ ]}
}
另外可以将babel编译过文件缓存起来,以此加快打包时间,主要在于设置cacheDirectory
loader: 'babel-loader?cacheDirectory=true'
2.HappyPack
因为受限于Node的单线程运行,所以webpack的打包也是单线程的,使用HappyPack可以将Loader的同步执行转为并行,从而执行Loader时的编译等待时间。
module: {loaders: [test: /\.js$/,include: [resolve('src')],exclude: /node_modules/,loader: 'happypack/loader?id=happybabel' //id对应插件下的配置的id]
},
plugins: [new HappyPack({id: 'happybabel',loaders: ['babel-loader?cacheDirectory'],threads: 4, // 线程开启数})
]
3.DllPlugin
该插件可以将特定的类库提前打包然后引入,这种方式可以极大的减少类库的打包次数,只有当类库有更新版本时才会重新打包,并且也实现了将公共代码抽离成单独文件的优化方案。
// webpack.dll.conf.js
const path = require('path')
const webpack = require('webpack')
module.exports = {entry: {vendor: ['react'] // 需要统一打包的类库},output: {path: path.join(__dirname, 'dist'),filename: '[name].dll.js',library: '[name]-[hash]'},plugins: [new webpack.DllPlugin({name: '[name]-[hash]', //name必须要和output.library一致context: __dirname, //注意与DllReferencePlugin的context匹配一致path: path.join(__dirname, 'dist', '[name]-manifest.json')})]
}
然后在package.json文件中增加一个脚本
'dll': 'webpack --config webpack.dll.js --mode=development'
//运行后会打包出react.dll.js和manifest.json两个依赖文件
最后使用DllReferencePlugin将刚生成的依赖文件引入项目中
// webpack.conf.js
module.exports = {//...其他配置plugins: [new webpack.DllReferencePlugin({context: __dirname,manifest: require('./dist/vendor-manifest.json') //此即打包出来的json文件})]
}
更多有关webpack配置DllPlugin请参考如何使用 Webpack 的 Dllplugin和webpack中DllPlugin用法
4.代码压缩相关
-
启用
gzip压缩 -
webpack3中,可以使用UglifyJS压缩代码,但是它是单线程的,因此可以使用webpack-parallel-uglify-plugin来运行UglifyJS,但在webpack4中只要启动了mode为production就默认开启了该配置 -
压缩
html和css代码,通过配置删除console.log和debugger等,防止可能造成的内存泄漏
new UglifyJsPlugin({UglifyOptions: {compress: {warnings: false,drop_console: true,pure_funcs: ['console.log']}},sourceMap: config.build.productionSourceMap,parallel: true
})
//或使用以下配置
new webpack.optimize.UglifyJsPlugin({compress: {warnings: false,drop_debugger: true,drop_console: true}
})
减少打包大小
1.按需加载,首页加载文件越小越好,将每个页面单独打包为一个文件,(同样对于loadsh类库也可以使用按需加载),原理即是使用的时候再去下载对应的文件,返回一个promise,当promise成功后再去执行回调。
2.Scope Hoisting
它会分析出模块之前的关系,尽可能的把打包出来的模块合并到一个函数中去
// 如在index.js问价中引用了test.js文件
export const a = 1 // test.js
import {a} from './test.js' // index.js
// 以上打包出来的文件会有两个函数,类似如下
[function(module, exports, require) {} // **0**function(module, exports, require) {} // **1**
]
如果使用scope hoisting的话会尽量打包成一个函数,在webpack 4中只需开启concatenateModules即可
module.exports = {optimize: {concatenateModules: true}
}
3.Tree shaking
它会删除项目中未被引用的代码,而如果在webpack 4中只要开启生产环境就会自动启动这个功能