webpack代码优化-Vue 项目性能优化 – 动手手册(最完整/最详尽的在线)。

序言

Vue 框架通过单向数据绑定和虚拟 DOM 技术帮助我们处理后端开发中最脏、最累的 DOM 操作,我们不再需要思考如何操作 DOM,如何最高效地操作 DOM;但是 Vue 项目中一直存在项目首屏优化、Webpack 编译配置优化等问题,所以我们仍然需要注意 Vue 项目性能的优化,让项目性能更高效,用户体验更好。本文是笔者通过实际项目的优化实践进行总结,希望读者看完本文后能有所启发,从而有助于优化自己的项目。本文内容分为以下三个部分:努力

了很久,希望自动点赞和鼓励~

github地址是:github.com/fengshi123/...,总结了作者所有的博客,也欢迎大家关注和加星~

一、代码级优化 1.1、v-if 和 v-show 区分使用场景

V-if 是真正的条件渲染,因为它确保条件块中的风暴错误和子组件在切换过程中被正确销毁和重建;它也是懒惰的:如果在初始渲染时条件为 false,则不执行任何操作 - 直到条件首先变为 true,条件块将开始渲染。

v-show 要简单得多,无论初始条件如何,元素都会始终被渲染,并且只需根据 CSS 的显示属性进行切换即可。

因此,V-IF适用于运行过程中条件很少变化,不需要频繁切换条件的场景;V-show适用于条件需要特别频繁切换的场景。

1.2 计算和监视区分使用场景

computed:是一个估计的属性,依赖于其他属性值webpack代码优化,但 COMPUTE d 的值有一个缓存,只有它所依赖的属性的值发生变化,下次获取 COMPUTED 的值时会重新估计 COMPUTED 的值;

观看:更多的是“观察”角色,类似于单个数据的窃听跳票,每次线投数据发生变化时,都会执行跳出以进行后续操作;

场景:

1.3、v-for 遍历必须给项添加键,并避免同时使用 v-if

(1) v-for 遍历必须为项目添加键

在遍历和渲染列表数据时,需要为每个项设置一个唯一的键值,以便 Vue 能够准确地找到列表数据.js内部机制。更新状态时,会将新状态值与旧状态值进行比较,并快速定位到差异。

(2) V-for 遍历可防止同时使用 V-IF

V-for 的优先级比 V-if 高,如果每次都要遍历整个链表,会影响速率,尤其是需要渲染一小部分的时候,必要时应该用 computed 属性替换。

推荐:

  • {{ user.name }}
computed: { activeUsers: function () { return this.users.filter(function (user) { return user.isActive }) } }

不推荐:

  • {{ user.name }}

1.4. 长列表性能优化

Vue 会绑架数据

通过 Object.defineProperty 来实现对数据变化的视图响应,但有时候我们的组件都是纯数据显示的,不会有任何变化,我们不需要 Vue 来绑架我们的数据,在大量数据显示的情况下,这可以大大减少组件初始化的时间,那么如何严格禁止 Vue 绑架我们的数据呢?您可以通过 Object.freeze 冻结对象,一旦冻结的对象就无法再更改。

export default {
  data: () => ({
    users: {}
  }),
  async created() {
    const users = await axios.get("/api/users");
    this.users = Object.freeze(users);
  }
};

1.5. 销毁事件

当一个 Vue 组件被销毁时,它会手动清除它与其他实例的连接,解绑它的所有指令和风暴 bug,并且只限制在组件本身的风波上。如果 js 中的 addEventListene 等方法不会被手动销毁,我们需要在组件销毁时自动删除那些暴风雨般的窃听,以免造成内存泄漏,例如:

created() {
  addEventListener('click', this.click, false)
},
beforeDestroy() {
  removeEventListener('click', this.click, false)
}

1.6. 图片资源的延迟加载对于图片过多的页面,

为了加快页面加载速度,很多时候我们需要不加载页面可视区域中没有出现的图片,等到它们滚动到可视区域后再加载。这将大大提高页面加载性能并改善用户体验。我们在项目中使用 Vue 的 vue-lazyload 插件

(1) 安装插件

npm install vue-lazyload --save-dev

(2)在词条档案中介绍和使用.js

import VueLazyload from 'vue-lazyload'

之后,可以直接在 Vue 中使用

Vue.use(VueLazyload)

或添加自定义选项

Vue.use(VueLazyload, {
preLoad: 1.3,
error: 'dist/error.png',
loading: 'dist/loading.gif',
attempt: 1
})

(3) 在 vue 文件上将 img 标签的 src 属性直接改为 v-lazy,因此将图像显示方式修改为延迟加载显示:

"/static/img/1.png">

以上就是 vue-lazyload 插件的简单用法,如果想看插件的更多参数选项,可以查看 vue-lazyload 的 github 地址。

