Vue项目卡顿慢加载?这些优化技巧告诉你!(一)

简介: Vue项目卡顿慢加载?这些优化技巧告诉你!

大厂面试题分享 面试题库

前后端面试题库 (面试必备) 推荐:★★★★★

地址:前端面试题库  web前端面试题库 VS java后端面试题库大全

前端开发是一个快速发展的领域,每天都会涌现出新的技术和工具。在实现功能的同时,开发人员面临着许多挑战如代码可维护性,加载时间,访问速度,构建速度等问题。这些挑战可能直接影响网站的性能和用户体验,需要采取一些优化措施来改善问题。在本文中,我们将探讨一些前端项目优化的具体措施,旨在帮助开发人员提高项目效率,升级用户体验。

综合各方面来说 就是小, 少, 快

小:减少项目体积

使用模块化开发,禁止使用全局变量和函数,尽量减少污染全局变量;

合理使用 Tree Shaking 和 Dead Code Elimination,只打包使用到的代码;

对于静态资源,尽量使用 CDN 加载外部资源,减轻服务器负担;

使用 Code splitting 减小入口文件的大小,按需加载组件和路由;

对于需要在不同页面中间切换的模块可以考虑使用 Vue 的 keep-alive 缓存机制。

少:减少 HTTP 请求次数

首先明确必须要的请求,其余的请求可以通过 Vue 的异步组件按需加载;

将常用的图片、Logo、Icon 等打包到 CSS 文件中,减小图片请求次数;

对于 AJAX 请求,可以采用缓存和数据请求合并等优化方式,减少请求次数。

快:提高页面加载速度

对于 Vue 项目,使用 Vue-Router 实现路由懒加载、动态加载,以及异步组件等方式;

对于静态资源,如图片、CSS、JS 等文件,使用 Gzip 或者 Brotli 等方式进行压缩,减小文件大小;

合理使用缓存,如 CDN 缓存、浏览器缓存等;

对于 Vue 页面,采用服务端渲染(SSR)可以提高首屏渲染速度;

对于代码压缩、合并等优化,现代构建具如 Vue CLI 已经集成了很好的优化策略;

量化工具

在进行项目优化的时候,不能盲目的从网上或者其他文档上找优化配置进行添加,你需要对项目的实际情况进行一个了解, 才能对症下药, 比如你需要知道打包耗了多长时间,具体哪个loderl或者plugin耗时长,打包资源各个模块的体积等等.

所以在开始优化之前,需要安装一些插件,帮助我们分析

progress-bar-webpack-plugin 查看编译进度

// 安装  
npm i -D progress-bar-webpack-plugin
// 使用
const chalk = require('chalk')
const ProgressBarPlugin = require('progress-bar-webpack-plugin')
module.exports = {
  plugins: [
    // 进度条
    new ProgressBarPlugin({
        format: `  :msg [:bar] ${chalk.green.bold(':percent')} (:elapsed s)`
      })
  ],
}
// 包含内容、进度条、进度百分比、消耗时间,进度条

speed-measure-webpack-plugin 编译速度分析

这个插件可以我们知道哪些plugin,哪些loader所耗时长,以及总打包编译时长, 帮助我们针对性的优化

// 安装
npm i -D speed-measure-webpack-plugin
// 配置方式一, 如果你是webpack搭建的项目,
const SpeedMeasurePlugin = require("speed-measure-webpack-plugin");
const smp = new SpeedMeasurePlugin();
module.exports = smp.wrap({
  // ...webpack config...
})
// 如果你是vuecli搭建的项目, 则如下
const SpeedMeasureWebpackPlugin = require('speed-measure-webpack-plugin')
module.exports = {
  chainWebpack: config => {
    config.plugin('speed')
    .use(SpeedMeasureWebpackPlugin)
  }
}
效果如下

webpack-bundle-analyzer 打包体积优化

这个插件可以让我们看到打包后的资源之中每个模块的大小``

// 安装
npm i -D webpack-bundle-analyzer
// 使用 如果是webpack搭建的项目
// webpack.prod.js
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = {
  plugins: [
    // 打包体积分析
    new BundleAnalyzerPlugin()
  ],
}
**// 如果是vuecli  则无需安装 已经内部安装了**
直接使用 npm run build --report 命令 或者 npm run build -- --report
就会在打包目录下生成一个report.html文件,打开这个文件就知道了

配置指南

任何优化,都要对症下药,而不是盲目的从网上找配置一股脑地堆上去, 比如说启动慢,构建慢,则可以用下面提到的缓存和多核多进程相关的配置进行提升, 优化打包资源则需要要具体分析,如下图,这个是一个项目里面的打包资源分析(通过webpack-bundle-analyzer生成),可以清晰的知道生成打包资源各个模块的大小,进而针对性的优化.

打包生成的资源大小

开启压缩后,gizp资源的大小

使用缓存能力

增加对应的缓存配置, 可以很好的提升构建和启动速度, 尤其是多次构建和启动(或热更新)的场景

cache-loadercache 配置

在webpack搭建的项目中,可以使用上述两个东西,改善构建速度

但是在vuecli创建的项目则不用

VueCli自带

