Skip to content

Vue3 代码风格工具集成

作者:Atom
字数统计:3.4k 字
阅读时长:15 分钟

目录

  1. 前言
  2. 包管理器选择
  3. 代码质量工具配置
  4. Git工作流规范
  5. 编辑器配置
  6. TypeScript配置
  7. 项目文档
  8. 最佳实践建议
  9. 完整配置文件示例

前言

规范化的前端项目不仅能够提高代码质量,还能显著提升团队协作效率。本文将详细介绍如何基于Vue 3搭建一套完整的项目规范,涵盖代码风格、提交规范、编辑器配置等各个方面,团队可以直接参考并应用到自己的项目中。

包管理器选择

本项目统一使用pnpm作为包管理工具,推荐最新版本为10.12.14。

bash
# 安装pnpm
npm install -g pnpm

# 创建项目
pnpm create vue@latest my-project
cd my-project

# 安装依赖
pnpm install

在项目根目录创建.npmrc文件,配置npm镜像源:

sh
registry=https://registry.npmmirror.com
strict-peer-dependencies=false

代码质量工具配置

ESLint配置

ESLint@9采用了新的扁平化配置方式,我们使用eslint.config.mjs文件进行配置。

首先安装相关依赖:

bash
pnpm add -D eslint @eslint/js globals eslint-config-prettier eslint-plugin-import-x eslint-plugin-prettier eslint-plugin-vue typescript-eslint

创建eslint.config.mjs文件:

javascript
import js from '@eslint/js'
import globals from 'globals'
import eslintConfigPrettier from 'eslint-config-prettier'
import eslintPluginImportX from 'eslint-plugin-import-x'
import eslintPluginPrettier from 'eslint-plugin-prettier/recommended'
import eslintPluginVue from 'eslint-plugin-vue'
import typescriptEslint from 'typescript-eslint'
import { readFileSync } from 'node:fs'

// 导入自动导入的ESLint配置
const eslintrcAutoImport = JSON.parse(readFileSync(new URL('./.eslintrc-auto-import.json', import.meta.url)))

// TypeScript ESLint配置
const tsEslint = typescriptEslint.config(...typescriptEslint.configs.recommended).map((config) => ({
  ...config,
  languageOptions: {
    ...config.languageOptions,
    parserOptions: {
      parser: '@typescript-eslint/parser'
    }
  }
}))

// Vue ESLint配置
const vueEslint = eslintPluginVue.configs['flat/recommended']

// 忽略的文件
const ignores = ['node_modules/', 'dist/', 'public/', 'src/assets/', '*.d.ts', '*.jpg', '*.jpeg', '*.png', '*.gif']

// 通用全局变量
const commonGlobals = { ...globals.browser, ...globals.node }

