压缩项目的打包体积,提高打包率是后端性能优化中非常重要的环节。 作者结合工作中的实践总结,整理出一些常规且行之有效的性能优化建议
项目背景
技术栈:vue-cli3+vue2+webpack4
主要插件:elementUI+echarts+axios+momentjs
目的:通过一系列优化方案,对比变更前后的包装体积和率,验证方案的有效性
项目初始数量及费率
vue项目可以添加--report命令:"build": "vue-cli-servicebuild--report",打包后dist目录会生成一个report.html文件,用于分析每个文件的大小
或者通过安装webpack-bundle-analyzer插件进行分析,步骤如下:
1)安装
npm install webpack-bundle-analyzer -D
2)在vue.config.js中引入
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = {
configureWebpack: {
plugins: [
new BundleAnalyzerPlugin()
]
}
}
3)npmrunserve运行后webpack 怎么压缩webpack 怎么压缩,打开浏览器:8888/即可看到分析页面
开始优化✈︎1、externals提取项目依赖
从前面的打包分析页面可以看出,chunk-vendors.js的体积为2.21M,最大的文件是一些公共依赖包,所以只要提取出这个依赖,就可以解析chunk-vendors。 js太大问题
你可以使用externals来提取这个依赖包,告诉webpack这些依赖是外部环境提供的,打包时可以忽略它们,并且它们不会被打入chunk-vendors.js中
1)vue.config.js中的配置:
module.exports = {
configureWebpack: {
externals: {
vue: 'Vue',
'vue-router': 'VueRouter',
axios: 'axios',
echarts: 'echarts'
}
}
2)使用CDN在index.html中引入依赖
<body>
<script src="http://lib.baomitu.com/vue/2.6.14/vue.min.js"></script>
<script src="http://lib.baomitu.com/vue-router/3.5.1/vue-router.min.js"></script>
<script src="http://lib.baomitu.com/axios/1.2.1/axios.min.js"></script>
<script src="http://lib.baomitu.com/echarts/5.3.2/echarts.min.js"></script>
</body>
验证外部的有效性:
重新打包,最新数据如下:
包装体积:1.12M
打包速率:18879ms
使用外挂后,封装体积压缩50%,封装率提高26%。
2. 按需引入组件库
为什么不使用externals的方式来处理元件库呢?
externals的缺点:直接在html中导入,失去了按需导入的功能,只能导入组件库完整的js和css
按需引入组件库的原则:最终只引入指定的组件和对应的样式
elementUI需要使用babel-plugin-component插件来实现。 插件功能如下:
根据需要导入 Button 组件:
import { Button } from 'element-ui'
Vue.component(Button.name, Button)
编译后的文件(手动导入button.css):
import _Button from "element-ui/lib/button";
import _Button2 from "element-ui/lib/theme-chalk/button.css";
// base.css是公共的样式
import "element-ui/lib/theme-chalk/base.css";
Vue.component(_Button.name, _Button);
通过这个插件,最终只引入指定的组件和样式,减少组件库的大小
1)安装babel-plugin-组件
npm install babel-plugin-component -D
2)在babel.config.js中引入
module.exports = {
presets: ['@vue/app'],
plugins: [
[
'component',
{
libraryName: 'element-ui',
styleLibraryName: 'theme-chalk'
}
]
]
};
验证组件库按需导入的有效性:
重新打包,最新数据如下:
包大小:648KB
打包速率:15135ms
按需引入元件库后,封装体积缩小72%,封装率提升40%。
同时,chunk-vendors.css的体积也大幅减小,从206KB减少到82KB
原卷:
按需导入后:
3、减少三方依赖量
继续分析打包后的文件,项目中使用了momentjs,发现打包后有很多未使用的语言包
使用 moment-locales-webpack-plugin 插件删除无用的语言包
1)安装
npm install moment-locales-webpack-plugin -D
2)在vue.config.js中引入
const MomentLocalesPlugin = require('moment-locales-webpack-plugin');
module.exports = {
configureWebpack: {
plugins: [
new MomentLocalesPlugin({localesToKeep: ['zh-cn']})
]
}
}
验证插件的有效性:
重新打包,最新数据如下:
包体积:407KB
打包速率:10505ms
减少三方依赖体积后,打包体积压缩82%,打包率提升59%。
4.HappyPack多线程打包
由于 Node.js 上运行的 webpack 是单线程模型,因此我们需要 webpack 能够同时处理多个任务,并利用多核 CPU 笔记本的强大功能
HappyPack可以实现多线程打包。 它将任务分解为多个子流程以并发执行。 子流程处理完毕后,将结果发送至主流程,提高打包率。
1)安装
npm install HappyPack -D
2)在vue.config.js中引入
const HappyPack = require('happypack');
const os = require('os');
// 开辟一个线程池,拿到系统CPU的核数,happypack 将编译工作利用所有线程
const happyThreadPool = HappyPack.ThreadPool({ size: os.cpus().length });
module.exports = {
configureWebpack: {
plugins: [
new HappyPack({
id: 'happybabel',
loaders: ['babel-loader'],
threadPool: happyThreadPool
})
]
}
}
验证HappyPack的有效性:
重新打包,最新数据如下:
打包速率:8949ms
使用HappyPack后,打包率进一步提升65%
由于测试项目较小,所以打包时间的减少并不算太多。实测发现,项目越复杂,HappyPack对打包率的提升越显着
5.Gzip压缩
线上项目通常是结合创建工具webpack插件或者服务器端配置nginx来实现gzip压缩进行http传输。 目的是尽量减少服务器端响应文件的体积,优化返回率
HTML、js、css资源使用gzip后一般可以压缩70%以上
这里介绍一下使用webpack进行gzip压缩的形式,使用compression-webpack-plugin插件
1)安装
npm install compression-webpack-plugin -D
2)在vue.config.js中引入
const CompressionPlugin = require('compression-webpack-plugin');
module.exports = {
configureWebpack: {
plugins: [
new CompressionPlugin({
test: /.(js|css)(?.*)?$/i, //需要压缩的文件正则
threshold: 1024, //文件大小大于这个值时启用压缩
deleteOriginalAssets: false //压缩后保留原文件
})
]
}
}
验证插件的有效性:
重新打包,原体积407KB压缩为108KB
6.DllPlugin动态链接库
DllPlugin和externals类似,都是提取依赖,节省打包时间。不同的是DllPlugin单独打包依赖,这样每次只创建业务代码,而externals则是将依赖转成CDN导入
当公司没有好的CDN资源或者不支持CDN时,可以考虑使用DllPlugin来替代外部
DllPlugin配置过程大致分为三步:
1)创建dll.config.js配置文件
import { DllPlugin } from "webpack";
export default {
// 需要抽离的依赖
entry: {
vendor: ["vue", "vue-router", "axios", "echarts"]
},
mode: "production",
optimization: {
splitChunks: {
cacheGroups: {
vendor: {
chunks: "all",
name: "vendor",
test: /node_modules/
}
}
}
},
output: {
filename: "[name].dll.js", // 输出路径和文件名称
library: "[name]", // 全局变量名称:其他模块会从此变量上获取里面模块
path: AbsPath("dist/static") // 输出目录路径
},
plugins: [
new DllPlugin({
name: "[name]", // 全局变量名称:减小搜索范围,与output.library结合使用
path: AbsPath("dist/static/[name]-manifest.json") // 输出目录路径
})
]
};
2)package.json配置脚本
"build:dll": "webpack --config ./dll.config.js",
3)使用DllReferencePlugin将打包的dll文件引用到所需的预编译依赖,通过html-webpack-tags-plugin打包时手动插入dll文件
vue.config.js的配置如下
import { DllReferencePlugin } from "webpack";
import HtmlTagsPlugin from "html-webpack-tags-plugin";
export default {
configureWebpack: {
plugins: [
new DllReferencePlugin({
manifest: AbsPath("dist/static/vendor-manifest.json") // manifest文件路径
}),
new HtmlTagsPlugin({
append: false, // 在生成资源后插入
publicPath: "/", // 使用公共路径
tags: ["static/vendor.dll.js"] // 资源路径
})
]
}
};
首先运行 npmrunbuild:dll 包生成依赖文件,然后运行 npmrunbuild 构建业务代码
优化总结
经过前面的一系列优化,我们可以看到:
这种方法虽然很常规,但是可以有效提高项目的性能
本文主要介绍项目打包和建立的优化方法。 下一篇会讲业务代码层面的性能优化,会有很多有趣的解决方案
系列文章
系列文章地址:github.com/xy-sea/blog
文中如有错误或不准确的地方,还请大家谅解,非常感谢。 如果您喜欢或启发某件事,欢迎加星