最近对公司商务运营管理平台做了部分优化,优化后包体积减小为原来的43%,性能有很大提升。
优化前
原配置文件中已包含部分优化,包括
- 使用
compression-webpack-plugin
开启gzip压缩 - 使用
svg-sprite-loader
将svg文件打包成雪碧图 - 使用
optimization.splitChunks
做代码分割
......
在此基础上仍有很大优化空间,首先借助 webpack-bundle-analyzer
将打包后的内容展示为方便交互的树状图,我们可以很直观的看到有哪些比较大的模块,然后做针对性优化。
可以看到总体为7.71M,其中node_modules占用较多,所以可进行较明显的构建优化.
CDN+external
> CDN 的工作原理是将源站的资源缓存到位于全球各地的 CDN 节点上,用户请求资源时,就近返回节点上缓存的资源,而不需要每个用户的请求都回您的源站获取,避免网络拥塞、缓解源站压力,保证用户访问资源的速度和体验。
可以看到打包模块中将一些引入库也打包进来,这里我们可以采用引入外链cdn取消对较大依赖模块的打包。
在vue.config.js中添加如图配置
同时在public中的index.html中引入cdn链接
需要注意点,在 html 中配置的 CDN 引入脚本最好要在 body 内的最底部,因为:
- 如果放在 body 上面或 header 内,则加载会阻塞整个页面渲染。
- 如果放在 body 外,则会在业务代码被加载之后加载,模块中使用了该模块将会报错
- CDN最好采用公司内部CDN,这里使用了vue及element官网链接和服务较好的bootcdn
按需引入
很多element组件只用到了较少一部分,所以可采用按需引入
安装插件babel-plugin-component
后修改.babelrc
文件
{
"presets": [],
"plugins": [
[
"component",
{
"libraryName": "element-ui",
"styleLibraryName": "theme-chalk"
}
]
]
}
在需要的地方引入,例
import { Loading } from "element-ui";
语言包优化
某些场景下,语言包会占用整个包体积的非常大一部分。实际上库本身的逻辑不会很大,moment 就是一个很好例子。如果是新项目,推荐使用dayjs替代moment,它只有2k,此处用了不影响原逻辑我们仍延用moment,把不使用的语言包过滤掉,推荐使用 ContextReplacementPlugin,他可以过滤掉不使用的语言,也可以用webpack的IgnorePlugin
插件
const ContextReplacementPlugin = require("webpack/lib/ContextReplacementPlugin");
config.plugin("ignore").use(new ContextReplacementPlugin(/moment[/\\]locale$/, /zh-cn$/));
过滤后仅为原来25%
去除console
日常开发为了方便调试,代码中会有一些console,但是在生产环境中为了信息安全这些console是不能出现的,这里我们使用terser-webpack-plugin
插件来去掉console。该插件通常用语代码压缩,有类似功能的插件还有uglifyjs-webpack-plugin
,但uglifyjs-webpack-plugin
缺点是不支持es6
安装
npm install terser-webpack-plugin --save-dev
使用
const TerserPlugin = require("terser-webpack-plugin");
vue.config.js的configureWebpack中添加
optimization: {
minimizer: [
new TerserPlugin({
terserOptions: {
compress: {
pure_funcs: ["console.log"]
}
}
})
]
},
打包时发现报错
排查后发现原因是webpack和terser插件的版本差异,terser目前最新版为5.0.2,但我们项目中使用的事webpack4.x,所以要安装terser插件的4.x版本,安装后重新build正常。
在打包后的dist文件夹app.js中搜索console.log未发现说明生效。
压缩图片
项目中有较多小于2k的icon和小图片可使用file-loader
和url-loader
处理
原理是url-loader可将小于limit的图片转成base64格式,大于limit的图片由file-loader编译
配置如下
const imagesRule = config.module.rule("images");
imagesRule.uses.clear();
imagesRule
.use("file-loader")
.loader("url-loader")
.options({
limit: 16384, // 小于2k转长base64
fallback: {
loader: "file-loader",
options: {
outputPath: "static/img"
}
}
});
打包后包大小减少了0.2M,效果不大,但是对图片处理更明显的优点是减少http请求以及在图片渲染过程中的性能提升。
最终效果
以上方式可使项目在花费较小时间成本的情况下让性能有较大提升,如对性能还有更高要求,仍有很多方式可进一步优化。