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

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

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

pdf插件优化

项目中有pdf预览的功能,安装了pdfjs-distvue-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$/, /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

开启 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-uivue或者其他的,看自己项目

// 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;
        });
    }
}
// 使用
<!DOCTYPE html>
<html lang="zh">
  <head>
    <% for (var i in htmlWebpackPlugin.options.cdn&&htmlWebpackPlugin.options.cdn.css) { %>
    <link href="<%= htmlWebpackPlugin.options.cdn.css[i] %>" rel="preload" as="style">
    <link href="<%= htmlWebpackPlugin.options.cdn.css[i] %>" rel="stylesheet">
    <% } %>
    <!-- 使用 CDN 加速的 JS 文件,配置在 vue.config.js 下 -->
    <% for (var i in htmlWebpackPlugin.options.cdn&&htmlWebpackPlugin.options.cdn.js) { %>
    <script src="<%= htmlWebpackPlugin.options.cdn.js[i] %>" type="text/javascript"></script>
    <% } %>
  </head>
  <body>
    <div id="app"></div>
  </body>
</html>
</html>

注意

  • 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 => {
    // 生产环境下清除 console.log
    if (process.env.NODE_ENV === 'production') {
      return {
        optimization: {
          minimizer: [
            new TerserPlugin({
              sourceMap: false,
              terserOptions: {
                compress: {
                  drop_console: true
                }
              }
            })
          ]
        }
      }
    }
  }
}

分包拆包

一般拆包原则如下

  • 将变动的与不易变动的资源进行分离 —> 有效利用缓存;* 将 node_modules 中的资源拆分出来,如果 node_modules 中的资源不变,就可以有效利用缓存,避免受到业务代码频繁改动的影响;
  • 将大的拆分成若干个小的 chunk —> 缩短单个资源下载时间;
  • 将公共模块抽离出来 —> 避免资源被重复打包,这样也可以在一定程度上减小打包产物总体积;
  • 将被多个 chunk 引用的包拆分成单独的模块;

要根据项目情况灵活配置,我就贴一个我在项目里使用的

// vue.config.js
module.exports = {
    chainWebpack(config) {
      config.when(process.env.NODE_ENV !== 'development',config => {
                    config
                        .optimization.splitChunks({
                            chunks: 'all',
                            cacheGroups: {
                                libs: {
                                    name: 'chunk-libs',
                                    test: /[\/]node_modules[\/]/,
                                    priority: 10,
                                    chunks: 'initial' // only package third parties that are initially dependent
                                },
                                elementUI: {
                                    name: 'chunk-elementUI', // split elementUI into a single package
                                    priority: 20, // the weight needs to be larger than libs and app or it will be packaged into libs or app
                                    test: /[\/]node_modules[\/]_?element-ui(.*)/ // in order to adapt to cnpm
                                },
                                commons: {
                                    name: 'chunk-commons',
                                    test: resolve('src/components'), // can customize your rules
                                    minChunks: 3, //  minimum common number
                                    priority: 5,
                                    reuseExistingChunk: true
                                }
                            }
                        })
                    // https:// webpack.js.org/configuration/optimization/#optimizationruntimechunk
                    config.optimization.runtimeChunk('single')
                }
            )
    }
}

压缩图片

项目里面后期肯定会放不少图片进去, 这些图片如果不压缩以下,占的资源就会非常大,社区里面有不少插件可以进行压缩,但我个人还是很喜欢熊猫压缩

推荐大家使用. 可以整个文件夹丢进去

结束语

一般常用的就这些,当然还有很多其他的优化方案, 这里没有绝对的最佳配置,只有最佳实践,大家根据自己的项目实际情况,逐步分析优化.

大厂面试题分享 面试题库

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

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

相关实践学习
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.(了解)表单校验插件】
13 4
|
4天前
|
JavaScript
vue尚品汇商城项目-day07【51.路由懒加载】
vue尚品汇商城项目-day07【51.路由懒加载】
14 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指令渲染列表