Vue项目卡顿慢加载?这些优化技巧告诉你!_vue数据多渲染卡顿
resolve: {alias: {},plugins},/* 第二种方式 在vuecli中*/// configureWebpack 返回函数式写法// 其他配置alias: {})// 为生产环境修改配置threshold: 10240, // 只有大小大于该值的资源会被处理 10240minRatio: 0.8, // 只有压缩率小于这个值的资源才会被处理。
module.exports = {
configureWebpack: {
resolve: {
alias: {
‘@’: resolve(‘./src’)
}
},
plugins
},
}
/* 第二种方式 在vuecli中*/
// configureWebpack 返回函数式写法
const CompressionWebpackPlugin = require(‘compression-webpack-plugin’)
const isProduction = process.env.NODE_ENV !== ‘development’
module.exports = {
…
configureWebpack: (config) => {
config.plugins.push(
new HardSourcePlugin()
)
// 其他配置
Object.assign(config.resolve, {
alias: {
‘@’: resolve(‘./src’)
}
})
// 为生产环境修改配置
if (isProduction) {
config.plugins.push(
new CompressionWebpackPlugin({
filename: ‘[path].gz[query]’,
algorithm: ‘gzip’,
test: new RegExp(‘.(’ + [‘html’, ‘js’, ‘css’].join(‘|’) + ‘)$’),
threshold: 10240, // 只有大小大于该值的资源会被处理 10240
minRatio: 0.8, // 只有压缩率小于这个值的资源才会被处理
deleteOriginalAssets: false // 删除原文件
})
)
}
},
}
// webpack.config.js 在webpack搭建的项目中
const CompressionWebpackPlugin = require(‘compression-webpack-plugin’)
module.exports = {
mode: ‘development’,
…
plugins: [
new CompressionWebpackPlugin({
filename: ‘[path].gz[query]’,
algorithm: ‘gzip’,
test: new RegExp(‘.(’ + [‘html’, ‘js’, ‘css’].join(‘|’) + ‘)$’),
threshold: 10240, // 只有大小大于该值的资源会被处理 10240
minRatio: 0.8, // 只有压缩率小于这个值的资源才会被处理
deleteOriginalAssets: false // 删除原文件
})
]
##### 服务端配置, 以nginx为例
服务端 Nginx 需开启 gzip\_static 功能;
在nginx.conf的server模块中加入以下代码:
server{
//开启和关闭gzip模式
gzip on;
//gizp压缩起点,文件大于2k才进行压缩;设置允许压缩的页面最小字节数,页面字节数从header头得content-length中进行获取。 默认值是0,不管页面多大都压缩。建议设置成大于2k的字节数,小于2k可能会越压越大。
gzip_min_length 2k;
// 设置压缩所需要的缓冲区大小,以4k为单位,如果文件为7k则申请2*4k的缓冲区
gzip_buffers 4 16k;
// 设置gzip压缩针对的HTTP协议版本
gzip_http_version 1.0;
// gzip 压缩级别,1-9,数字越大压缩的越好,也越占用CPU时间
gzip_comp_level 2;
//进行压缩的文件类型
gzip_types text/plain application/javascript text/css application/xml;
// 是否在http header中添加Vary: Accept-Encoding,建议开启
gzip_vary on;
}
访问时 可以看到

#### 利用多核/多进程能力
##### `thread-loader`
* 多进程程处理loader
* 使用时,需将此 loader 放置在其他 loader 之前。放置在此 loader 之后的 loader 会在一个独立的 worker 池中运行。
* 本身启动进程就需要耗费时间,\*\*请仅在耗时的操作中使用此 loader!\*\*要不然收益达不到你的预期
##### `happypack`
* 启动多进程来优化构建速度,但是作者不维护了,注意安装版本,
* 替换方案建议使用`thread-loader`
{
// 当js代码用babel处理兼容性且本身代码就比较多的情况下可以使用thread-loader开启多线程打包
// thread-loader本身启动进程就需要耗费时间, 所以当js代码不多时就不要开启, 否则还可能会延长打包时间
test: ‘/.js$/’,
exclude: /node_modules/,
use: [
{
loader: ‘thread-loader’,
options: {
// 默认是cpu核 - 1, 可以通过这里更改开启几个进程
works: 2
}
}
]
}
// @file: webpack.config.js
const HappyPack = require(‘happypack’);
var happyThreadPool = HappyPack.ThreadPool({ size: 5 });
exports.module = {
rules: [
{
test: /.js$/,
// 1) replace your original list of loaders with "happypack/loader":
// loaders: [ 'babel-loader?presets[]=es2015' ],
use: ['happypack/loader'?id=babel], // 这里的id 就是定义在plugin里面HappyPack实例构造参数传入的id
include: [ /* ... */ ],
exclude: [ /* ... */ ]
},
{
test: /.less$/,
use: 'happypack/loader?id=styles'
},
]
};
exports.plugins = [
// 2) create the plugin:
new HappyPack({
// 3) re-add the loaders you replaced above in #1:
loaders: [ 'babel-loader?presets[]=es2015' ],
threadPool: happyThreadPool,
id: 'babel'
}),
new HappyPack({
id: 'styles',
threadPool: happyThreadPool,
loaders: [ 'style-loader', 'css-loader', 'less-loader' ]
})
];
注意: **这部分,如果你是vueCli创建的项目,则不用配置, 内部已处理**
#### 关闭source map
生产环境关闭`productionSourceMap`、`css sourceMap`, 生产环境没必要打开这个
// vue.config.js
const isProduction = process.env.NODE_ENV === ‘production’
// 判断是否是生产环境
module.exports = {
productionSourceMap: !isProduction, //关闭生产环境下的SourceMap映射文件
css: {
sourceMap: !isProduction, // css sourceMap 配置
loaderOptions: {
…其它代码
}
},
…其它代码
}
#### 组件的按需加载配置
这里以ElementUi 为例, 其他组件库官网上会有对应说明, 大体上差不多
借助 babel-plugin-component,我们可以只引入需要的组件,以达到减小项目体积的目的。
npm install babel-plugin-component -D
// .babelrc 或者 babel.config.js
{
“presets”: [[“es2015”, { “modules”: false }]],
“plugins”: [
[
“component”,
{
“libraryName”: “element-ui”,
“styleLibraryName”: “theme-chalk”
}
]
]
}
如图,可以看到对比,


还有需要注意的是,如果你使用了自定义主题, 那么在babel的配置中如官网以下

#### 解决Echarts打包后体积过大问题
从刚开始的图中,能看到, echarts占了很大的体积, 这不能接受
##### 方案一
在index.html模板文件中引入cdn, 打包的时候webpack配置externals ,这样webpack就不会打这个包到vendors里,减少体积,缺点是cnd稳定性可能会有问题,而且是先请求cdn资源之后再请求自己服务器代码,非同源。pass
##### 方案二
`babel-plugin-equire` 我见社区有这个按需引入echarts的插件, 不过我没研究过, 感兴趣的可以去试试,我选择的是方案三
##### 方案三
在线定制echarts, 可以选择自己想要的功能,生成的js,就会小很多,
[在线定制网址](https://bbs.csdn.net/topics/618166371)
将生成的echarts.min.js引入到项目中,替换项目中的echarts引用
import echarts from ‘echarts’
变成下面
import echarts from ‘./plugins/echarts.min.js’
也可将这个js放到index.html里面,
在main.js文件里面
Vue.prototype.$echarts = window.echarts
同时可以卸载调之前装的echarts
npm unistall echarts


可以看到 还是很明显的变化的
接下来 再看看打包生成的report现状

可以看到pdf占比还是很大, 继续优化
#### pdf插件优化
项目中有pdf预览的功能,安装了`pdfjs-dist` 和`vue-pdf`两个插件,后来跟后端协商,走文件流的方式了, 就没用到这两个, 就卸载了, 如果谁有相关方案,欢迎来提
#### moment.js的优化
如果时间充裕,建议换成day.js 大小只有6kb, 但是我们项目里面用moment地方太多了,且比较混乱, 就暂时先不更换, 采用剔除其他语言包的方案
方案一
const MomentLocalesPlugin = require(‘moment-locales-webpack-plugin’);
module.exports = {
configureWebpack: {
plugins: [
new MomentLocalesPlugin({
// 保留一个
localesToKeep: [‘zh-cn’],
}),
]
}
}
//使用
import moment from ‘moment’;
// 按需加载需要引入对应的语言包
import ‘moment/locale/zh-cn’;
moment.locale(‘zh-cn’);
方案二
const webpack = require(‘webpack’);
module.exports = {
//…
plugins: [
// 忽略 moment.js的所有本地文件
new webpack.IgnorePlugin(/^./locale / , / m o m e n t /, /moment /,/moment/),
],
};
// 使用
import moment from ‘moment’;
// 按需加载需要引入对应的语言包
import ‘moment/locale/zh-cn’;
moment.locale(‘zh-cn’);


#### 针对lodash库优化
项目中有时会安装lodash,但一般只使用几个方法, 在打包的时候,会发现会将lodash全部打进去, 所以使用下面这两个库
* `babel-plugin-lodash` 用来精简Lodash模块的,只保留用到的方法。
* `lodash-webpack-plugin` 这个插件经过用noop, identity, 或其余更简单的替代品来替换一些模块的特性,使得打包后的体积更小(翻译)。
注意:这个插件默认会关闭一些lodash不经常使用的特性,能够给插件传递options来开启某些特性
modules.exports = {
// 其余配置省略…
plugins: [‘lodash’]
}
// vue.config.js
const LodashModuleReplacementPlugin = require(‘lodash-webpack-plugin’);
module.exports = {
// …
configureWebpack: {
plugins: [
new LodashModuleReplacementPlugin()
]
}
}
// 或者chainWebpack 但是我觉得这种写法,有点一言难尽
module.exports = {
chainWebpack: config => {
config.plugin(“loadshReplace”)
.use(new LodashModuleReplacementPlugin());
}
}


注意: 这个插件可能带来一些意想不到的坑, 可能会导致使用第三方插件报错出现一些其他问题,具体可以参考下这篇文章 [zhuanlan.zhihu.com/p/349260482](https://bbs.csdn.net/topics/618166371)
#### 开启 Tree Shaking 功能
在前面的依赖视图分析中可以看到sailfish 这个依赖,如下图,它是我们公司以前封装的UI库,它是以源码的方式供项目使用, 没有打包. 老项目里面用了几个组件,打包的时候发现还是全部打进来了


优化方式有以下几个点
1. 按需加载:在需要使用这个 UI 库的组件时再进行动态加载,不在打包时将整个库全部打入。
2. 开启 Tree Shaking:如果你使用的是 ES6 模块化的方式引入这个 UI 库,并且使用了相关的工具(如 webpack),则可以开启 Tree Shaking 功能,只将你用到的组件打入打包文件中,未使用的组件将会被去除。
3. 使用 babel-plugin-import 插件:有些 UI 库将所有的组件都导出为一个模块,对于这种情况,你可以使用 babel-plugin-import 插件,通过按需加载的方式只加载你使用的组件,而不是全部导入。
4. 自己打包:如果这个 UI 库的源码是开放的,而且你只想使用部分组件,那么你也可以自己将需要的组件单独打包,而不是全部打包。
因为后期规划要替换掉它,所以不想在它上面浪费过多精力
#### 其他的优化
##### externals
`externals`配置项用来告诉`Webpack`要构建的代码中使用了哪些不用被打包的模块,也就是说这些模版是外部环境提供的,`Webpack`在打包时可以忽略它们
一般是将体积较大的第三方包抽离为externals,一般处理`element-ui`,`vue`或者其他的,看自己项目
// vue.config.js
module.exports = {
configureWebpack: {
externals: {
// 安装的包名 — 暴露的全局变量的值
“element-ui”: “ELEMENT”,
echarts: “echarts”,
vue: “Vue”,
},
},
}
然后在index.html引入对应的cnd链接, 如果害怕cdn不稳定,可以去下载下来,copy到自己的项目中,手动引入, 也可使用webpack配置注入进去
// vue.config.js
module.exports = {
chainWebpack: config => {
config.plugin(‘html’).tap(args => {
args[0].cdn = {
js: [
‘https://xx.com/CDN/js/index-element-ui@2.13.0.js’,
],
css: [
‘https://xx.com/CDN/css/element-ui2.13.0/index.css’,
],
};
return args;
});
}
}
// 使用
<% for (var i in htmlWebpackPlugin.options.cdn&&htmlWebpackPlugin.options.cdn.css) { %> <% } %> <% for (var i in htmlWebpackPlugin.options.cdn&&htmlWebpackPlugin.options.cdn.js) { %> <% } %>
注意
* externals:声明文件被外部引用不用打包,不参与打包流程,由于直接写死在html里,可以使用cdn等加速
* externals缺点:直接html内引入的,所以不会有treeshaking,按需引入等,具体看自己取舍
推荐常用的两个cdn服务 BootCDN 与 cdnjs 。
#### 移除 preload(预载) 与 prefetch (预取)
vue 脚手架默认开启了 preload 与 prefetch,当我们项目很大时,会造成首屏加载速度慢的元凶
>
> preload 与 prefetch 都是一种资源预加载机制; preload 是预先加载资源,但并不执行,只有需要时才执行它; prefetch 是意图预获取一些资源,以备下一个导航/页面使用; preload 的优先级高于 prefetch。
>
>
>
// vue.config.js
chainWebpack: config => {
// 移除 preload(预载) 插件
config.plugins.delete(‘preload’)
// 移除 prefetch(预取) 插件
config.plugins.delete(‘prefetch’)
}
主要关注首屏速度, 可自行去体验下关闭前后的效果
#### 清除log等调试信息
使用 terser-webpack-plugin 清除 console.log
先安装依赖
npm install terser-webpack-plugin --save-dev
然后配置
const TerserPlugin = require(‘terser-webpack-plugin’);
module.exports = {
configureWebpack: config => {
❤️ 谢谢支持
喜欢的话别忘了 关注、点赞哦~。
开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
// 移除 preload(预载) 插件
config.plugins.delete(‘preload’)
// 移除 prefetch(预取) 插件
config.plugins.delete(‘prefetch’)
}
主要关注首屏速度, 可自行去体验下关闭前后的效果
#### 清除log等调试信息
使用 terser-webpack-plugin 清除 console.log
先安装依赖
npm install terser-webpack-plugin --save-dev
然后配置
const TerserPlugin = require(‘terser-webpack-plugin’);
module.exports = {
configureWebpack: config => {
❤️ 谢谢支持
喜欢的话别忘了 关注、点赞哦~。
开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
[外链图片转存中…(img-6f0IVaO4-1714164498360)]

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐
所有评论(0)