由于webpack各种配置层出不穷,上一篇只是列举了一些常用的配置,而不知道什么时候又会变。。。
剩余的只能按需去查阅文档进行配置咯
这次是一些webpack优化配置策略说明
下面是正文,顺序不分先后
webpack-bundle-analyzer
可视化分析工具,优化可以具体用这个来看包的大小以及分布
1 | # NPM |
1 | const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; |
暴露变量的三种方式
webpack.ProvidePlugin 注入变量
不会将变量暴露到window上
1 | const webpack = require('webpack'); |
expose-loader 暴露到window上
帮你把一些变量放到window上
- 先安装expose-loader
- 配置loader
注:只要引用一次就会暴露到window上,但是有个缺陷:库会被打包进去bundle文件内。
1 | module.exports = { |
外部变量externals + cdn
添加cdn资源插件 add-asset-html-cdn-webpack-plugin
可以把静态资源放到cdn上
- 可以提高页面加载速度方式
- 打包时候不会被打进去
1 | const AddAssetHtmlCdnWebpackPlugin = require('add-asset-html-cdn-webpack-plugin'); |
如果使用cdn的加载方式 引用的时候不希望打包,最好把他表示成外部变量,在externals内加入
1 | module.exports={ |
tree-shaking 消除无用代码
只针对于es6模块 import export,生产环境会自动生效
- import 静态 必须先导入,才能进行使用
- require 动态 可以在代码中实时导入使用
1 | module.exports={ |
副作用:模块没有被引用,但是模块内的方法被执行,则会保留这个模块代码
修复方式,在package.json内加入
1 | { |
- 注:sideEffects不要给false,给false会出现如下副作用
sideEffects 设置为false
1 | { |
在js中引入css,由于没有导出变量
1 | import 'style.css' |
会被tree-shaking认为没有被使用,会把这个模块删掉。
如果非要设置false,需使用require()进行引入
1 | require('style.css'); |
scope-hosting(自动,不需要手动优化)
mode为prod时,把变量进行压缩,去提取模块中导出的变量
1 | let a = 1; |
scope-hosting后
1 | console.log(3); |
热更新
热更新会保持之前状态,进行更新dom
1 | module.exports = { |
有个问题,css-loader自动支持热更新,但是js更改后会刷新浏览器。
使用以下代码
1 | if(module.hot) { |
1 | if(module.hot) { |
懒加载
import() 动态导入,是实验性的草案,返回一个promise对象,所以可以用async+await 或者promise.then()
需要新增一个插件@babel/plugin-syntax-dynamic-import
1 | module.exports = { |
/* webpackChunkName:"video" */
可以自定义打包后代码块的名称/* webpackPrefetch:true */
资源预读取/* webpackPreload:true */
资源预加载
代码优化: prefetch,preload,dns-prefetch defer async
1 | let button = document.createElement('button'); |
ignorePlugin
webpack.IgnorePlugin(), 也有另外一个插件 ContextReplacementPlugin
例如某个类库下还有引用大量的包,被打包进bundle内,则可以用这个进行忽略
如下是对moment库进行优化
1 | module.exports = { |
最后因为忽略掉了很多文件,导致变为英文,可以用如下方法优化:
1 | import 'moment/locale/zh-cn'; // 在使用的地方再次引入 |
dllPlugin
先将不需要频繁改变的代码打包好放在那,节约构建时间,一般用在dev环境中,生产环境则一般用splitChunks快速拆分多个包
新建一个webpack.dll.js
1 | const webpack = require('webpack'); |
在webpack项目打包的文件配置:
打包时候首先会在 manifest.json 里面找缓存
1 | const webpack = require('webpack'); |
最后会在html里面把这个dll文件以静态资源的方式放进html中
1 | const webpack = require('webpack'); |
总结:先产生mainfest.json (name) 和一个js文件全局变量名字一致
引用的时候引用manifest.json 会先去上面查找,找到后,加载对应的内容
include/exclude
可以对loader 限制一些引入和排除范围,减少遍历次数
1 | { |
图片和icon分开打包
需注意svg不是图片,转化成base64会出问题
- icon 走file-loader 包括 woff|svg|eot|ttf 等
- 图片 走url-loader png|jpg 等等
file-loader 只有copy功能,url-loader 包含limit,可以转化为base64
splitChunks
一般在生产环境中使用,dev环境一般使用dllplugin
- 实现代码的公用
- 分割第三方模块
如果两者在生产环境中共用,可能会导致打包重复,或者不是全量包的问题
1 | module.exports = { |
resolve
可以减少查找文件的范围,设置扩展名,别名,主入口名等等。
1 | module.exports = { |
devtool
https://webpack.docschina.org/configuration/devtool/
一般来讲做以下配置
- dev “cheap-module-source-map” || “cheap-module-eval-source-map”
- prod “source-map”
开发环境一般有需要就是用以上配置,没需要就不做配置
生产环境一般会使用source-map,但是会配置不让普通用户访问
1 | module.exports = { |
多线程打包 happypack
项目比较大的时候会使用,因为开进程比较浪费时间。
总结
比较有效的优化手段
- CDN
- dllPlugin
- splitChunks
- happypack