export default [
  {
    ignores,
    plugins: {
      'import-x': eslintPluginImportX
    },
    languageOptions: {
      globals: commonGlobals
    }
  },
  ...tsEslint,
  ...vueEslint,
  js.configs.recommended,
  {
    ...eslintPluginPrettier,
    rules: {
      ...eslintPluginPrettier.rules,
      ...eslintConfigPrettier.rules
    }
  },
  {
    files: ['src/**/*.{js,ts,jsx,tsx,vue}'],
    rules: {
      // Vue相关规则
      'vue/v-on-event-hyphenation': [
        'warn',
        'always',
        {
          autofix: true
        }
      ],
      'vue/html-self-closing': [
        'warn',
        {
          html: {
            void: 'any',
            normal: 'always',
            component: 'always'
          },
          svg: 'always',
          math: 'always'
        }
      ],
      'vue/attribute-hyphenation': 'off',
      'vue/singleline-html-element-content-newline': 'off',
      'vue/multi-word-component-names': 'off',

      // TypeScript规则
      '@typescript-eslint/no-explicit-any': 'warn',
      '@typescript-eslint/no-unused-vars': 'warn',
      '@typescript-eslint/no-unused-expressions': ['error', { allowShortCircuit: true, allowTernary: true }],

      // 通用规则
      'array-callback-return': 'error',
      'sort-imports': 'off',

      // 导入规则
      'import-x/order': [
        'error',
        {
          groups: ['external', 'builtin', 'internal', 'type', 'parent', 'object', 'sibling', 'index']
        }
      ],
      'import-x/no-cycle': 'error',
      'import-x/no-self-import': 'error',

      // 异步规则
      'no-async-promise-executor': 'warn',

      // Vue组件规则
      'vue/component-options-name-casing': ['warn', 'PascalCase'],
      'vue/component-name-in-template-casing': [
        'warn',
        'PascalCase',
        {
          registeredComponentsOnly: false,
          ignores: []
        }
      ],
      'vue/component-api-style': ['error', ['script-setup', 'composition']],
      'vue/define-macros-order': ['error', { order: ['defineOptions', 'defineProps', 'defineEmits', 'defineSlots'] }],
      'vue/custom-event-name-casing': [
        'warn',
        'kebab-case',
        {
          ignores: []
        }
      ],
      'vue/define-emits-declaration': ['warn', 'type-based'],
      'vue/define-props-declaration': ['warn', 'type-based'],
      'vue/slot-name-casing': ['warn', 'camelCase']
    },
    languageOptions: {
      ecmaVersion: 'latest',
      sourceType: 'module',
      parserOptions: {
        parser: typescriptEslint.parser,
        ecmaFeatures: {
          jsx: true
        }
      },
      ...eslintrcAutoImport // 合并自动导入的全局变量
    }
  }
]

Prettier配置

安装Prettier相关依赖:

bash
pnpm add -D prettier eslint-plugin-prettier eslint-config-prettier

创建.prettierrc.js文件:

javascript
export default {
  printWidth: 120, // 一行的字符数,超过会自动换行
  singleAttributePerLine: false, // 每行强制换行,只能使用单个属性
  tabWidth: 2, // 一个tab代表几个空格
  useTabs: false, // 是否使用tab进行缩进
  singleQuote: true, // 使用单引号而非双引号
  semi: false, // 行尾不使用分号
  trailingComma: 'none', // 不使用尾逗号
  bracketSpacing: true, // 对象大括号直接是否有空格,例如 { a: 1 }
  endOfLine: 'auto',
  jsxBracketSameLine: false, // 在jsx中 '>' 是否单独放一行
  arrowParens: 'always', // 箭头函数参数总是使用括号
  bracketSameLine: true // 多行HTML元素的'>'放在最后一行的末尾,而不是另起一行
}

Stylelint配置

安装Stylelint相关依赖:

bash
pnpm add -D stylelint stylelint-config-html stylelint-config-prettier stylelint-config-recommended-scss stylelint-config-standard stylelint-order stylelint-prettier prettier-stylelint stylelint-config-recess-order stylelint-config-recommended-vue stylelint-config-standard-scss stylelint-scss postcss postcss-html

创建.stylelintrc.js文件:

