Vue3 还原一个企业级后台-12-性能优化
性能优化路由懒加载、组件按需引入原型也要快。前面三篇业务模块写完页面一多首屏直接飙到 3 秒、打包 1.8MB——虽然 Mock 数据让原型看起来像真的但加载速度暴露了它是原型。本文用 5 个优化把首屏压到 0.9 秒打包缩到 580KB。一、先看现状优化前的基线数据优化之前先跑一组基线否则你不知道优化到底有没有效果。pnpmbuildVite 的构建输出会直接告诉你包体大小dist/index.html 0.45 kB dist/assets/index-d25b7a3e.css 398.52 kB # 全是 Element Plus 的样式 dist/assets/index-c8e1ff01.js 1420.31 kB # 所有页面 组件 Element PlusChrome DevTools 的 Lighthouse 跑一遍指标优化前FCP首屏内容绘制3.2sLCP最大内容绘制4.1sTTI可交互时间3.8s总 JS 体积1.42 MB总 CSS 体积398 KBLighthouse 评分65记下这组数据——每做完一个优化就重新跑一次看数字变化。性能优化最忌讳凭感觉一定要量化。二、路由懒加载首屏体积砍掉 60%这是效果最明显的一步。问题很简单目前的router/index.js是这样写的// ❌ 同步 import所有页面组件在首页就被打包进来了importApiRegistryfrom/views/api-manage/ApiRegistry.vueimportApiDetailfrom/views/api-manage/ApiDetail.vueimportModelHubfrom/views/model-hub/ModelHub.vueimportModelDetailfrom/views/model-hub/ModelDetail.vueimportPublishListfrom/views/model-publish/PublishList.vueimportPublishDetailfrom/views/model-publish/PublishDetail.vueimportLoginfrom/views/Login.vueconstroutes[{path:/,redirect:/api-manage/registry},{path:/,component:MainLayout,children:[{path:api-manage/registry,component:ApiRegistry},{path:api-manage/detail/:id,component:ApiDetail},{path:model-hub,component:ModelHub},{path:model-hub/detail/:id,component:ModelDetail},{path:model-publish,component:PublishList},{path:model-publish/detail/:id,component:PublishDetail},]},{path:/login,component:Login}]用户在首页/api-manage/registry但浏览器已经把模型汇聚、模型发布、登录页的代码全部下载了——这些页面用户根本没访问。2.1 改成动态 import// ✅ 动态 importVite 自动拆包访问时才加载constroutes[{path:/,redirect:/api-manage/registry},{path:/,component:MainLayout,children:[{path:api-manage/registry,component:()import(/views/api-manage/ApiRegistry.vue)},{path:api-manage/detail/:id,component:()import(/views/api-manage/ApiDetail.vue)},{path:model-hub,component:()import(/views/model-hub/ModelHub.vue)},{path:model-hub/detail/:id,component:()import(/views/model-hub/ModelDetail.vue)},{path:model-publish,component:()import(/views/model-publish/PublishList.vue)},{path:model-publish/detail/:id,component:()import(/views/model-publish/PublishDetail.vue)}]},{path:/login,component:()import(/views/Login.vue)}]这一改Vite 会在构建时把每个import()调用单独拆成一个 chunk。首屏只加载MainLayoutApiRegistry其他页面的代码在用户点击时才按需加载。2.2 魔法注释给 chunk 取个好名字默认的 chunk 名是数字 hash如3a2f1c.js调试时完全看不出谁是谁。加上魔法注释component:()import(/* webpackChunkName: api-registry *//views/api-manage/ApiRegistry.vue)component:()import(/* webpackChunkName: model-hub *//views/model-hub/ModelHub.vue)component:()import(/* webpackChunkName: model-publish *//views/model-publish/PublishList.vue)构建输出变成dist/assets/api-registry-3a2f1c.js 42 KB dist/assets/model-hub-b7e8d4.js 38 KB dist/assets/model-publish-9f1a3c.js 29 KB dist/assets/api-detail-5d2b8e.js 24 KB dist/assets/index-c8e1ff01.js 386 KB ← 只剩首屏需要的代码首屏 JS 从 1.42 MB 降到约 386 KB砍掉 73%。2.3 优化效果优化项变化首屏 JS1.42 MB → 0.39 MBFCP3.2s → 1.8s三、Element Plus 按需引入再砍 200KB目前项目是全局引入Element Plus// main.js — 全局引入importElementPlusfromelement-plusimportelement-plus/dist/index.cssapp.use(ElementPlus)这意味着即使你只用了el-table和el-button浏览器也要下载整个 Element Plus 库~800KB gzip 后 ~200KB。再加上 CSS 里的全部组件样式398KB加在一起就是 600KB 的冗余。3.1 安装按需引入插件pnpmadd-Dunplugin-vue-components unplugin-auto-import这两个插件分工明确unplugin-vue-components自动按需引入 Element Plus 组件你写el-button它自动import { ElButton } from element-plusunplugin-auto-import自动按需引入 Composition API你写ref、computed它自动import { ref, computed } from vue3.2 配置 vite.config.js// vite.config.jsimport{defineConfig}fromviteimportvuefromvitejs/plugin-vueimportAutoImportfromunplugin-auto-import/viteimportComponentsfromunplugin-vue-components/viteimport{ElementPlusResolver}fromunplugin-vue-components/resolversimport{fileURLToPath,URL}fromnode:urlexportdefaultdefineConfig({plugins:[vue(),AutoImport({resolvers:[ElementPlusResolver()],imports:[vue,vue-router,pinia],// 自动引入 ref/reactive/computed/useRouter/useStore 等dts:src/auto-imports.d.ts// 生成类型声明文件}),Components({resolvers:[ElementPlusResolver()],dts:src/components.d.ts// 生成组件类型声明文件})],resolve:{alias:{:fileURLToPath(newURL(./src,import.meta.url))}}})3.3 修改 main.js// main.js — 去掉全局引入import{createApp}fromvueimportAppfrom./App.vueimportrouterfrom./routerimportpiniafrom./storeimport./mockimport./styles/index.scssconstappcreateApp(App)app.use(pinia)app.use(router)// ❌ 删掉这行app.use(ElementPlus)app.mount(#app)现在你可以在任何.vue文件里直接写el-table、el-button、el-dialog插件会自动处理引入不需要手动 import。3.4 图标也要按需引入Element Plus 的图标库element-plus/icons-vue有 200 个图标全局引入也会增加包体积。正确的做法是按需引入// ❌ 全局引入打包进所有图标import*asElementPlusIconsVuefromelement-plus/icons-vuefor(const[key,component]ofObject.entries(ElementPlusIconsVue)){app.component(key,component)}// ✅ 按需引入只用到的图标才会打包import{Plus,Search,Edit,Delete,ArrowLeft}fromelement-plus/icons-vue// 在组件中使用el-button:iconPlus新增/el-button3.5 注意主题覆写的适配之前我们在第 04 篇用 SCSS 变量覆写了 Element Plus 主题。按需引入后SCSS 变量仍然生效——因为unplugin-vue-components只是控制 JS 组件的引入不干预 CSS。主题覆写是在styles/element-override.scss中定义通过vite.config.js的css.preprocessorOptions注入全局不受按需引入影响。// vite.config.js — 主题覆写配置保持不变css:{preprocessorOptions:{scss:{additionalData:use /styles/element-override.scss as *;}}}3.6 优化效果优化项变化Element Plus JS全量 → 按需省 ~200KB gzipElement Plus CSS398KB → ~60KB只含用到的组件样式图标全量 200 → 按需 8 个四、路由切换优化加个进度条和缓存4.1 NProgress让加载有反馈路由懒加载后首次访问模型汇聚页面会有 300~500ms 的加载时间。这段时间用户盯着白屏体验很差。加个进度条pnpmaddnprogresspnpmadd-Dtypes/nprogress// router/index.jsimportNProgressfromnprogressimportnprogress/nprogress.cssNProgress.configure({showSpinner:false,speed:400,minimum:0.2})router.beforeEach((to,from,next){NProgress.start()next()})router.afterEach((){NProgress.done()})页面顶部的蓝色进度条一闪而过用户知道正在加载不会误以为卡死了。4.2 KeepAlive不让状态白费模型汇聚的详情页有 3 个 Tab用户在接口参数 Tab 里编辑了几行数据切到模型文件 Tab 看了一眼再切回来——编辑的内容没了。!-- MainLayout.vue -- template div classmain-layout TopBar / div classlayout-body SideNav / div classcontent-area router-view v-slot{ Component } keep-alive :includecachedViews component :isComponent / /keep-alive /router-view /div /div /div /template script setup import { ref } from vue // 只缓存需要保持状态的页面 const cachedViews ref([ ModelHub, // 模型汇聚列表搜索条件保持 ApiRegistry, // API 注册列表筛选状态保持 ModelDetail // 模型详情Tab 状态保持 ]) /scriptinclude数组按组件name匹配。未在数组中的页面不会缓存切走即销毁不占内存。五、构建优化进一步缩小包体积5.1 拆 vendor chunkElement Plus 的el-table、el-form、el-dialog这些组件在多个页面中复用。默认情况下它们可能被打进每个页面的 chunk 里导致重复打包。用manualChunks把它们单独拆出来// vite.config.jsexportdefaultdefineConfig({build:{rollupOptions:{output:{manualChunks:{element-plus:[element-plus],// Element Plus 单独打包vue-vendor:[vue,vue-router,pinia]// Vue 全家桶单独打包}}}}})这样 Element Plus 的代码只会被打包一次所有页面共享一个element-plus-xxx.jschunk。浏览器第二次访问时直接用缓存不需要重新下载。5.2 可视化分析看看到底谁占了大头拆完还不放心用rollup-plugin-visualizer生成一张可视化图pnpmadd-Drollup-plugin-visualizer// vite.config.jsimport{visualizer}fromrollup-plugin-visualizerexportdefaultdefineConfig({plugins:[// ... 其他插件visualizer({open:true,// 构建完自动打开浏览器gzipSize:true,// 显示 gzip 后大小brotliSize:true// 显示 brotli 后大小})]})构建后自动打开stats.html一张树状图直观展示每个模块的体积占比。一眼能看到Element Plus 的表格组件最胖~80KBElement Plus 图表库占了 60KB其实我们没用图表mockjs 占了 45KB……5.3 排除未使用的依赖可视化分析暴露的第一个问题mockjs被打进生产包了。第 11 篇我们已经用import.meta.env.DEV做了环境判断但为了确保 tree-shaking 彻底生效再加一道保险// vite.config.jsexportdefaultdefineConfig({define:{__MOCK_ENABLED__:false// 生产环境关闭 Mock}})同时确保 mock 目录只在开发环境 import生产构建时 Vite 会直接把这部分代码从产物中剔除。六、最终效果用数据说话所有优化完成后再跑一次pnpm build和 Lighthouse指标优化前优化后提升FCP3.2s0.9s-72%LCP4.1s1.2s-71%TTI3.8s1.1s-71%首屏 JS1.42 MB0.21 MB-85%总 CSS398 KB62 KB-84%构建产物1.82 MB0.58 MB-68%Lighthouse659227 分6.1 各优化项的贡献优化项体积缩减FCP 改善路由懒加载~1 MB-1.4sElement Plus 按需引入~340 KB-0.5s图标按需引入~80 KB-0.1svendor chunk 拆分无直接缩减但后续访问 0 下载—mock 生产剔除~45 KB-0.1sNProgress无体积变化改善心理等待—路由懒加载贡献了最大的改进——它直接把 6 个页面的代码从首屏中移除。Element Plus 按需引入的效果也很显著CSS 从 398KB 降到 62KB节省了 84%。七、性能优化的铁律三条原则做完这轮优化沉淀三条原则1. 先量再优。优化前跑 Lighthouse /pnpm build记基线优化后跑了对比。没有数据你永远不知道优化够了没。2. 改动最小的优化往往收益最大。路由懒加载只改了路由定义10 行代码首屏体积砍了 73%。Element Plus 按需引入也只加了两个插件配置。真正的性能杀手通常是架构层面的问题不是某个函数慢了 3ms。3. 不要过度优化。Vite 本身的 tree-shaking 和按需加载已经做得很好别一上来就手写terser配置、自定义分包策略。先用工具层的默认优化不够再补。本项目这 5 个优化做完Lighthouse 92 分对于一个原型项目来说已经远超预期。上一篇11 - Mock 数据策略让原型看起来真实下一篇预告代码写完、性能达标最后一件事——怎么证明你还原了 Figma下一篇用 Playwright pixelmatch 做自动化像素对比把 Figma 截图和开发截图放到一起量化像素一致度。

