vue3 + vite 性能优化与开发经验分享

前言

本篇文章是笔者在使用 vue3 + vite 实际开发过程中的一些经验分享,涵盖 vite 构建优化配置项的实践,以及一些开发中实用技巧的分享。

gzip 压缩

未开启压缩时:通过vite打包之后,vite会提示开启 gzip压缩之后的文件大小,可以看到文件体积将会显著下降

接下来,我们使用 vite-plugin-compression 进行 gzip 压缩

javascript 复制代码
import viteCompression from 'vite-plugin-compression'
export default defineConfig({
  plugins: [
    viteCompression(),
  ],
})

通过 gzip 压缩之后,文件会被转化为 gz 压缩包,体积会明显减少,虽然是压缩包格式,但浏览器解压时间非常快,几乎可以忽略。所以开启 gzip 压缩 是有必要尝试的。

动态导入

使用动态导入,在 webpack 或 vite 这样的打包工具之中,都会自动开启代码分割。

路由懒加载

vue-router 路由懒加载

Vue Router 支持开箱即用的动态导入,这意味着你可以用动态导入代替静态导入:

javascript 复制代码
// 将
// import UserDetails from './views/UserDetails.vue'
// 替换成
const UserDetails = () => import('./views/UserDetails.vue')

const router = createRouter({
  // ...
  routes: [{ path: '/users/:id', component: UserDetails }],
})

异步导入组件

javascript 复制代码
import { defineAsyncComponent } from 'vue'

const AsyncComp = defineAsyncComponent(() =>
  import('./components/MyComponent.vue')
)

代码分割

所谓代码分割,实际上就是将大文件拆解为小文件,充分利用 http2 多路复用的特点,更高效的加载文件。以前一个大文件需要加载很长的时间,拆解为小文件,多个文件一起加载,就可以极大的提高网站的加载效率。

除了动态导入能够自动开启代码分割以外,我们还可以通过对 vite 进行配置来手动进行代码分割。

manualChunks 自定义分割

通过对 manualChunks 对象进行配置,自定义代码分割规则。key 为自定义名称,value 以数组形式配置,子元素可以填写 package.json名称 或 src/相对路径下的指定文件

ts 复制代码
// vite.config.ts
build: {
  // rollup 配置
  rollupOptions: {
    output: {
      manualChunks: {
        // vue vue-router合并打包
        vue: ['vue', 'vue-router'],
        lodash: ['lodash'],
        // 两个文件合并成一个文件
        a: ['src/components/a.vue','src/components/b.vue'],
        ...
      }
    }
  }
}

又或者你可以采用函数配置方法,可以更细粒度的去配置代码分割规则

ts 复制代码
// vite.config.ts
build: {
  // rollup 配置
  rollupOptions: {
    output: {
      manualChunks(id, { getModuleInfo }) {
        const match = /.*.strings.(\w+).js/.exec(id)
        if (match) {
          const language = match[1] // e.g. "en"
          const dependentEntryPoints = []
          const idsToHandle = new Set(getModuleInfo(id).dynamicImporters)

          for (const moduleId of idsToHandle) {
            const { isEntry, dynamicImporters, importers } = getModuleInfo(moduleId)
            if (isEntry || dynamicImporters.length > 0) dependentEntryPoints.push(moduleId)
            for (const importerId of importers) idsToHandle.add(importerId)
          }
          if (dependentEntryPoints.length === 1) {
            return `${dependentEntryPoints[0].split('/').slice(-1)[0].split('.')[0]}.strings.${language}`
          }
          if (dependentEntryPoints.length > 1) {
            return `shared.strings.${language}`
          }
        }
      },
    }
  }
}

设置路径别名

这样可以在引入文件时,不再需要使用相对路径,自定义起点路径,方便各个层级的代码引入。比如以下的代码示例,可以方便我们使用src目录下的文件。

ts 复制代码
// vite.config.ts
// 设置路径别名
resolve: {
  alias: [
    {
      find: '@',
      replacement: path.resolve('./src'),
    },
  ],
}
ts 复制代码
import { apiGetInfo } from '@/apis/funtion'
import { useStore } from '@/stores/index'