javascript
export default {
  root: true,
  defaultSeverity: 'warning',
  extends: ['stylelint-config-recess-order', 'stylelint-config-standard-scss', 'stylelint-config-recommended-vue/scss'],
  plugins: ['stylelint-scss'],
  ignoreFiles: ['**/*', '!src/**/*', 'src/**/*.{js,jsx,ts,tsx}'],
  rules: {
    'scss/at-rule-no-unknown': true,
    'function-no-unknown': null,
    'value-no-vendor-prefix': null,
    'property-no-vendor-prefix': null,
    'selector-class-pattern':
      '^[a-z]([a-z0-9-]+)?(__([a-z0-9]+-?)+)?(__([a-z0-9]+-?)+)?(--([a-z0-9]+-?)+){0,2}$|^Mui.*$|^([a-z][a-z0-9]*)(_[a-z0-9]+)*$',
    'font-family-no-missing-generic-family-keyword': null,
    'scss/dollar-variable-pattern': null,
    'block-no-empty': null,
    'no-empty-source': null,
    'property-no-unknown': null,
    'no-descending-specificity': null,
    'selector-pseudo-class-no-unknown': [
      true,
      {
        ignorePseudoClasses: ['export', 'deep', 'global', 'import']
      }
    ],
    'rule-empty-line-before': [
      'always',
      {
        except: ['first-nested'],
        ignore: ['after-comment']
      }
    ],
    'custom-property-empty-line-before': [
      'always',
      {
        except: ['after-custom-property', 'first-nested']
      }
    ],
    'declaration-empty-line-before': [
      'always',
      {
        except: ['after-declaration', 'first-nested']
      }
    ],
    // 忽略特定at规则
    'at-rule-no-unknown': [
      true,
      {
        ignoreAtRules: [
          'tailwind',
          'apply',
          'variants',
          'responsive',
          'screen',
          'function',
          'if',
          'each',
          'include',
          'mixin',
          'return',
          'use'
        ]
      }
    ],
    'unit-no-unknown': [true, { ignoreUnits: ['rpx'] }],
    'order/order': ['custom-properties', 'declarations'],
    'order/properties-order': ['width', 'height']
  },
  overrides: [
    {
      files: ['src/**/*.vue'],
      extends: [
        'stylelint-config-recess-order',
        'stylelint-config-standard-scss',
        'stylelint-config-recommended-vue/scss'
      ],
      plugins: ['stylelint-scss'],
      rules: {
        'declaration-property-value-no-unknown': null,
        'scss/dollar-variable-pattern': null,
        'block-no-empty': null,
        'comment-empty-line-before': null,
        'no-empty-source': null,
        'property-no-unknown': null,
        'selector-pseudo-class-no-unknown': [
          true,
          {
            ignorePseudoClasses: ['deep', 'v-deep']
          }
        ]
      }
    }
  ]
}

自动导入适配

安装自动导入相关依赖:

bash
pnpm add -D unplugin-auto-import

vite.config.ts中配置:

typescript
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import AutoImport from 'unplugin-auto-import/vite'

export default defineConfig({
  plugins: [
    vue(),
    AutoImport({
      // 自动导入Vue相关API
      imports: ['vue', 'vue-router', 'pinia'],
      // 生成对应的d.ts文件
      dts: true,
      // 生成ESLint配置文件
      eslintrc: {
        enabled: true, // 默认false
        filepath: './.eslintrc-auto-import.json',
        globalsPropValue: true
      }
    })
  ]
})

Git工作流规范

Husky配置

安装Husky:

bash
pnpm add -D husky
pnpm exec husky init

lint-staged配置

安装lint-staged:

bash
pnpm add -D lint-staged

创建lint-staged.config.js文件:

javascript
export default {
  '*.{js,jsx,ts,tsx,vue}': ['eslint --fix'],
  '*.vue': ['eslint --fix', 'stylelint --fix'],
  '*.{scss,less,css,stylus,styl}': ['stylelint --fix'],
  '*.{js,jsx,ts,tsx,vue,css,scss,less,md,json}': ['prettier --write']
}

配置Husky的pre-commit钩子,创建.husky/pre-commit文件:

bash
#!/usr/bin/env sh

pnpm exec lint-staged

commitlint配置

安装commitlint相关依赖:

bash
pnpm add -D @commitlint/cli @commitlint/config-conventional

创建.commitlintrc.js文件:

javascript
export default {
  extends: ['@commitlint/config-conventional']
}

配置Husky的commit-msg钩子,创建.husky/commit-msg文件:

bash
#!/usr/bin/env sh

pnpm exec commitlint -e

确保脚本有执行权限:

bash
chmod +x .husky/pre-commit
chmod +x .husky/commit-msg

编辑器配置

editorconfig配置

在项目根目录创建.editorconfig文件:

ini
# EditorConfig is awesome: https://EditorConfig.org

# top-most EditorConfig file
root = true

[*]
charset = utf-8
# 设置space使用index_size, 设置为tab使用tab_width
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true

vscode配置

创建.vscode/settings.json文件:

