Vue 3项目工程化:从代码规范到CI/CD部署全流程指南

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项目将具备企业级的代码质量保障、高效的开发体验和可靠的自动化部署流程。建议根据项目实际需求调整配置,并持续关注前端工程化领域的新工具和最佳实践。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值