Vue 中的工程化设计
Vue 中有很多优秀的工程化设计,有很多是可以应用到日常开发中的,下面盘点一下 Vue 中的工程化设计有哪些可以学习的思想和技巧。
一、分层架构与依赖治理
用物理边界约束架构,防止代码腐化
Vue 具体做法
| 实践 | 具体做法 | 可借鉴点 |
|---|---|---|
| 单向依赖图 | 编译器 → 共享包 ← 运行时,二者互不引用 | 数据流单向流动 |
| 共享包收敛 | 所有跨包工具收敛到 @vue/shared | 禁止同层级相互引用 |
| 私有包隔离 | packages-private/ 物理隔离 | 防止误发布 |
前端项目三层划分
┌─────────────────────────────────────┐
│ 视图层 (UI Layer) │ 页面组件、通用组件
├─────────────────────────────────────┤
│ 业务层 (Business Layer) │ 状态管理、业务逻辑
├─────────────────────────────────────┤
│ 基础层 (Infrastructure Layer) │ 工具函数、API 封装、类型定义
└─────────────────────────────────────┘
依赖规则:上层可引用下层,下层禁止引用上层,禁止同层级相互引用。
工程实现示例
eslint-plugin-import/no-restricted-paths 限制跨包引用:
module.exports = {
rules: {
'import/no-restricted-paths': [{
map: [
// 禁止 ui-components 导入业务逻辑
{ target: 'packages/ui-components', from: 'packages/business-logic' },
// 禁止业务包直接引用平台层
{ target: 'packages/platform', from: 'packages/*' },
],
base: process.cwd(),
}],
},
};
二、条件编译与环境标志
Vue 中使用了较多环境变量控制分支代码:__DEV__、__TEST__、__SSR__。
使用环境变量隔离开发、测试和生产代码,避免将不必要的代码打包到生产环境。
Vue 实现
通过 esbuild define 选项在构建时替换,核心环境变量包括 __DEV__、__SSR__、__TEST__(见 rollup.config.js:170-218)。条件分支在编译后彻底消失。
前端项目实践
Vite 项目中,环境变量通过 .env 文件定义:
# .env.development
VITE_API_BASE_URL=http://localhost:3000
VITE_ENABLE_MOCK=true
# .env.production
VITE_API_BASE_URL=https://api.example.com
VITE_ENABLE_MOCK=false
在代码中使用:
// 根据环境决定是否启用 Mock
if (import.meta.env.VITE_ENABLE_MOCK) {
import('./mock').then(({ setupMock }) => setupMock());
}
// 移除日志(生产环境自动清空)
if (import.meta.env.DEV) {
console.log('Debug info:', data);
}
配合 rollup-plugin-visualizer 可视化产物大小,确保无用代码被彻底清除。
三、平台无关的测试策略
核心思想:测试粒度与运行时环境解耦
Vue 三层测试设计
| 层级 | 环境 | 测什么 | 速度 |
|---|---|---|---|
| 单元测试 | Node | 逻辑、算法、编译器 | 最快 |
| 单元测试 | jsdom | DOM 操作、事件 | 中等 |
| E2E | Puppeteer | 真实浏览器行为 | 最慢 |
自建 runtime-test 包:用纯 JS 对象模拟 DOM,让 VDOM 相关测试不依赖任何浏览器环境。
前端项目实践
Vitest 统一测试框架:
// vitest.config.ts
import { defineConfig } from 'vitest/config'
export default defineConfig({
test: {
environment: 'jsdom',
globals: true,
},
})
分层测试示例:
// 纯逻辑测试(Node 环境,最快)
describe('useOrderList', () => {
it('should filter by status', () => {
const { filteredOrders } = useOrderList({ status: 'pending' });
expect(filteredOrders.value).toHaveLength(3);
});
});
// 组件测试(jsdom,测试 DOM 交互)
import { mount } from '@vue/test-utils'
describe('OrderList.vue', () => {
it('should emit select event', async () => {
const wrapper = mount(OrderList);
await wrapper.find('.order-item').trigger('click');
expect(wrapper.emitted('select')).toBeTruthy();
});
});
关键原则:测试下沉(能用 Node 就不走 jsdom)、80/20 法则(80% 单元测试,E2E 只覆盖核心流程)。
runtime-test 核心原理
const node = {
nodeType: 1,
tagName: 'DIV',
children: [],
props: {},
eventListeners: {},
};
function createElement(tag, props, children) {
return { nodeType: 1, tagName: tag, props, children };
}
function patch(old, new) {
// 简单的 vdom diff 逻辑
}
这样 VDOM 的 mount、patch 等逻辑完全可以在 Node 环境中测试,不依赖 JSDOM 或 Puppeteer。
四、代码规范约束
Vue 的 ESLint 配置不是"建议",而是编译时强制执行。
前端项目实践
1. pre-commit Hook
pnpm add -D husky lint-staged
{
"lint-staged": {
"*.{ts,vue}": ["eslint --fix", "git add"]
}
}
npx husky add .husky/pre-commit "npx lint-staged"
2. CI 强制检查
# .github/workflows/lint.yml
name: Lint
on: [push, pull_request]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: pnpm install
- run: pnpm lint
3. Vite 构建时强制检查
// vite.config.ts
import eslint from 'vite-plugin-eslint2'
export default defineConfig({
plugins: [
eslint({
failOnWarning: true,
}),
],
})
4. 最佳实践链路
编辑器(提示) → pre-commit(兜底) → CI(强制)
- 编辑器:VSCode + ESLint 插件,实时提示
- pre-commit:lint-staged 只检查暂存区,快速反馈
- CI:最终防线,无法绕过
五、Commit 规范与自动流水线
Angular Commit Convention 在 Vue 中的价值不仅是"提交好看":
feat(compiler): add template optimization
fix(reactivity): patch array mutation tracking
衍生的工程能力
- 自动生成 CHANGELOG:按 feat/fix/perf 分类,版本发布零人工整理
- 语义化版本推断:feat → minor,fix → patch,breaking → major,减少人为判断失误
- CI 条件执行:通过 scope 判断只跑受影响包的测试(Monorepo 可借此优化)
前端项目实践
1. Commit 规范
格式:type(scope): subject,用正则校验:
// scripts/verify-commit.js
const commitRE = /^(revert: )?(feat|fix|docs|dx|style|refactor|perf|test|workflow|build|ci|chore|types|wip)(\(.+\))?: .{1,50}/
if (!commitRE.test(msg)) {
console.error('invalid commit message format');
process.exit(1);
}
# .husky/commit-msg
node scripts/verify-commit.js
2. 自动流水线
核心流程:pnpm release → 选择版本 → 更新版本号 → 生成 CHANGELOG → git commit/tag/push → CI 触发
详细配置见:自动流水线配置指南.md
3. 语义化版本
feat(xxx):→ minor 版本fix(xxx):→ patch 版本BREAKING CHANGE:→ major 版本
打标签发布:git tag v1.2.0 && git push
总结:在自己项目中最值得考虑的 3 件事
- 画好"地图":明确每个包/目录的职责和依赖方向,用 ESLint 的 import/no-restricted-paths 或自定义规则强制执行
- 测试分层守护:从单元测试(Node)→ 组件测试(jsdom)→ E2E(浏览器),按速度由快到慢、覆盖范围由小到大递进,CI 中分层执行,PR 阶段只跑必要测试
- 规范焊死在工具链:能自动化的不要靠人记,能编译时拦截的不要留到运行时