json
{
  "prettier.prettierPath": "./node_modules/prettier",
  "prettier.requireConfig": true,
  "editor.formatOnSave": true,
  "editor.formatOnPaste": true,
  "editor.dragAndDrop": false,
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": "explicit",
    "source.fixAll.stylelint": "explicit"
  },
  "stylelint.enable": true,
  "stylelint.validate": ["css", "less", "scss", "vue"],
  "eslint.enable": true,
  "eslint.format.enable": true,
  "eslint.useFlatConfig": true,
  "eslint.codeActionsOnSave.mode": "problems",
  "eslint.validate": ["typescript", "javascript", "javascript react", "typescript react", "vue"],
  "[vue]": {
    "editor.formatOnSave": true,
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  }
}

创建.vscode/extensions.json文件,推荐安装的VS Code扩展:

json
{
  "recommendations": [
    "dbaeumer.vscode-eslint",
    "stylelint.vscode-stylelint",
    "esbenp.prettier-vscode",
    "gencer.html-slim-scss-css-class-completion",
    "syler.sass-indented",
    "eamodio.gitlens",
    "donjayamanne.githistory",
    "editorconfig.editorconfig",
    "vue.volar"
  ]
}

TypeScript配置

创建tsconfig.json文件:

json
{
  "compilerOptions": {
    "target": "ESNext",
    "useDefineForClassFields": true,
    "module": "ESNext",
    "moduleResolution": "Node",
    "strict": true,
    "jsx": "preserve",
    "sourceMap": true,
    "resolveJsonModule": true,
    "isolatedModules": true,
    "esModuleInterop": true,
    "lib": ["ESNext", "DOM"],
    "skipLibCheck": true,
    "baseUrl": ".",
    "paths": {
      "@/*": ["src/*"]
    },
    "types": ["vite/client"]
  },
  "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
  "references": [{ "path": "./tsconfig.node.json" }]
}

创建tsconfig.node.json文件:

json
{
  "compilerOptions": {
    "composite": true,
    "module": "ESNext",
    "moduleResolution": "Node",
    "allowSyntheticDefaultImports": true
  },
  "include": ["vite.config.ts"]
}

项目文档

创建一个高质量的README.md文件对项目的长期维护至关重要,应包含以下内容:

  1. 项目名称和简介
  2. 技术栈说明
  3. 目录结构
  4. 安装和使用指南
  5. 开发规范
  6. 常见问题

示例见文章最后的完整配置文件示例部分。

最佳实践建议

  1. 统一环境

    • 使用统一的Node.js版本
    • 使用统一的包管理器版本
    • 配置.nvmrc文件指定Node版本
  2. 代码规范

    • 组件命名使用PascalCase
    • CSS类名使用kebab-case
    • 文件名规范(如组件文件使用PascalCase)
  3. 分支管理

    • 采用标准的Git工作流,如GitFlow或GitHub Flow
    • 主分支保护,通过PR合并代码
  4. 构建优化

    • 代码拆分和懒加载
    • 图片优化
    • 缓存策略
  5. 项目文档

    • 保持文档更新
    • 包含常见问题(FAQ)
    • 编写组件使用示例

完整配置文件示例

package.json 核心配置

