Vue 3项目工程化:从代码规范到CI/CD部署全流程指南
一、项目初始化与工程化配置
1. 现代化项目脚手架搭建
使用Vite初始化项目:
npm create vite@latest vue3-project --template vue-ts
cd vue3-project
npm install
推荐基础依赖:
npm install -D eslint prettier eslint-plugin-vue @typescript-eslint/parser @typescript-eslint/eslint-plugin husky lint-staged stylelint stylelint-config-standard
2. 工程化配置文件结构
vue3-project/
├── .vscode/ # VSCode工作区配置
│ ├── settings.json # 编辑器统一配置
│ └── extensions.json # 推荐插件
├── .husky/ # Git钩子
│ ├── pre-commit # 提交前钩子
│ └── commit-msg # 提交信息校验
├── config/ # 构建配置
│ ├── vite/ # Vite环境配置
│ └── jest/ # 测试配置
└── .eslintrc.js # ESLint配置
└── .prettierrc.js # Prettier配置
└── stylelint.config.js # Stylelint配置
└── tsconfig.json # TypeScript配置
└── vite.config.ts # Vite主配置
二、代码规范与质量保障
1. ESLint + Prettier配置
.eslintrc.js:
module.exports = {
root: true,
env: {
node: true,
browser: true,
es2021: true
},
extends: [
'eslint:recommended',
'plugin:vue/vue3-recommended',
'@vue/typescript/recommended',
'plugin:prettier/recommended'
],
parserOptions: {
ecmaVersion: 2021
},
rules: {
'vue/multi-word-component-names': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'vue/component-tags-order': ['error', {
order: ['template', 'script', 'style']
}],
'vue/attribute-hyphenation': ['error', 'always']
}
}
.prettierrc.js:
module.exports = {
printWidth: 100,
tabWidth: 2,
useTabs: false,
semi: false,
singleQuote: true,
quoteProps: 'as-needed',
jsxSingleQuote: false,
trailingComma: 'none',
bracketSpacing: true,
bracketSameLine: false,
arrowParens: 'always',
endOfLine: 'lf'
}
2. Stylelint样式规范
stylelint.config.js:
module.exports = {
extends: ['stylelint-config-standard', 'stylelint-config-prettier'],
rules: {
'selector-class-pattern': null,
'no-descending-specificity': null,
'value-no-vendor-prefix': null,
'property-no-vendor-prefix': null,
'at-rule-no-unknown': [
true,
{
ignoreAtRules: ['tailwind', 'apply', 'variants', 'responsive', 'screen']
}
]
}
}
3. Git提交规范
Commitizen配置:
npm install -D commitizen cz-conventional-changelog
package.json:
{
"scripts": {
"commit": "cz"
},
"config": {
"commitizen": {
"path": "./node_modules/cz-conventional-changelog"
}
}
}
commitlint配置:
npm install -D @commitlint/cli @commitlint/config-conventional
.commitlintrc.js:
module.exports = {
extends: ['@commitlint/config-conventional'],
rules: {
'type-enum': [
2,
'always',
['feat', 'fix', 'docs', 'style', 'refactor', 'test', 'chore', 'revert']
],
'subject-case': [0]
}
}
三、自动化测试体系
1. 测试工具链配置
安装测试依赖:
npm install -D vitest @vue/test-utils happy-dom @vitest/coverage-v8
vite.config.ts:
/// <reference types="vitest" />
import { defineConfig } from 'vite'
export default defineConfig({
test: {
globals: true,
environment: 'happy-dom',
coverage: {
provider: 'v8',
reporter: ['text', 'json', 'html'],
include: ['src/**/*.{ts,vue}']
}
}
})
2. 单元测试示例
组件测试:
// tests/components/Button.spec.ts
import { mount } from '@vue/test-utils'
import Button from '@/components/Button.vue'
describe('Button Component', () => {
it('renders button text', () => {
const wrapper = mount(Button, {
props: {
text: 'Click me'
}
})
expect(wrapper.text()).toContain('Click me')
})
it('emits click event', async () => {
const wrapper = mount(Button)
await wrapper.trigger('click')
expect(wrapper.emitted()).toHaveProperty('click')
})
})
Composable测试:
// tests/composables/useCounter.spec.ts
import { renderHook } from '@testing-library/vue'
import { useCounter } from '@/composables/useCounter'
describe('useCounter', () => {
it('should increment count', () => {
const { result } = renderHook(() => useCounter(0))
expect(result.current.count.value).toBe(0)
result.current.increment()
expect(result.current.count.value).toBe(1)
})
})
3. E2E测试方案
Cypress安装:
npm install -D cypress @cypress/vite-dev-server
cypress.config.ts:
import { defineConfig } from 'cypress'
import viteConfig from './vite.config'
export default defineConfig({
component: {
devServer: {
framework: 'vue',
bundler: 'vite',
viteConfig: viteConfig
}
},
e2e: {
baseUrl: 'http://localhost:5173',
setupNodeEvents(on, config) {
// 实现节点事件监听器
}
}
})
四、构建优化策略
1. Vite高级配置
vite.config.ts优化:
import { defineConfig, splitVendorChunkPlugin } from 'vite'
import { visualizer } from 'rollup-plugin-visualizer'
export default defineConfig({
plugins: [
splitVendorChunkPlugin(),
visualizer({
open: true,
gzipSize: true,
brotliSize: true
})
],
build: {
rollupOptions: {
output: {
manualChunks: {
vue: ['vue', 'vue-router', 'pinia'],
element: ['element-plus'],
vendor: ['lodash', 'axios']
},
chunkFileNames: 'assets/js/[name]-[hash].js',
entryFileNames: 'assets/js/[name]-[hash].js',
assetFileNames: 'assets/[ext]/[name]-[hash].[ext]'
}
}
}
})
2. 性能优化插件
推荐插件集合:
npm install -D @vitejs/plugin-legacy vite-plugin-compression vite-plugin-imagemin vite-plugin-pwa
配置示例:
import legacy from '@vitejs/plugin-legacy'
import viteCompression from 'vite-plugin-compression'
import { imagemin } from 'vite-plugin-imagemin'
export default defineConfig({
plugins: [
legacy({
targets: ['defaults', 'not IE 11']
}),
viteCompression({
algorithm: 'gzip',
threshold: 10240 // 10KB以上压缩
}),
imagemin({
gifsicle: { optimizationLevel: 3 },
mozjpeg: { quality: 80 },
pngquant: { quality: [0.8, 0.9] },
svgo: {
plugins: [
{ name: 'removeViewBox' },
{ name: 'removeEmptyAttrs', active: false }
]
}
})
]
})
五、CI/CD自动化部署
1. GitHub Actions工作流
.github/workflows/ci-cd.yml:
name: CI/CD Pipeline
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 18
- run: npm ci
- run: npm run test:unit
- run: npm run test:e2e
- uses: codecov/codecov-action@v3
with:
token: ${{ secrets.CODECOV_TOKEN }}
build:
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 18
- run: npm ci
- run: npm run build
- uses: actions/upload-artifact@v3
with:
name: dist
path: dist
deploy:
needs: build
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/download-artifact@v3
with:
name: dist
- uses: azure/webapps-deploy@v2
with:
app-name: 'vue3-app'
publish-profile: ${{ secrets.AZURE_PUBLISH_PROFILE }}
package: ./dist
2. Docker多阶段构建
Dockerfile:
# 构建阶段
FROM node:18-alpine as builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# 生产阶段
FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
nginx.conf:
server {
listen 80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html;
try_files $uri $uri/ /index.html;
}
gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
}
六、监控与维护
1. 性能监控接入
Sentry配置:
// src/utils/monitoring.ts
import * as Sentry from '@sentry/vue'
import { BrowserTracing } from '@sentry/tracing'
export function initMonitoring(app: App) {
Sentry.init({
app,
dsn: process.env.VITE_SENTRY_DSN,
integrations: [
new BrowserTracing({
routingInstrumentation: Sentry.vueRouterInstrumentation(router),
tracingOrigins: ['localhost', 'your-domain.com']
})
],
tracesSampleRate: 1.0,
environment: process.env.NODE_ENV
})
}
2. 错误边界组件
<script setup lang="ts">
import { onErrorCaptured, ref } from 'vue'
import { captureException } from '@sentry/vue'
const error = ref<Error | null>(null)
const errorInfo = ref<any>(null)
onErrorCaptured((err, vm, info) => {
error.value = err
errorInfo.value = info
captureException(err, { extra: { component: vm.$options.name, info } })
return false // 阻止错误继续向上传播
})
</script>
<template>
<slot v-if="!error"></slot>
<div v-else class="error-boundary">
<h2>Something went wrong</h2>
<button @click="error = null">Try again</button>
</div>
</template>
七、进阶工程化实践
1. 微前端集成方案
基于qiankun的配置:
// 主应用
import { registerMicroApps, start } from 'qiankun'
registerMicroApps([
{
name: 'vue3-subapp',
entry: '//localhost:7101',
container: '#subapp-container',
activeRule: '/subapp'
}
])
start()
// 子应用适配
if (window.__POWERED_BY_QIANKUN__) {
__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__
}
2. 模块联邦配置
vite.config.ts:
import { defineConfig } from 'vite'
import federation from '@originjs/vite-plugin-federation'
export default defineConfig({
plugins: [
federation({
name: 'host-app',
remotes: {
remote_app: 'http://localhost:5001/assets/remoteEntry.js'
},
shared: ['vue', 'pinia']
})
],
build: {
target: 'esnext',
minify: false,
cssCodeSplit: false
}
})
八、项目文档自动化
1. TypeDoc文档生成
配置typedoc:
npm install -D typedoc typedoc-plugin-markdown
typedoc.json:
{
"entryPoints": ["src/main.ts"],
"out": "docs/api",
"plugin": ["typedoc-plugin-markdown"],
"excludeExternals": true,
"excludePrivate": true,
"hideGenerator": true
}
2. 组件文档生成
使用Vitepress:
npm install -D vitepress vue-docgen-cli
文档生成脚本:
{
"scripts": {
"docs:dev": "vitepress dev docs",
"docs:build": "vitepress build docs",
"docs:generate": "vue-docgen -c ./docgen.config.js"
}
}
通过这套完整的工程化方案,您的Vue 3项目将具备企业级的代码质量保障、高效的开发体验和可靠的自动化部署流程。建议根据项目实际需求调整配置,并持续关注前端工程化领域的新工具和最佳实践。