cache-loader 会默认为 Vue/Babel/TypeScript 编译开启。文件会缓存在 node_modules/.cache 中。 如果你遇到了编译方面的问题,记得先清缓存目录之后再试试看。

thread-loader 会在多核 CPU 的机器上为 Babel/TypeScript 转译开启。

hard-source-webpack-plugin

这个插件主要是利用缓存,提升二次启动和二次打包的速度, 效果很直观

使用方式

// vue.config.js  在vuecli中
const HardSourcePlugin = require('hard-source-webpack-plugin')
module.exports = {
 configureWebpack: {
        plugins: [new HardSourcePlugin()]
    }
}
// webpack.config.js  在webpack搭建的项目中
const HardSourcePlugin = require('hard-source-webpack-plugin')
module.exports = {
   mode: 'development',
   ...
   plugins: [new HardSourcePlugin()]
}

开启babel缓存

只需要在babel-loader的配置里加一个参数即可:cacheDirectory: true

 {
   test: /.js$/,
   exclude: /node_modules/,
   loader: 'babel-loader',
   options: {
     presets: [
       [
         '@babel/preset-env',
         {
           useBuiltIns: 'usage',
           corejs: { version: 3 },
           targets: {
             chrome: '60',
             firefox: '50'
           }
         }
       ]
     ],
     // 开启babel缓存
     // 第二次构建时,会读取之前的缓存
     cacheDirectory: true
   }
 },

生成gizp的打包资源

打包的时候开启gzip可以很大程度减少包的大小,页面大小可以变为原来的30%甚至更小,非常适合线上部署, 但还记得需要服务端支持

compression-webpack-plugin

前端配置

]// vue.config.js 在vuecli中
/* 第一种方式 */
const CompressionWebpackPlugin = require('compression-webpack-plugin')
const plugins = [...]
if (isProduction) {
    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 // 删除原文件
        })
    )
}
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

生产环境关闭productionSourceMapcss 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,就会小很多,

在线定制网址

将生成的echarts.min.js引入到项目中,替换项目中的echarts引用

import echarts from 'echarts'
变成下面
import echarts from './plugins/echarts.min.js'
也可将这个js放到index.html里面, 
<script src="./static/lib/echarts.min.js"></script>
在main.js文件里面
Vue.prototype.$echarts = window.echarts
同时可以卸载调之前装的echarts
npm unistall echarts

可以看到 还是很明显的变化的

接下来 再看看打包生成的report现状

可以看到pdf占比还是很大, 继续优化

Vue项目卡顿慢加载?这些优化技巧告诉你!(二):https://developer.aliyun.com/article/1415081

相关实践学习
Serverless极速搭建Hexo博客
本场景介绍如何使用阿里云函数计算服务命令行工具快速搭建一个Hexo博客。
相关文章
|
2天前
|
JavaScript
理解 Vue 的 setup 应用程序钩子
【10月更文挑战第3天】`setup` 函数是 Vue 3 中的新组件选项,在组件创建前调用,作为初始化逻辑的入口。它接收 `props` 和 `context` 两个参数,内部定义的变量和函数需通过 `return` 暴露给模板。`props` 包含父组件传入的属性,`context` 包含组件上下文信息。`setup` 可替代 `beforeCreate` 和 `created` 钩子,并提供类似 `data`、`computed` 和 `methods` 的功能,支持逻辑复用和 TypeScript 类型定义。
20 11
|
4天前
|
JavaScript
vue尚品汇商城项目-day07【vue插件-50.(了解)表单校验插件】
vue尚品汇商城项目-day07【vue插件-50.(了解)表单校验插件】
14 4
|
4天前
|
JavaScript
vue尚品汇商城项目-day07【51.路由懒加载】
vue尚品汇商城项目-day07【51.路由懒加载】
15 4
|
4天前
|
JavaScript
vue尚品汇商城项目-day07【vue插件-54.(了解)生成二维码插件】
vue尚品汇商城项目-day07【vue插件-54.(了解)生成二维码插件】
14 2
|
7天前
|
JavaScript
vue组件中的插槽
本文介绍了Vue中组件的插槽使用,包括单个插槽和多个具名插槽的定义及在父组件中的使用方法,展示了如何通过插槽将父组件的内容插入到子组件的指定位置。
|
5天前
|
JavaScript
vue消息订阅与发布
vue消息订阅与发布
|
6天前
|
JavaScript 前端开发 IDE
Vue学习笔记5:用Vue的事件监听 实现数据更新的实时视图显示
Vue学习笔记5:用Vue的事件监听 实现数据更新的实时视图显示
|
6天前
|
JavaScript 前端开发 API
Vue学习笔记4:用reactive() 实现数据更新的实时视图显示
Vue学习笔记4:用reactive() 实现数据更新的实时视图显示
|
5天前
|
JavaScript 前端开发
Vue学习笔记8:解决Vue学习笔记7中用v-for指令渲染列表遇到两个问题
Vue学习笔记8:解决Vue学习笔记7中用v-for指令渲染列表遇到两个问题
|
5天前
|
JavaScript 前端开发 API
Vue学习笔记7:使用v-for指令渲染列表
Vue学习笔记7:使用v-for指令渲染列表