问题发生背景
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
配置项还是不熟悉,很多配置还是需要去查,去搜。慢慢学习吧~