json
{
  "name": "vue3-project",
  "private": true,
  "version": "1.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vue-tsc --noEmit && vite build",
    "preview": "vite preview",
    "eslint": "eslint --config eslint.config.mjs . --ext .vue,.js,.ts,.jsx,.tsx,.mjs,.cjs --cache --cache-location node_modules/.cache/eslint/",
    "eslint:fix": "eslint --config eslint.config.mjs . --ext .vue,.js,.ts,.jsx,.tsx,.mjs,.cjs --fix --cache --cache-location node_modules/.cache/eslint/",
    "stylelint": "stylelint --cache \"**/*.{vue,less,postcss,css,scss}\" --cache --cache-location node_modules/.cache/stylelint/",
    "stylelint:fix": "stylelint --cache --fix \"**/*.{vue,less,postcss,css,scss}\" --cache --cache-location node_modules/.cache/stylelint/",
    "prettier": "prettier --check .",
    "prettier:fix": "prettier --write .",
    "lint:all": "npm run eslint:fix && npm run stylelint:fix && npm run prettier:fix",
    "prepare": "husky",
    "type-check": "vue-tsc --noEmit"
  },
  "dependencies": {
    "vue": "^3.4.21",
    "vue-router": "^4.3.0",
    "pinia": "^2.2.2"
  },
  "devDependencies": {
    "@commitlint/cli": "^19.2.1",
    "@commitlint/config-conventional": "^19.2.1",
    "@eslint/js": "^9.29.0",
    "@types/node": "^20.12.10",
    "@typescript-eslint/eslint-plugin": "^7.18.0",
    "@typescript-eslint/parser": "^7.18.0",
    "@vitejs/plugin-vue": "^5.0.5",
    "eslint": "^9.29.0",
    "eslint-config-prettier": "^9.1.0",
    "eslint-plugin-import-x": "^4.16.1",
    "eslint-plugin-prettier": "^5.5.0",
    "eslint-plugin-vue": "^9.33.0",
    "globals": "^16.2.0",
    "husky": "^9.1.7",
    "lint-staged": "^15.5.2",
    "postcss": "^8.4.49",
    "prettier": "^3.5.3",
    "sass": "^1.69.7",
    "stylelint": "^16.20.0",
    "stylelint-config-prettier": "^9.0.5",
    "stylelint-config-recommended-scss": "^14.1.0",
    "stylelint-config-standard": "^36.0.1",
    "stylelint-config-recess-order": "6.0.0",
    "stylelint-config-recommended-vue": "^1.6.0",
    "stylelint-config-standard-scss": "14.0.0",
    "stylelint-scss": "^6.11.1",
    "typescript": "^5.8.3",
    "typescript-eslint": "^8.35.1",
    "unplugin-auto-import": "^0.18.3",
    "vite": "^4.5.14",
    "vue-tsc": "^2.0.6"
  }
}

示例README.md

markdown
# Vue 3 项目模板

<div align="center">

