从测试转开发三年后,我用 Vue.js 拯救了团队的“祖传屎山”项目
去年双11前夕,我们组接了个大活——重构公司内部那个用了快五年的后台管理系统。说“重构”,其实大家心里都清楚:这玩意儿早就是个缝缝补补的“祖传屎山”了,前端还是 jQuery + Bootstrap 的混合体,每次改个按钮样式都能触发三个未知 Bug。产品经理拍着胸脯说:“这次一定要现代化!” 领导点头:“用 Vue 吧,生态好,上手快。”
我,一个从测试转开发刚满三年的“半路出家选手”,默默打开了 GitHub,心想:行吧,反正跳槽简历里得有点像样的项目,不如趁机搞点硬核的。
背景:为什么非得是 Vue?
其实一开始我是抗拒的。毕竟我最近在狂刷 LeetCode 准备跳槽,晚上还得啃《动手学深度学习》想蹭点 AI 热度,哪有空折腾前端?但现实很骨感——我们团队只有两个人会写前端,另一个还在休产假。运维老哥听说要用 Vue,冷笑一声:“上次你们 npm install 卡了半小时,害我重启 CI/CD 流水线。” 我只能苦笑:谁让咱是从测试转过来的呢,连 node_modules 删起来都比别人狠(毕竟以前天天删日志)。
但说实话,Vue 的确是个合理选择。我们的系统用户主要是内部运营和客服,对兼容性要求不高(Chrome 最新版就行),但对交互流畅度和开发效率要求高。而且——别笑——Vue 的文档真的太友好了!对比隔壁 React 的“你先去学 JSX、Hooks、Context、Suspense……”,Vue 的渐进式上手简直像给新手开了个 VIP 通道。
实战:从零搭建一个“不翻车”的 Vue 项目
第一步:别直接 vue create,先看 GitHub 上的大佬怎么玩
我可没傻到自己从零配置。打开 GitHub,搜 “vue enterprise boilerplate”,立马找到 vue-enterprise-boilerplate(注:真实存在,由 Chris Fritz 维护,Vue 官方成员)。这个仓库简直就是企业级项目的模板教科书:TypeScript + Pinia + Vue Router + ESLint + Prettier + Vitest + Cypress,全齐了。
我直接 fork 了一份,删掉不需要的示例代码,保留核心架构。重点来了:很多教程只教你怎么跑起来,但没人告诉你生产环境怎么部署、怎么监控错误、怎么做性能优化。这个 boilerplate 里连 Sentry 错误上报和 Lighthouse CI 都配好了,感动到想给作者发红包。
# 我们的初始化命令(省略一万句脏话)
git clone https://github.com/yourname/vue-enterprise-boilerplate.git internal-dashboard
cd internal-dashboard
pnpm install # 别问为什么用 pnpm,问就是 node_modules 太占 SSD
第二步:状态管理?别一上来就 Vuex!
很多人一听到“状态管理”就条件反射想到 Vuex。但兄弟,Vuex 已经进入维护模式了!现在官方主推的是 Pinia——轻量、TypeScript 友好、没有 mutations 那套反人类设计。
我们有个需求:全局用户信息要在多个组件里用,比如头像、权限、部门。用 Pinia 写起来简直丝滑:
// stores/user.ts
import { defineStore } from 'pinia'
export const useUserStore = defineStore('user', {
state: () => ({
name: '',
avatar: '',
permissions: [] as string[]
}),
actions: {
async fetchUserInfo() {
const res = await api.getUser()
this.name = res.name
this.avatar = res.avatar
this.permissions = res.permissions
}
}
})
在组件里直接 const userStore = useUserStore(),不用 mapState、mapActions 那一套,清爽得像喝了冰阔落。
第三步:组件库选型——别被 UI 框架绑架
我们试过 Element Plus,也试过 Naive UI。最后选了 Naive UI,原因很现实:它支持按需引入、暗色主题开箱即用、TypeScript 类型定义完整,而且文档里每个组件都有 Playground(在线编辑器),改个颜色不用重启 dev server。
但最大的坑来了:国际化。我们系统要支持中英文切换。Element Plus 的 i18n 配置复杂得像在解微分方程,而 Naive UI 只需一行:
import { createDiscreteApi } from 'naive-ui'
const { message, dialog } = createDiscreteApi(['message', 'dialog'])
// 然后在 app.use 里注入 locale
不过吐槽一句:产品经理临时加需求说要加日语支持,我差点把键盘扔了——但 Naive UI 真的只改一个 JSON 文件就搞定了,服气。
性能优化:让用户不再骂“这页面怎么又卡了”
上线前一周,QA 同事(没错,就是我以前的同行)提了个 Bug:“列表页滚动卡成 PPT”。我打开 Performance 面板一看,好家伙,每次滚动都在触发 50+ 次 re-render,因为每个列表项都绑定了复杂的计算属性。
解决方案:
- 虚拟滚动:用
vue-virtual-scroller,3000 条数据秒开。 - 计算属性缓存:把频繁调用的逻辑移到
computed,避免重复计算。 - 懒加载图片:
<img v-lazy="src">+ Intersection Observer。
最骚的操作是:我把所有 icon 换成了 SVG Sprite,首屏加载时间从 2.3s 降到 0.9s。运维老哥看到 Lighthouse 分数从 45 飙到 92,居然请我喝了杯瑞幸——虽然他说是因为“终于不用半夜被报警电话吵醒”。
调试技巧:那些年我踩过的坑
- 热更新失效?十有八九是
vite.config.ts里的resolve.alias配错了。建议用绝对路径@/components而不是相对路径。 - Pinia 数据不响应?检查是不是直接赋值了对象属性(如
user.name = 'xxx'),应该用$patch或整个替换 state。 - 生产环境白屏?99% 是路由守卫没处理异步逻辑。记住:
router.beforeEach里必须 return Promise 或调用 next()。
有一次我在周五晚上加班改一个权限 Bug,死活复现不了。最后发现是本地 mock 数据和线上接口字段不一致——测试出身的我居然栽在这种低级错误上,脸都绿了。从此以后,我写 API 接口必先定义 TypeScript interface,并用 Zod 做运行时校验。
效果与反思:从“能用”到“好用”
项目上线后,内部用户反馈“终于不像上个世纪的系统了”。更重要的是,开发效率提升明显:以前加个表单要两天(还要联调后端),现在用 Vue + Naive UI 的 Form 组件,半天搞定。
下表是我们重构前后的关键指标对比:
| 指标 | 重构前 | 重构后 | 提升 |
|---|---|---|---|
| 首屏加载时间 | 2.3s | 0.9s | 61% ↓ |
| Bundle 体积 | 3.2MB | 1.1MB | 66% ↓ |
| 新功能平均开发周期 | 3天 | 1.2天 | 60% ↓ |
| 生产环境 JS 错误率 | 8.7% | 0.3% | 97% ↓ |
当然,也有教训:不要过度工程化。一开始我试图把所有逻辑拆成 composable,结果新人看了直摇头。后来简化了架构,核心原则就一条:业务复杂度决定技术复杂度。
写在最后:一个“转行仔”的真心话
作为从测试转开发的人,我比纯开发更在意“可维护性”和“可观测性”。Vue 的生态系统之所以强大,不只是因为语法糖,而是它围绕“开发者体验”构建了一整套工具链——从 Vite 的极速启动,到 Vue DevTools 的组件 inspect,再到 Vitest 的快如闪电的单元测试。
最近我在 GitHub 上 star 了一个叫 vueuse 的项目,里面全是实用的 Composition API 工具函数,比如 useStorage、useMouse,拿来即用。这种开源精神让我觉得,即使我只是个小厂程序员,也能站在巨人的肩膀上写出不那么烂的代码。
如果你也在准备跳槽,或者正被老旧项目折磨,不妨试试用 Vue 重构一小块功能。别怕踩坑——毕竟,我当年连 npm 和 yarn 都分不清,现在不也能在简历上写“主导 Vue 3 全栈项目”了嘛(笑)。
对了,本文提到的所有项目和教程,我都整理到了我的 GitHub 主页(ID: ex-tester-dev),欢迎 Star & Fork。顺便,有内推机会的老板也可以私信我,LeetCode 刷到 300 题了,Vue 项目 ready to ship,AI 还在学,但 promise resolve 得很快 😉

评论 0