前言
在现代 Web 开发中,前端性能优化至关重要。Vue 3 和 Vite 作为新一代的前端框架和构建工具,提供了许多性能优化的功能和实践方法。 本文结合实际开发做一些总结分享,帮助大家在以后的开发过程中能够实际运用到,希望能帮到大家。
性能指标
在开始优化之前,了解一些关键的性能指标非常重要:
- 页面加载时间(Load Time) :从用户发出请求到页面完全加载所需的时间。
- 首次内容绘制(First Contentful Paint, FCP) :浏览器渲染出第一个内容元素的时间点。
- 最大内容绘制(Largest Contentful Paint, LCP) :页面主要内容加载完成的时间点。
- 累计布局偏移(Cumulative Layout Shift, CLS) :页面视觉稳定性的衡量标准。
- 交互延迟(Time to Interactive, TTI) :页面可完全交互的时间点。
总结一下就是:一个字快
,三个字 响应快
优化方向整体介绍
- 优化工具辅助工具,为什么我把它放在第一位因为在实际优化过程中它真的非常好用, rollup-plugin-visualizer是一个强大且直观的工具,用于帮助开发者在使用 Rollup 打包时,生成详细的模块依赖图谱。通过可视化的方式,你可以清晰地理解代码的打包结构和优化潜在点,从而更高效地管理和优化你的 JavaScript 应用程序。
- 安装
npm install --save-dev rollup-plugin-visualizer
或者yarn add --dev rollup-plugin-visualizer
- 使用
rollup-plugin-visualizer
这里有一个坑在新版中是不支持默认导入,所有有些网上有些资料是直接默认导入的这样会报错visualizer is not function
,所以在实际使用中需要注意版本。
vite.config.ts
import { defineConfig, PluginOption } from 'vite'
import vue from '@vitejs/plugin-vue'
import { resolve } from 'node:path';
import {visualizer} from 'rollup-plugin-visualizer'
// https://vitejs.dev/config/
export default defineConfig({
resolve: {
alias: [
{
find: '@',
replacement: resolve(__dirname, './src'),
},
],
},
plugins: [
vue(),
visualizer({
open: true //在默认用户代理中打开生成的文件
}),
],
})
- 可以清晰的知道每一个模块之间的依赖的关系,占比大小等等。
2.减少包的体积:按需使用第三方库
、提炼公共组件公共方法减少冗余
、 代码压缩
、 图片压缩
、字体文件等资源压缩
。
3.减少HTTP请求: 合并文件
、使用图像精灵(Sprite)技术
、使用字体图标代替图片
。
4.使用cdn:减轻源服务器的压力
、同域名的并发请求限制数量为一般6个
。
5.缓存策略:主要有HTTP缓存
和浏览器缓存
。
具体优化实施
1.router路由懒加载 +webpackchunkname
如果使用 router 的静态引入路由的话,打包后所有组件会打包成一个js和css 文件这样文件就非常大,影响页面加载,Vue Router 支持开箱即用的动态导入,这意味着你可以用动态导入代替静态导入。这样就可以把对应的组件打包成单独的文件,只会在路由被访问的时候才加载对应组件文件。
如果把所有的组件都打包成独立的文件,这样http请求数量又变多了,所以我们需要用到webpackChunkName将相同name的组件打包到一个文件中,因为我们是vite 项目 要想实现 webpackChunkName
还需要用到 vite-plugin-webpackchunkname
插件。插件如何使用我就不介绍了,主要看下路由文件怎么写的。
router/index.ts
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router';
// import Home from '@/view/home/index.vue';
// import HomeInfo from '@/view/home/info.vue';
// import About from '@/view/about/index.vue';
// import AboutInfo from '@/view/about/info.vue';
const routes: RouteRecordRaw[] = [
{
path: '/',
name: 'Layout',
redirect: '/home',
meta: {
title: '根路由',
},
children: [
{
path: '/home',
name: 'Home',
component: () => import(/* webpackChunkName: "home" */'@/view/home/index.vue'),// Home,
meta: {
title: '首页',
},
},
{
path: '/home/info',
name: 'HomeInfo',
component: () => import(/* webpackChunkName: "home" */'@/view/home/info.vue'),// HomeInfo,
meta: {
title: '首页详情',
},
},
{
path: '/about',
name: 'About',
component: () => import(/* webpackChunkName: "about" */'@/view/about/index.vue'), //About,
meta: {
title: '关于',
},
},
{
path: '/about/info',
name: 'AboutInfo',
component: () => import(/* webpackChunkName: "about" */'@/view/about/info.vue'), //AboutInfo,
meta: {
title: '关于详情',
},
},
],
}
];
const router = createRouter({
history: createWebHistory(),
routes,
});
export default router;
2.利用 vite build.rollupOptions.output manualChunks
合并拆分代码,利用 *FileNames 把文件分组方便查看维护 ,利用 terser 移除 打印 只需要安装 npm i terser
即可 配置参照下面内容。
vite.config.ts
import { defineConfig, PluginOption } from 'vite'
import vue from '@vitejs/plugin-vue'
import { resolve } from 'node:path';
import {visualizer} from 'rollup-plugin-visualizer'
import { manualChunksPlugin } from 'vite-plugin-webpackchunkname'
// https://vitejs.dev/config/
export default defineConfig({
resolve: {
alias: [
{
find: '@',
replacement: resolve(__dirname, './src'),
},
],
},
plugins: [
vue(),
visualizer({
open: true //在默认用户代理中打开生成的文件
}),
manualChunksPlugin()
],
build: {
terserOptions: {
compress: {
//生产环境时移除console
drop_console: true,
drop_debugger: true,
},
},
// 关闭文件计算
reportCompressedSize: false,
// 关闭生成map文件 可以达到缩小打包体积
sourcemap: false, // 这个生产环境一定要关闭,不然打包的产物会很大
// 压缩
minify: false,
cssCodeSplit: true,
rollupOptions: {
output: {
// 入口文件名
entryFileNames: `assets/js/[name]-[hash].js`,
// 块文件名
chunkFileNames: `assets/js/[name]-[hash].js`,
// 资源文件名 css 图片等等
assetFileNames: `assets/[ext]/[name]-[hash].[ext]`,
// 大文件拆分
manualChunks(id) {
if (id.includes("node_modules")) {
//把vue vue-router @vueuse 等核心模块打包成一个文件
if (id.includes('vue')) {
return 'vue';
}else{
//最小化拆分包
return id
.toString()
.split("node_modules/")[1]
.split("/")[0]
.toString();
}
}
},
},
},
},
})
3.使用图像精灵(Sprite)技术 这个技术在几年前很有必要,但是到了现在好像用到的就很少了,大部分都是用的字体图标库。
将多个小图标合并成一张大图,并使用 CSS 来显示其中的部分图像,减少 HTTP 请求。
首先,创建一个包含多个图标的 Sprite 图:将多个小图标合并成一张大图,并使用 CSS 来显示其中的部分图像,减少 HTTP 请求。
css
/* styles/sprite.scss */
.icon {
background-image: url('/path/to/sprite.png');
background-repeat: no-repeat;
}
.icon-home {
background-position: 0 0;
width: 32px;
height: 32px;
}
.icon-settings {
background-position: -32px 0;
width: 32px;
height: 32px;
}
4.使用CDN 减少自己服务器负载,加快资源请求
- 在 Vite 项目中,可以通过配置将某些依赖项从打包中排除,并改为从 CDN 加载。
vite.config.ts
// vite.config.js
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
export default defineConfig({
plugins: [vue()],
build: {
rollupOptions: {
external: ['vue'],
output: {
globals: {
vue: 'Vue',
}
}
}
}
});
- 在
index.html
中引入 CDN 资源:
index.html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + Vue + TS</title>
<script src="https://cdn.jsdelivr.net/npm/vue@3.4.29"></script>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
5. 静态压缩优化 npm i vite-plugin-compression -D
以及优化字体文件大小 字体压缩格式转换我直接推荐一个在线网站
安装插件 npm i vite-plugin-compression -D
这个需要后端配合 修改nginx 文件才有用
vite.config.ts
import { defineConfig, PluginOption } from 'vite'
import vue from '@vitejs/plugin-vue'
import { resolve } from 'node:path';
import {visualizer} from 'rollup-plugin-visualizer'
import { manualChunksPlugin } from 'vite-plugin-webpackchunkname'
import { imagetools } from 'vite-imagetools';
// https://vitejs.dev/config/
export default defineConfig({
resolve: {
alias: [
{
find: '@',
replacement: resolve(__dirname, './src'),
},
],
},
plugins: [
vue(),
visualizer({
open: true //在默认用户代理中打开生成的文件
}),
manualChunksPlugin(),
imagetools()
],
build: {
terserOptions: {
compress: {
//生产环境时移除console
drop_console: true,
drop_debugger: true,
},
},
// 关闭文件计算
reportCompressedSize: false,
// 关闭生成map文件 可以达到缩小打包体积
sourcemap: false, // 这个生产环境一定要关闭,不然打包的产物会很大
// 压缩
minify: false,
cssCodeSplit: true,
rollupOptions: {
// 忽略打包vue文件
external: ['vue'],
output: {
globals: {
vue: 'Vue', //cdn 配置
},
// 入口文件名
entryFileNames: `assets/js/[name]-[hash].js`,
// 块文件名
chunkFileNames: `assets/js/[name]-[hash].js`,
// 资源文件名 css 图片等等
assetFileNames: `assets/[ext]/[name]-[hash].[ext]`,
// 大文件拆分
manualChunks(id) {
if (id.includes("node_modules")) {
//把vue vue-router @vueuse 等核心模块打包成一个文件
if (id.includes('vue')) {
return 'vue';
}else{
//最小化拆分包
return id
.toString()
.split("node_modules/")[1]
.split("/")[0]
.toString();
}
}
},
},
},
},
})
6. 组件按需引入,一般参照官方文档配置即可
本项目用到了 按需引入 element-puls
首先你需要安装unplugin-vue-components
和 unplugin-auto-import
这两款插件
arduino
npm install -D unplugin-vue-components unplugin-auto-import
完整 vite.config.ts 配置如下
vite.config.ts
import { defineConfig, PluginOption } from 'vite'
import vue from '@vitejs/plugin-vue'
import { resolve } from 'node:path';
import {visualizer} from 'rollup-plugin-visualizer'
import { manualChunksPlugin } from 'vite-plugin-webpackchunkname'
import viteCompression from 'vite-plugin-compression'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
// https://vitejs.dev/config/
export default defineConfig({
resolve: {
alias: [
{
find: '@',
replacement: resolve(__dirname, './src'),
},
],
},
plugins: [
vue(),
visualizer({
open: true //在默认用户代理中打开生成的文件
}),
manualChunksPlugin(),
// 静态资源压缩
viteCompression({
verbose: true, // 默认即可
disable: false, // 开启压缩(不禁用),默认即可
deleteOriginFile: false, // 删除源文件
threshold: 5120, // 压缩前最小文件大小
algorithm: 'gzip', // 压缩算法
ext: '.gz' // 文件类型
}),
AutoImport({
resolvers: [ElementPlusResolver()],
}),
Components({
resolvers: [ElementPlusResolver()],
}),
],
build: {
terserOptions: {
compress: {
//生产环境时移除console
drop_console: true,
drop_debugger: true,
},
},
// 关闭文件计算
reportCompressedSize: false,
// 关闭生成map文件 可以达到缩小打包体积
sourcemap: false, // 这个生产环境一定要关闭,不然打包的产物会很大
// 压缩
minify: false,
cssCodeSplit: true,
rollupOptions: {
// 忽略打包vue文件
external: ['vue'],
output: {
globals: {
vue: 'Vue', //cdn 配置
},
// 入口文件名
entryFileNames: `assets/js/[name]-[hash].js`,
// 块文件名
chunkFileNames: `assets/js/[name]-[hash].js`,
// 资源文件名 css 图片等等
assetFileNames: `assets/[ext]/[name]-[hash].[ext]`,
// 大文件拆分
manualChunks(id) {
if (id.includes("node_modules")) {
//把 vue-router @vueuse 等核心模块打包成一个文件
if (id.includes('vue-router') || id.includes('vueuse')) {
return 'vue';
}else{
//最小化拆分包
return id
.toString()
.split("node_modules/")[1]
.split("/")[0]
.toString();
}
}
},
},
},
},
})
总结
暂时想到的就这么多,希望通过本文知识点 结合 Vue 3 和 Vite 的性能优化策略,可以有效提升你的 Web 应用的性能。
最后放上本篇文章用到的项目应用demo 如果有疑问的可以把demo 下载下来自己去跑一跑 ,试着从头开始一步一步修改代码,多次打包看结果进行对比,这样可以加深理解。 如果这篇文章对你有所帮助,可以来波点赞收藏加关注。