1.7. 延迟加载路由

Vue 是一个单页应用,可能会有很多路由引入,这样用 webpcak 打包的文件非常大,当步入首页时,加载的资源太多,页面会出现蓝屏,不利于用户体验。如果我们能将不同路由对应的组件拆分成不同的代码块,然后在访问路由时加载相应的组件,效率会更高。这将大大增加折叠显示的速率,并可能减慢其他页面的速率。

路由延迟加载:

const Foo = () => import('./Foo.vue')
const router = new VueRouter({
  routes: [
    { path: '/foo', component: Foo }
  ]
})

1.8. 按需引入第三方插件

我们经常需要在项目中引入第三方插件,如果我们直接引入整个插件,会导致项目的体积过大,我们可以使用 babel-plugin-component,然后我们只能引入所需的组件来达到减少项目体积的目的。以下是将元素 UI 组件库引入项目的示例:

(1) 首先,安装 babel-plugin-component:

npm install babel-plugin-component -D

(2) 之后,将 .babelrc 更改为:

{
  "presets": [["es2015", { "modules": false }]],
  "plugins": [
    [
      "component",
      {
        "libraryName": "element-ui",
        "styleLibraryName": "theme-chalk"
      }
    ]
  ]
}

(3)在主.js中引入一些组件:

import Vue from 'vue';
import { Button, Select } from 'element-ui';
 Vue.use(Button)
 Vue.use(Select)

1.9. 优化无限列表的性能

如果您的应用程序具有特别长或无限滚动的列表webpack代码优化,则需要使用窗口来优化性能,仅呈现一小部分内容,并减少重新呈现组件和创建 DOM 节点的时间。你可以参考以下开源项目 vue-virtual-scroll-list 和 vue-virtual-scroller 来优化这些无限列表场景。

1.10. 服务器端渲染 SSRor 预渲染

服务端渲染是指 Vue 在客户端由标签渲染的整个 HTML 片段在服务器上完成,服务端生成的 HTML 片段直接返回给客户端,称为服务端渲染。

(1)服务器端渲染的优点:

(2)服务器端渲染的缺点:

如果您的项目是

SEO 和首屏渲染是评价项目的关键指标,那么你的项目需要服务器端渲染来帮助你实现最佳的初始加载性能和 SEO,如何实现 VueSSR 可以参考作者的另一篇文章《VueSSR 踏上坑之旅》。如果你的 Vue 项目只需要改进几个营销页面的 SEO(例如 /、/about、/contact 等),那么你可能需要预渲染并在构建时为特定路由生成一个静态 HTML 文件。优点是设置预渲染更容易,您可以将后端用作完全静态的站点,您可以使用预渲染-spa-插件轻松添加。

二、Webpack 级别优化 2.1、Webpack 压缩镜像

在 vue 项目中,你不仅可以在 webpack.base.conf 的 url-loader 中设置限制大小,.js来处理图像,将大于限制的图像转换为 base64 格式,其余的都不做。所以对于一些较大的图片资源,在请求资源时加载会很慢,我们可以使用 image-webpack-loader 来压缩图片:

(1) 首先,安装镜像包加载器:

npm install image-webpack-loader --save-dev

(2)之后,在webpack.base.conf.js中配置它:

{
  test: /.(png|jpe?g|gif|svg)(?.*)?$/,
  use:[
    {
    loader: 'url-loader',
    options: {
      limit: 10000,
      name: utils.assetsPath('img/[name].[hash:7].[ext]')
      }
    },
    {
      loader: 'image-webpack-loader',
      options: {
        bypassOnDebug: true,
      }
    }
  ]
}

2.2. 将冗余代码从 ES6 减少到 ES5

Babel 插件在将 ES6 代码转换为 ES5 代码时会注入一些辅助函数,比如下面的 ES6 代码:

class HelloWebpack extends Component{...}

将此代码转换为工作 ES5 代码时,需要以下两个辅助函数:

babel-runtime/helpers/createClass  // 用于实现 class 语法
babel-runtime/helpers/inherits  // 用于实现 extends 语法    

默认情况下,Babel 在每个输出文件中嵌入依赖的帮助程序代码,如果多个源代码文件依赖于此类帮助程序函数,则此类帮助程序函数的代码将出现多次,从而导致代码冗余。为了不重复此类帮助程序函数的代码,当它们依赖时,您可以通过 require('babel-runtime/helpers/createClass') 方法导出它们,以便它们只出现一次。使用 babel-plugin-transform-runtime 插件来实现此功能,将相关的辅助函数替换为导出的句子,从而减小 babel 编译的代码的文件大小。

(1) 首先,安装 babel-plugin-transform-runtime:

npm install babel-plugin-transform-runtime --save-dev

(2) 之后,将 .babelrc 配置文件更改为:

