Webpack 性能优化
开发环境优化
加快构建速度 -- HMR
HMR 热更新,一个模块发生更新,只重新打包更新这一个模块
devServer: {
hot: true
}
- html 不需要热更新
- 样式文件支持 HMR 功能,style-loader 支持
- js 文件默认不能使用 HMR,需要添加如下代码,只能处理非入口的 js 文件
if(module.hot) {
module.hot.accept('./some.js', function () {
// do something
})
}
方便调试代码 -- source-map
source-map,源代码与产物代码之间的映射关系
// webpack.config.js 中开启 source-map
// [inline-|hidden-|eval-][nosources-][cheap-[module-]]soure-map
devtool: 'source-map'
| 参数 | 生成位置 | 说明 |
|---|---|---|
| source-map | 外部 | 错误代码的源代码及位置 |
| inline- | 内联 | 生成到文件底部 错误代码的源代码及位置 |
| eval- | 内联 | 生成到构建的文件中每个文件的 eval 后 错误代码的源代码及位置 |
| hidden- | 外部 | 不能追踪错误,只能提示构建后代码的错误位置 |
| nosources- | 外部 | 有错误代码的源代码位置,但无源代码 |
| cheap- | 外部 | 有错误代码的源代码,只能确定到行 |
| cheap-module- | 外部 | 会包含 module 的 sourcemap |
生产环境优化
加快 loader 处理 -- oneOf
// webpack.config.js
modules: {
rules: [
{
test: /xx/
...
}, {
// 使用 oneOf 文件只会匹配其中一个 loader
// 注意不能有两个配置处理同一文件
oneOf: [
{ test: /.x1./, loader: 'xx1'} ,
{ test: /.x2./, loader: 'xx2'} ,
{ test: /.x3./, loader: 'xx3'} ,
]
}
]
}
缓存
babel 缓存
在 babel-loader 中设置参数,cacheDirectory: ture
文件资源缓存
资源文件使用哈希值命名,如
[hash]webpack 每次打包的唯一 hash[chunkhash]每个 chunk 具有的 hash,如果几个文件同属一个 chunk,它们的 chunkhash 一样[contenthash]每个文件具有的唯一 hash
因此最佳选择就是 contenthash
tree-shaking
去除无用代码
前提必须使用 ES6 模块,在 production 就支持 tree-shaking 了
package.json 中的配置 sideEffects,如果为 false,则表示当前项目下文件无副作用, tree-shaking 的过程中就有可能把 import './index.css' 干掉;如果为 ["*.css", "*.less"],则表示 css/less 文件有副作用,就会保留
code split
使用多入口
在 entry 中配置多个入口
optimization
// node_modules 中的代码单独打包
// 自动分析多入口中的公共文件,并单独打包成一个 chunk
optimization: {
splitChunks: {
chunks: 'all'
}
}
import()
使用 import() 动态导入,能将某个文件单独打包
使用 webpackChunkName 注释可以给打包后的文件命名,否则以一串 id 命名
import(/* webpackChunkName: "test"*/ './test.js')
.then(testModule => {
console.log('文件加载完成')
}).catch(() => {
console.log('文件加载失败')
})
懒加载和预加载
懒加载
使用时才加载
import(/* webpackChunkName: "test"*/ './test.js')
预加载
预加载,浏览器空闲时,默默的加载,到了使用时就早已完成加载,节省了时间,又不会影响正常的加载
import(/* webpackChunkName: 'test', webpackPrefetch: true */ './test.ts)
PWA
PWA(Progressive Web Apps,渐进式网络应用),可以实现离线可访问的应用
workbox-webpack-plugin 帮助 serviceworker 快速启动,删除旧的 servicework
new WorkboxWebpackPlugin.GenerateSW({
clientsClaim: true,
skipWaiting: true,
})
// 注册 serviceworker
// 处理兼容性
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serivceWork.register('/service-worker.js')
.then(()=> console.log('sw注册成功'))
.catch(()=> console.log('sw注册失败'))
})
}
多进程打包
使用 thread-loader,并放在需要的 loader 后面,开启多进程打包,但由于开启多进程也会耗时,只有工作时间较长时,开启才有效果,否则会有反效果
{
test: /\.js$/,
use: [
'thread-loader',
{
loader: 'babel-loader',
options: {...}
}
]
}
externals
使用外部扩展,不将代码打入包中,例如在 html 中使用 CDN 引入 jquery ,而打包时需要排除 jquery
// webpack.config.js
module.exports = {
...
externals: {
// 忽略包名:全局变量名
jquery: jQuery
}
...
}