引入全局公共样式

vitejs.dev/config/shar...

所有预处理器选项支持additionalData选项,该选项可用于为每个样式内容注入额外的代码。以下以 less 为例子,注入全局的公共样式,使得各个 less 文件都可以直接使用公共文件中的样式,不用手动引入。

ts 复制代码
export default defineConfig({
  css: {
    preprocessorOptions: {
      less: {
        additionalData: `@import "@/styles/common.less";`,
      }
    },
  },
})
less 复制代码
// src\styles\common.less
.ellipsis {
  overflow: hidden; /* 超出部分被隐藏 */
  text-overflow: ellipsis; /* 被裁剪的文本使用省略号表示 */
  white-space: nowrap; /* 禁止换行,文本在一行内显示 */
}
less 复制代码
// 任意less文件
.text {
  .ellipsis;
}

terser 压缩

build.minify 中配置 terser,可以将打包体积降到最小。通过对 build.terserOptions 进行配置,可以更详细的配置你想要的效果。

build.minify 中配置 terser 时必须先安装 Terser。

shell 复制代码
npm i terser -D
ts 复制代码
// vite.config.ts
build: {
  minify: 'terser', //是否禁用最小化混淆,esbuild打包速度最快,terser打包体积最小。
  terserOptions: {
    compress: {
      drop_console: true,
      drop_debugger: true,
    },
    format: {
      comments: false, // 删除所有注释
    },
  },
},

强制预构建插件包

我们可以通过对 vite.config.ts 中 optimizeDeps 的配置来优化依赖项。

默认情况下,不在 node_modules 中的,链接的包不会被预构建。使用此选项可强制预构建链接的包。

使用强制预构建,可以提高后续页面的加载性能,因为Vite会将那些具有许多内部模块的 ESM 依赖项转换为单个模块。有些包将它们的 ES 模块构建为许多单独的文件,彼此导入。一旦模块变得也来越多,众多的HTTP请求导致浏览器将不堪重负,而通过预构建可以将其构建为单个模块,现在我们只需要一个HTTP请求。

如果你使用的是一个有很多深层导入的库,你也可以指定一个尾部的 glob 模式来一次性地预构建所有深层导入。这将避免在使用新的深层导入时不断地预构建。

ts 复制代码
export default defineConfig({
  optimizeDeps: {
    include: ['my-lib/components/**/*.vue'],
  },
})

依赖预构建

依赖预构建仅适用于开发模式,并使用 esbuild 将依赖项转换为 ES 模块。在生产构建中,将使用 @rollup/plugin-commonjs

其他打包配置优化

ts 复制代码
build: {
  chunkSizeWarningLimit: 2000,// chunk 超过 2000kb 之后进行提示
  cssCodeSplit: true, //css 拆分
  sourcemap: false, //不生成sourcemap
  assetsInlineLimit: 5000, //小于该值 图片将打包成Base64
},

后记

以上就是本次文章的全部内容,感谢观看,本篇文章均为个人实践经验分享,如有不对还请见谅,欢迎留言探讨。

相关推荐
hong_zc5 分钟前
初始 html
前端·html
小小吱10 分钟前
HTML动画
前端·html
糊涂涂是个小盆友31 分钟前
前端 - 使用uniapp+vue搭建前端项目(app端)
前端·vue.js·uni-app
Amd79444 分钟前
Nuxt.js 应用中的 schema:written 事件钩子详解
生命周期·vite·配置·日志·nuxt·服务·钩子
浮华似水1 小时前
Javascirpt时区——脱坑指南
前端
王二端茶倒水1 小时前
大龄程序员兼职跑外卖第五周之亲身感悟
前端·后端·程序员
_oP_i1 小时前
Web 与 Unity 之间的交互
前端·unity·交互
钢铁小狗侠1 小时前
前端(1)——快速入门HTML
前端·html
凹凸曼打不赢小怪兽1 小时前
react 受控组件和非受控组件
前端·javascript·react.js
狂奔solar2 小时前
分享个好玩的,在k8s上部署web版macos
前端·macos·kubernetes