[![Vue](https://img.shields.io/badge/Vue-3.4-brightgreen.svg)](https://vuejs.org/)
[![Vite](https://img.shields.io/badge/Vite-4.5-purple.svg)](https://vitejs.dev/)
[![Pinia](https://img.shields.io/badge/Pinia-2.2-yellow.svg)](https://pinia.vuejs.org/)
[![TypeScript](https://img.shields.io/badge/TypeScript-5.8-blue.svg)](https://www.typescriptlang.org/)
[![Node](https://img.shields.io/badge/Node-%3E%3D18.0-green.svg)](https://nodejs.org/)
[![License](https://img.shields.io/badge/License-MIT-red.svg)](#许可证)

</div>

## 📋 目录

- [项目简介](#项目简介)
- [功能特点](#功能特点)
- [技术栈](#技术栈)
- [快速开始](#快速开始)
  - [环境要求](#环境要求)
  - [安装与使用](#安装与使用)
  - [可用脚本](#可用脚本)
- [项目结构](#项目结构)
- [开发规范](#开发规范)
  - [代码风格](#代码风格)
  - [分支管理](#分支管理)
  - [提交规范](#提交规范)
- [许可证](#许可证)

## 项目简介

项目简介内容

## 功能特点

- **特点1**:描述
- **特点2**:描述
- **特点3**:描述

## 技术栈

- **前端框架**:Vue 3.4.x
- **构建工具**:Vite 4.5.x
- **状态管理**:Pinia 2.2.x
- **路由管理**:Vue Router 4.3.x
- **CSS预处理器**:Sass 1.69.x
- **编程语言**:TypeScript 5.8.x
- **HTTP客户端**:Axios 1.7.x
- **代码规范**:ESLint 9.29.x + Prettier 3.5.x + Stylelint 16.20.x
- **Git钩子**:Husky 9.1.x + Lint-staged 15.5.x

## 快速开始

### 环境要求

- **Node.js**: >= 18.0.0
- **包管理器**: pnpm >= 10.12.14
- **浏览器兼容**: 支持现代浏览器,不兼容IE

### 安装与使用

1. **克隆项目**

```bash
git clone [项目仓库地址]
cd [项目名称]
```

2. **安装依赖**

```bash
pnpm install
```

3. **启动开发服务器**

```bash
pnpm dev
```

4. **构建项目**

```bash
pnpm build
```

### 可用脚本

| 命令                 | 描述                              |
| -------------------- | --------------------------------- |
| `pnpm dev`           | 启动开发服务器                    |
| `pnpm build`         | 构建生产环境代码                  |
| `pnpm preview`       | 本地预览生产构建                  |
| `pnpm eslint`        | 检查JavaScript/TypeScript/Vue代码 |
| `pnpm eslint:fix`    | 自动修复ESLint问题                |
| `pnpm stylelint`     | 检查CSS/SCSS样式                  |
| `pnpm stylelint:fix` | 自动修复Stylelint问题             |
| `pnpm prettier:fix`  | 格式化所有文件                    |
| `pnpm lint:all`      | 执行所有代码检查并自动修复        |
| `pnpm type-check`    | 执行TypeScript类型检查            |

## 项目结构

```sh
vue3-project
├─ public                     // 公共资源,可直接访问
├─ src                        // 项目核心文件夹
│  ├─ assets                  // 公共资源文件
│  │  ├─ icons                // 图标资源
│  │  ├─ images               // 图片资源
│  │  └─ styles               // 全局样式
│  │     ├─ variables.scss    // SCSS变量
│  │     ├─ mixins.scss       // SCSS混合
│  │     └─ global.scss       // 全局样式
│  ├─ components              // 公共组件
│  ├─ composables             // 组合式函数
│  ├─ config                  // 公共配置
│  ├─ directives              // 全局指令
│  ├─ hooks                   // 自定义钩子
│  ├─ pages                   // 页面组件
│  ├─ router                  // 路由配置
│  ├─ services                // API服务
│  ├─ stores                  // 状态管理
│  ├─ types                   // TypeScript类型
│  ├─ utils                   // 工具函数
│  ├─ App.vue                 // 根组件
│  ├─ main.ts                 // 入口文件
├─ eslint.config.mjs          // ESLint配置
├─ .prettierrc.js             // Prettier配置
├─ .stylelintrc.js            // Stylelint配置
├─ tsconfig.json              // TypeScript配置
├─ vite.config.ts             // Vite配置
└─ package.json               // 项目配置和依赖
```

## 开发规范

### 代码风格

项目已配置ESLint、Prettier和Stylelint来保证代码质量和一致性:

- 提交代码前会自动检查和格式化
- 可以手动执行 `pnpm lint:all` 检查并修复所有问题
- 组件命名使用PascalCase
- CSS类名使用kebab-case
- 组件目录结构保持一致

### 分支管理

项目采用以下分支管理策略:

- `main`或`master`: 稳定的生产环境代码
- `develop`: 测试环境分支,用于集成测试
- `feature/*`: 功能开发分支,从主分支创建
- `release/*`: 发布准备分支,多个团队同时上线时使用的公共分支

### 提交规范

提交信息格式:`类型(作用域): 描述`

类型包括:

- `feat`: 新功能
- `fix`: 修复bug
- `docs`: 文档变更
- `style`: 代码格式调整
- `refactor`: 代码重构
- `perf`: 性能优化
- `test`: 测试相关
- `chore`: 构建过程或辅助工具变动

示例:

- `feat(chat): 添加聊天记录导出功能`
- `fix(upload): 修复图片上传失败问题`

## 许可证

[MIT License](./LICENSE)

以上配置可作为Vue 3项目的基础规范,团队可以根据自身需求进行适当调整和扩展。通过这套规范,团队成员可以快速上手,减少代码冲突,提高开发效率,保证代码质量。