相关新闻

二十位联系人六组字母:鸿蒙通讯录种子数据点亮每一格索引

二十位联系人六组字母:鸿蒙通讯录种子数据点亮每一格索引

实例:通讯录管理(Contacts) 20 条种子数据,覆盖 6 个字母分组,索引条和统计条都有内容一、种子数据设计思路 覆盖 6 个首字母组:A5、B2、C3、L4、W3、Z3姓名含常见姓氏(张/李/王/赵/周/刘/陈/杨…

2026/8/19 1:02:41 阅读更多 →
AI Agent技能开发实战:从零构建智能体工具链与自动化应用

AI Agent技能开发实战:从零构建智能体工具链与自动化应用

这次我们来看一个关于 Agent Skills 的实战教程资源。这个标题指向的是一套号称“最全最细”的 Agent Skills 实战教程,目标是帮助学习者快速入门并掌握相关技能。对于想进入 AI Agent 开发领域的人来说,最关心的不是概念有多复杂,而是有没有…

2026/8/24 15:59:17 阅读更多 →
基于Spring Boot与Milvus的RAG企业知识库实战搭建指南

基于Spring Boot与Milvus的RAG企业知识库实战搭建指南

在企业级应用开发中,如何让AI大模型精准地回答公司内部文档、产品手册、技术规范等私有知识,而不是“一本正经地胡说八道”,是许多开发者面临的共同挑战。传统的微调方案成本高昂、周期长,且难以应对知识的快速更新。此时&#xf…

2026/8/26 9:22:03 阅读更多 →

最新新闻

AI时代存储新范式:Agent Storage如何破解大模型训练的性能瓶颈

AI时代存储新范式:Agent Storage如何破解大模型训练的性能瓶颈

1. 从成本中心到性能引擎:Agent Storage的范式革命如果你最近在关注AI基础设施,尤其是大模型训练和推理的落地,大概率会听到一个词:“存储瓶颈”。这不再是老生常谈的IOPS(每秒输入输出操作次数)或带宽问题…

2026/8/26 9:21:21 阅读更多 →
AI时代存储架构革新:从成本中心到性能引擎的范式转移

AI时代存储架构革新:从成本中心到性能引擎的范式转移

1. 从“成本中心”到“性能引擎”:AI时代存储的范式转移如果你最近在关注AI项目的落地,尤其是那些涉及大模型训练、推理或者智能体(Agent)应用的项目,大概率会听到团队里这样的抱怨:“数据加载太慢了&#…

2026/8/26 9:21:21 阅读更多 →
苹果CMS视频网站搭建全攻略:从环境部署到采集上线

苹果CMS视频网站搭建全攻略:从环境部署到采集上线

简介:在Web开发与内容管理领域,CMS(内容管理系统)是快速构建信息型网站的核心工具。它通过将内容录入、模板渲染与数据存储分离,让开发者无需从零编码即可实现功能完备的站点。视频类网站对内容组织、播放展示和资源更…

2026/8/26 9:21:21 阅读更多 →
双DGX Spark实测:DeepSeek V4 Flash价格屠榜与本地部署指南

双DGX Spark实测:DeepSeek V4 Flash价格屠榜与本地部署指南

最近海外一位人工智能方向的博士研究者放出了一组很有意思的测试:用两台 NVIDIA DGX Spark 组成的本地集群,把 DeepSeek V4 Flash、Gemini 1.5 Flash、GLM-4-Plus 三个模型拉到同一环境里做横向对比。最终结论用标题来说就是四个字:价格屠榜。…

2026/8/26 9:21:21 阅读更多 →
从YOLOv8玉米识别数据集实践:目标检测标注与训练全流程解析

从YOLOv8玉米识别数据集实践:目标检测标注与训练全流程解析

简介:目标检测是计算机视觉的核心任务之一,其效果高度依赖数据质量与训练策略。在农业场景中,玉米识别等细粒度检测对模型鲁棒性提出更高要求。构建高质量数据集不仅是简单收集图片,还需经过筛选、标注、质检与合理划分&#xff0…

2026/8/26 9:21:19 阅读更多 →
Java Set集合深度解析:HashSet、TreeSet与LinkedHashSet核心原理与实战选型

Java Set集合深度解析:HashSet、TreeSet与LinkedHashSet核心原理与实战选型

1. 项目概述:为什么Set是Java集合框架的“独行侠”?在Java的集合框架里,List、Map、Set三足鼎立,各自扮演着不同的角色。如果说List像一个有序的队列,允许你按号入座,Map像一个高效的字典,让你通…

2026/8/26 9:20:16 阅读更多 →

日新闻

Python random 模块常用函数详解:从入门到实战

Python random 模块常用函数详解:从入门到实战

目录 1. 引言2. 准备工作3. 基础随机函数4. 序列相关函数5. 随机种子与复现6. 实战案例7. 注意事项8. 常见问题与排查9. 总结 1. 引言 摘要: 本文系统介绍 Python 标准库 random 模块中最常用的随机数生成函数。内容涵盖基础随机函数(random()、unifor…

2026/8/26 0:00:40 阅读更多 →
《Microsoft Sql server 2008 Internals》读书笔记--第三章Databases and Database Files(2)

《Microsoft Sql server 2008 Internals》读书笔记--第三章Databases and Database Files(2)

《Microsoft Sql server 2008 Internals》索引目录: 《Microsoft Sql server 2008 Internals》读书笔记--目录索引 在上篇文章中,主要介绍了创建数据库的基本语法和FileGroup的初步知识。需要注意的是: 关于FileGroup 如果你的系统是用Raid设备直接存…

2026/8/26 1:18:18 阅读更多 →
政务AI智能体怎么建?三种模式、三步路径与四个误区

政务AI智能体怎么建?三种模式、三步路径与四个误区

政务AI智能体已经从概念试点阶段,转入了政务服务的常态化落地应用;在实际使用过程中,它能自主理解办事需求、辅助完成填报申报、开展材料预审,并联动多个系统协同作业,真正嵌入到政务办理的全流程当中。但在落地推进过…

2026/8/26 1:18:18 阅读更多 →

周新闻

[光学原理与应用-521]:对光的错误理解与纠偏

[光学原理与应用-521]:对光的错误理解与纠偏

首先光是一种能量的载体和形态,宏观上观察到的光是由无数个微观的光量子组成的,每个光子在产生的瞬间,其在真空的空间中以确定不变的速度沿着一个初始的方向一直向前,在微观层面,每个光量子的运动轨迹是以波函数所展现…

2026/8/25 3:38:12 阅读更多 →
SIP通话转接原理与REFER方法实战解析

SIP通话转接原理与REFER方法实战解析

1. 通话转接不是“挂断再拨号”,而是SIP会话的动态重定向你有没有遇到过这样的场景:客服坐席A正在和客户通电话,突然需要把这通对话无缝转给专家坐席B,客户完全感知不到中间的断连——既没听到忙音,也没被要求重新拨号…

2026/8/25 3:38:18 阅读更多 →
Kolla-ansible单节点OpenStack部署实战:从环境准备到排坑指南

Kolla-ansible单节点OpenStack部署实战:从环境准备到排坑指南

1. 为什么选择Kolla-ansible来部署单节点OpenStack?如果你正在寻找一种能把OpenStack从“概念”快速变成“可用的实验环境”的方法,那么Kolla-ansible几乎是当前最主流、最省心的选择。我见过太多人卡在手动编译依赖、配置服务、处理版本冲突的泥潭里&am…

2026/8/25 3:38:23 阅读更多 →

月新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/26 3:50:20 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗?ncmdump解密工具帮你轻松解决这个困…

2026/8/25 10:31:12 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片:为英语学习 App 打造桌面级学习助手适用平台:HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0(API 26 Beta)新增了 AgentCard 智能体卡片能力,这是继 HMAF(鸿蒙智能体框架&#x…

2026/8/26 1:24:05 阅读更多 →