"plugins": [
    "transform-runtime"
]

有关插件的更多详细信息,请查看 babel-plugin-transform-runtime。

2.3. 提取公共代码

如果在项目中没有提取每个页面的第三方库和公共模块,则项目将出现以下问题:

所以我们需要将多个页面的通用代码提取到单独的文件中,以优化上述问题。Webpack 有一个插件 CommonsChunkPlugin,专门设计用于从多个块中提取公共部分,我们在项目中配置共享资源块插件如下:

// 所有在 package.json 里面依赖的包,都会被打包进 vendor.js 这个文件中。
new webpack.optimize.CommonsChunkPlugin({
  name: 'vendor',
  minChunks: function(module, count) {
    return (
      module.resource &&
      /.js$/.test(module.resource) &&
      module.resource.indexOf(
        path.join(__dirname, '../node_modules')
      ) === 0
    );
  }
}),
// 抽取出代码模块的映射关系
new webpack.optimize.CommonsChunkPlugin({
  name: 'manifest',
  chunks: ['vendor']
})

有关插件的更多详细信息,请查看CommonsChunkPlugin的详细介绍。

2.4. 模板预编译

DOM 或 JavaScript 中的字符串模板,模板在运行时编译为渲染函数。通常,此过程足够快,但对于性能敏感的应用程序,最好避免这些用法。

预编译模板的最简单方法是使用单文件组件 — 相关的构建设置将手动预编译,因此创建的代码已包含编译的渲染函数而不是原始模板字符串。

如果您使用

webpack 并且更喜欢将 JavaScript 与模板文件分开,可以使用 vue-template-loader,它也可以在创建过程中将模板文件转换为 JavaScript 渲染函数。

2.5 提取组件的 CSS

使用单文件组件时,组件内部的 CSS 通过 JavaScript 以样式标签的形式动态注入。这是一个很小的运行时费用,如果使用服务器端渲染,可能会导致“完美内容闪烁”(FOUC)。将所有组件的 CSS 提取到同一个文件中将避免此问题,并且还可以更好地压缩和缓存 CSS。

1. 图像优化措施

优化图像是 Web 后端优化的重要组成部分,因为图像是网页中带宽消耗最大和加载时间最长的资源之一。以下是通过优化图像来优化 Web 后端的一些方法:

压缩图像:压缩图像可以减小图片的文件大小,从而减少加载时间。

使用矢量图形

:使用矢量图形(如 SVG)可减小文件大小并无限缩放而不会失真。

使用网络P

格式化图像:WebP 是 Google 开发的一种图像格式,可大幅减小文件大小,从而减少加载时间。WebP图像可用于现代浏览器webpack 图片压缩方案,如Chrome,Firefox,Edge和Opera。使用适当的图片格式

:使用适当的图片格式可以大大减小图片的文件大小。对于需要透明背景的图像,请使用 PNG 格式;对于颜色较少的图像,请使用 GIF 格式;对于照片和复杂图像,使用 JPEG 格式。删除图像元数据

:图像通常包含元数据,例如拍摄日期、相机型号等。删除此元数据可以减小图像的文件大小。缓存图像

:在浏览器中缓存图像可以减少页面加载时间。您可以使用浏览器缓存机制或 CDN 来缓存图像。

CSSSprites:使用 CSSSprites 将多个图像合并为一个大图像,减少页面上的图像数量,从而减少 HTTP 请求的数量,减少页面的加载时间。图像预加载

:通过预加载图像,您可以改善用户体验并减少加载时间。您可以使用预加载或预提取标签来预加载图像。

用响应

式图像:使用响应式图像根据设备的帧速率提供不同大小的图像,从而减少加载时间和带宽消耗。您可以使用 srcset 属性和 size 属性来实现响应式图像。

使用延迟加载延迟加载图像

:Lazyload 是一种延迟加载技术,它会延迟页面中的图像,直到用户滚动到页面上的适当位置。这减少了页面的初始加载时间,但改善了用户体验。延迟加载技术或IntersectionObserver API可用于延迟加载图像。使用 CDN 加速图片加载

:CDN 可以将图片缓存到靠近用户的节点,从而提高图片加载率和用户体验。

二、图像优化实践2.1、压缩图片

基于 Vue3+Webpack5 的 vue.config .js配置示例:

您需要安装映像-webpack-loader:

npm install image-webpack-loader --save-dev

将以下代码添加到 vue.config.js 文件中:

const { defineConfig } = require("@vue/cli-service");
module.exports = defineConfig({
  transpileDependencies: true,
  devServer: {
    port: 8123,
    // 调试时启用 gzip 压缩
    compress: true,
    // 调试时允许内网穿透,让外网的人访问到本地调试的 H5 页面
    disableHostCheck: true,
  },
  configureWebpack: {
    plugins: [],
    module: {
      rules: [],
    },
  },
  chainWebpack: (config) => {
    const imagesRule = config.module.rule("images");
    imagesRule
      .use("image-webpack-loader")
      .loader("image-webpack-loader")
      .options({
        mozjpeg: {
          progressive: true,
          quality: 65,
        },
        optipng: {
          enabled: false,
        },
        pngquant: {
          quality: [0.65, 0.9],
          speed: 4,
        },
        gifsicle: {
          interlaced: false,
        },
        webp: {
          quality: 75,
        },
      });
  },
});

2.2. 使用 SVG 格式的图片

优化思路:由于JPEG、PNG、GIF格式的图像不能通过gzip等压缩算法进行压缩,所以可以使用SVG矢量图形(文本类型)通过gzip等压缩算法压缩文本。

如果您需要使用 SVG

图像,最好使用专门的SVG编辑器或绘图工具来创建或编辑它们,例如Inkscape,一种流行的开源矢量图形编辑器。

2.3. 使用 WebP/AVIF 格式的图片

以下一代格式交付图像:WebP 和 AVIF 等图像格式通常比 PNG 或 JPEG 压缩得更好,从而加快下载速度并减少数据消耗。

使用 picture 元素在 HTML 文件中加载图像,以支持不同的图像格式并与不支持 WebP 图像的浏览器兼容:


  
  

通过使用 WebP/AVIF 格式的图像,以及通过使用 HTML 文件中的图片元素加载图像来支持不同的图像格式。这有效地减少了带宽使用并提高了图像加载率,从而提高了网站性能和用户体验。

将 PNG/JPEG 格式的图像转换为 WebP 格式的图像

使用在线工具:jpg-to-webp使用Python批量转换图像

:Python实现图像规范和转换处理

2.4 使用Image Base64编码的DataURI

优化思路:由于 JPEG、PNG 和 GIF 格式的图片无法通过 gzip 等压缩算法进行压缩,通过配置 webpack,当打包时,将 JPEG、PNG 和 GIF 格式的图片转换为 Image Base64 编码的 DataURI,文本可以通过 gzip 等压缩算法进行压缩。

应该注意的是,将图像转换为图像 Base64 编码的 DataURI 字符串可能会导致文件过大webpack 图片压缩方案,并影响应用程序的加载速率。为此,建议只将小文件转换为base64编码的字符串,将大文件编译成普通图像文件。

基于 Vue2+Webpack4 的 vue.config .js配置示例:

// vue.config.js
module.exports = {
  devServer: {
    host: "0.0.0.0",
    port: 9999,
    https: false,
    // 调试时启用 gzip 压缩
    compress: true,
    // 调试时允许内网穿透,让外网的人访问到本地调试的 H5 页面
    disableHostCheck: true,
  },
  configureWebpack: {
    rules: [],
    plugins: [],
  },
  configureWebpack: (config) => {},
  chainWebpack: (config) => {
    config.module
      .rule("images")
      .test(/.(png|jpe?g|gif)$/i)
      .use("url-loader")
      .loader("url-loader")
      .tap((options) => {
        // 将文件大小限制为100kb以内,超过100kb的文件将被编译成普通的图片文件。
        options.limit = 100 * 1024;
        return options;
      });
  },
};

2、Vue3+Webpack5 vue.config .js配置示例:

// vue.config.js
const path = require("path");
const { defineConfig } = require("@vue/cli-service");
module.exports = defineConfig({
  transpileDependencies: true,
  devServer: {
    port: 8123,
    // 调试时启用 gzip 压缩
    compress: true,
    // 调试时允许内网穿透,让外网的人访问到本地调试的 H5 页面
    disableHostCheck: true,
  },
  configureWebpack: {
    module: {
      rules: [
        {
          test: /.(png|jpe?g|gif)$/i,
          type: "asset",
          parser: {
            dataUrlCondition: {
              maxSize: 100 * 1024, // 将文件大小限制为 100kb 以内,超过 100kb 的文件将被编译成普通的图片文件。
            },
          },
        },
      ],
    },
  },
  chainWebpack: (config) => {
    config.resolve.alias.set("@", path.resolve(__dirname, "src"));
  },
});

该代码展示了如何使用 Webpack5 的资产模块将图像转换为 base64 编码的字符串。通过配置 dataUrlCondition.maxSize,可以指定将大文件转换为 base64 编码字符串的程度。大于此大小的文件将被编译为普通图像文件。

另外,为了防止在 Vue3 中使用导入短语时出现相对路径的问题,可以通过 chainWebpack 配置别名,提示我们使用 @ 而不是 src 目录路径。

从上面的对比可以看出,累积布局偏斜(CLS,累积布局移位)指标已经优化,这是一个意想不到的优化,因此不确定优化是否会达到预期。