问题发生背景
vue
项目首屏加载缓慢,f12
一看有的js
文件很大,有1.3M旁边,还有个chunk
文件也有1.2M,但是目前不知道里面打包了什么东西,导致入口文件加载缓慢,导致发接口的时机延长,所以看见首页的东西就很晚了。
所以原因是:首屏加载的js缓慢,导致页面空白时间太久。
优化思路
先把打包报告打出来看一下,打包了哪些东西?
1. 安装个webpack
打包工具插件,查看打包报告
打包报告:
可以看到有两个js
文件很大,9300那个大部分是图片打包到了js
里面,在代码里面看一下这个文件:
可以看到webpack
打包,把某些文件图片转换成了base64
图片格式,图片又很多,导致整个的js
文件很大。
按照这个思路试想一下:能不能不让图片转换成base64
格式?
查了一下文档发现,webpack
会默认把某些较小的图片文件打包成base64
,为了加快访问图片,不用请求资源,原本是一件好事,没想到我们这个项目图片太多了,导致用这个配置之后,反而加慢了整体的进程。
2. 设置图片限制,不打包成base64
格式。
const { defineConfig } = require("@vue/cli-service"); const BundleAnalyzer = require("webpack-bundle-analyzer").BundleAnalyzerPlugin; module.exports = defineConfig({ publicPath: process.env.VUE_APP_CURENVs, outputDir: "h5_integral_mall", // 打包名称 lintOnSave: process.env.NODE_ENV !== "production", transpileDependencies: true, productionSourceMap: false, css: { loaderOptions: { scss: { additionalData: `@import "~@/assets/css/app.scss";`, }, }, }, // 该配置表示,图片大小最大为1KB,小于1KB的才会转换为base64 chainWebpack: (config) => { config.module .rule("images") .test(/\.(png|svg|jpg|jpeg|gif)$/) .set("parser", { dataUrlCondition: { maxSize: 1, }, }); } });
上面优化配置项要注意的是:不同的webpack
版本对应不同的写法,需要对照webpack
官网尝试。当时试了好久不成功,是因为webpack
版本不同,写法也没生效。
打包后试一下:
可以看到文件已经变小了。但是打包完后整体的包的img
文件夹大了,是正常的,因为图片都被放出来了。
3. chunk
文件过大,拆包处理。
chainWebpack: (config) => { config.module .rule("images") .test(/\.(png|svg|jpg|jpeg|gif)$/) .set("parser", { dataUrlCondition: { maxSize: 1, }, }); // 开发环境不拆包 // 分模块和优先级进行拆分 if (process.env.NODE_ENV !== "development") { config.optimization.splitChunks({ chunks: "all", automaticNameDelimiter: "-", cacheGroups: { vant: { name: "chunk-vant", priority: 32, test: /[\\/]node_modules[\\/]_?vant(.*)/, }, mathjs: { name: "chunk-mathjs", priority: 35, test: /[\\/]node_modules[\\/]_?mathjs(.*)/, }, vue: { name: "chunk-vuejs", priority: 30, test: /[\\/]node_modules[\\/](vue|vue-router|vuex)[\\/]/, }, // src/components组件从chunk里拆分出来 components: { name: "chunk-components", test: resolve("src/components"), minChunks: 2, priority: 5, reuseExistingChunk: true, }, }, }); config.optimization.runtimeChunk("single"); } }
分模块和优先级进行拆分。
打包后如下:
可以看出从之前的一个chunk
文件拆分成了好几个chunk
文件。整个项目的文件大小也从6.39M减小到4.66M。
4. moment
插件处理
从分析报告可以看出:moment
文件加有一个local
文件,查了一下文档,这个文件主要是用于各个地区的时间处理,由于项目中没使用到,主要是在中国时区,所以可以考虑去除该模块。
configureWebpack: (config) => { if (process.env.NODE_ENV !== "development") { config.plugins.push( new BundleAnalyzer({ // 设置混淆选项 openAnalyzer: true, analyzerPort: 1000, }) ); // 去除moment文件夹中的local文件。 config.plugins.push( new webpack.IgnorePlugin({ resourceRegExp: /^\.\/locale$/, contextRegExp: /moment$/, }) /* 压缩loader */ ); } },
打包后如下:
5. 开启CSS
代码压缩
const { defineConfig } = require("@vue/cli-service"); const TerserPlugin = require("terser-webpack-plugin"); const BundleAnalyzer = require("webpack-bundle-analyzer").BundleAnalyzerPlugin; const webpack = require("webpack"); /* 开启css压缩 */ const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); module.exports = defineConfig({ publicPath: process.env.VUE_APP_CURENVs, outputDir: "h5_integral_mall", // 打包名称 lintOnSave: process.env.NODE_ENV !== "production", transpileDependencies: true, productionSourceMap: false, css: { loaderOptions: { scss: { additionalData: `@import "~@/assets/css/app.scss";`, }, }, }, configureWebpack: (config) => { if (process.env.NODE_ENV !== "development") { config.plugins.push( new webpack.IgnorePlugin({ resourceRegExp: /^\.\/locale$/, contextRegExp: /moment$/, }) ); config.optimization.minimizer = [ /* 开启css压缩 */ new CssMinimizerPlugin(), ]; } }, chainWebpack: (config) => { config.module .rule("images") .test(/\.(png|svg|jpg|jpeg|gif)$/) .set("parser", { dataUrlCondition: { maxSize: 1, }, }); }, });
6. CDN
加载外部资源
在vue.config.js
中,配置哪些外部资源需要cdn
加载:
/* 根据环境动态配置cdn资源 */ let externals = {}; let CDN = { css: [], js: [] }; /* 非开发环境 */ if (process.env.NODE_ENV !== "development") { externals = { /** * externals对象属性分析: * '包名':'在项目中引入的名字'**/ lodash: "lodash", mathjs: "mathjs", vconsole: "vconsole", }; CDN = { css: [], js: [ "https://cdn.bootcdn.net/ajax/libs/mathjs/12.3.0/math.min.js", "https://cdn.bootcdn.net/ajax/libs/lodash.js/4.17.21/lodash.min.js", "https://cdn.bootcdn.net/ajax/libs/vConsole/3.15.1/vconsole.min.js", ], }; }
紧接上面的chainWebpack
配置:
chainWebpack: (config) => { config.module .rule("images") .test(/\.(png|svg|jpg|jpeg|gif)$/) .set("parser", { dataUrlCondition: { maxSize: 1, }, }); }, config.plugin('html').tap(args => { // 参数对象添加属性叫cdn,值就是上面CDN对象 args[0].cdn = CDN// 配置CDN给插件 return args })
接下来在html页面中,循环配置中的cdn资源:
<!-- 导入js --> <% for(var js of htmlWebpackPlugin.options.cdn.js) { %> <script src="<%=js%>"></script> <% } %>
最后打包看一下:
可以看到打包后,打包文件里已经没有我们在config.js
里面配置的外部资源了。有效的减少了包的文件大小。从之前的6.38M减少到3.69M。
在打包后的index.html
可以看到,加载了我们配置的js
包。
这个cdn
加载有个注意的是::要找个靠谱的cdn
网站,我之前配置了之后,cdn
崩了一天,所以这种方案后面就没有使用。
7. 关于图片还有其他的思路,就是挺麻烦
这个思路适合在项目初期建设阶段,就是将项目中的图片文件放在public
文件夹下,这样webpack
就不会将图片打包。注意的就是,在代码中引用图片资源的写法就要注意,都要写成相对路径。
大部分图片有三种格式:
require
方式引用图片css
,backgrundImage
设置背景图片还有就是在模板标签中使用图片
首先在vue.config.js
里面配置一下环境变量,可以在css
中写env
中配置的环境变量。
module.exports = defineConfig({ publicPath: process.env.VUE_APP_CURENVs, outputDir: "h5_xiaoyiyunxuan", // 打包名称 lintOnSave: process.env.NODE_ENV !== "production", transpileDependencies: true, productionSourceMap: false, css: { // css增加环境变量,在css中就可以使用$env-host来替换项目的域名和端口 loaderOptions: { scss: { additionalData: `$env-host:"${process.env.VUE_APP_HOST}";$env-curenvs:"${process.env.VUE_APP_CURENVs}";@import "~@/assets/css/app.scss";`, }, },
require
方式引用图片格式代码改写:
css
,backgrundImage
设置背景图片
在模板标签中使用图片
总结
通过打包报告会有思路,去哪方面去优化,有问题解决问题,就是自己对webpack
配置项还是不熟悉,很多配置还是需要去查,去搜。慢慢学习吧~