从0到1搭建企业级Vue3框架(一):超丝滑的现代前端工程化指南

201 阅读6分钟

从0到1搭建企业级Vue3框架(一):超丝滑的现代前端工程化指南

关键词:Vue3 + TypeScript + Vite + Pinia ✨ 代码规范 🚀 Git提交自动化 🔧


引言:为什么你需要这篇指南?

你是否还在用Vue CLI手动配置项目?每次启动项目都要花半小时调ESLint和Prettier?提交代码时总被队友吐槽Commit Message不规范?
本文将带你从零配置开始,搭建一个开箱即用的现代化Vue3框架,集成:

  • 代码规范(ESLint + Stylelint + Prettier三件套)
  • Git提交自动化(Husky + Commitizen + 可视化提交模板)
  • 极致开发体验(VSCode配置优化 + 一键修复)
    全程只需15分钟,从此告别配置地狱!

一、环境准备:让你的VSCode先卷起来

必装插件清单(直接抄作业)

插件名称作用
Vue-OfficialVue3语法高亮+智能提示
Vue VSCode Snippets输入v3秒生成Vue3模板
ESLint实时检查JavaScript/TS代码规范
Stylelint实时检查CSS/SCSS代码规范
Unocss原子化CSS智能提示

node版本大于20,


二、创建项目:Vite闪电启动

1. 一招生成Vue3+TS项目

pnpm create vue@latest  

按提示选择:

  • TypeScript ✅
  • JSX 支持 ✅
  • Vue Router ✅
  • Pinia ✅(状态管理必备)
  • 单元测试按需开启
  • Eslint 一定选择否 后面我们有专门的插件!!!

tips:tsconfig.app.json、tsconfig.node.json打开如果报错的话,按照以下方式就能完美解决了

image.png

三、代码规范:ESLint + Stylelint黄金组合

1. 配置ESLint(黑科技一键配置)

eslint9x 扁平化设计 导致相关插件产生滞后 并未适配,所以这里使用antfu 组合prettier&eslint

2. 安装依赖(直接复制)

安装前我们在项目中初始下git (git init)

npx @antfu/eslint-config@latest

image.png 然后按照提示执行pnpm install 可以看到在我们项目中创建了eslint.config.js 和setting.json文件 我们稍微改造下eslint.config.js,

import antfu from '@antfu/eslint-config'
export default antfu({
  // @stylistic/eslint-plugin-plus
  stylistic: true,
  // eslint-plugin-format
  formatters: true,
  // unocss 检测&格式化 暂时注释 等配置了unocss再开放为true
  // unocss: true,
  // vue的eslint配置
  vue: true,
  // 保存删除未引入的代码
  // isInEditor: false,
  // 9x版本 忽略文件这种配置方式 废弃掉eslintignore
  ignores: [
    '*.sh',
    'node_modules',
    '*.md',
    '*.woff',
    '*.ttf',
    '.idea',
    '/public',
    '/docs',
    '.husky',
    '.local',
    '/bin',
    'Dockerfile',
  ],
})

package.json 配置 后面结合husky 提交代码时自动进行eslint校验修复。

"scripts": { 
    "lint": "eslint .",
    "lint:fix": "eslint . --fix"
}

3. Stylelint配置(专治CSS强迫症)

//这里我是用的sass 使用less的可以把sass相关的都改成less
pnpm install scss postcss postcss-html postcss-scss sass stylelint stylelint-config-recess-order stylelint-config-standard -D

创建stylelint.config.mjs

/** @type {import('stylelint').Config} */
export default {
  // stylelint-config-standard 基础配置
  // stylelint-config-recess-order 样式顺序
  extends: ['stylelint-config-standard', 'stylelint-config-recess-order'],
  // 不同文件类型用不同解析器
  overrides: [
    {
      files: ['**/*.(css|html|vue)'],
      customSyntax: 'postcss-html'
    },
    // sass
    {
      files: ['*.scss', '**/*.scss'],
      customSyntax: 'postcss-scss',
      rule: {
        'scss/percent-placeholder-pattern': null,
        'scss/at-mixin-pattern': null
      }
    }
  ],
  rules: {
    // 'prettier/prettier': true,
    'media-feature-range-notation': null,
    'selector-not-notation': null,
    'import-notation': null,
    'function-no-unknown': null,
    'selector-class-pattern': null,
    'selector-pseudo-class-no-unknown': [
      true,
      {
        ignorePseudoClasses: ['global', 'deep']
      }
    ],
    'selector-pseudo-element-no-unknown': [
      true,
      {
        ignorePseudoElements: ['v-deep', ':deep']
      }
    ],
    'at-rule-no-unknown': [
      true,
      {
        ignoreAtRules: [
          'tailwind',
          'apply',
          'variants',
          'responsive',
          'screen',
          'function',
          'if',
          'each',
          'include',
          'mixin',
          'extend',
          'use'
        ]
      }
    ],
    'no-empty-source': null,
    'named-grid-areas-no-invalid': null,
    'no-descending-specificity': null,
    'font-family-no-missing-generic-family-keyword': null,
    'rule-empty-line-before': [
      'always',
      {
        ignore: ['after-comment', 'first-nested']
      }
    ],
    'unit-no-unknown': [true, { ignoreUnits: ['rpx'] }],
    'order/order': [
      [
        'dollar-variables',
        'custom-properties',
        'at-rules',
        'declarations',
        {
          type: 'at-rule',
          name: 'supports'
        },
        {
          type: 'at-rule',
          name: 'media'
        },
        'rules'
      ],
      { severity: 'error' }
    ]
  },
  ignoreFiles: ['**/*.js', '**/*.jsx', '**/*.tsx', '**/*.ts']
}


四、Git提交自动化:告别"fix: bug"

1. 初始化Husky(自动化神器)

自动配置
npx husky-init

项目下会多出husky文件

image.png

2. 安装lint-staged (过滤git暂存区文件的工具)

pnpm install lint-staged -D
// 新建 lint-staged.config.mjs
/**  @type {import('lint-staged').Config} */
export default {
    '*.{js,jsx,ts,tsx}': ['eslint --fix'],
    '*.json': ['eslint --fix'],
    '*.vue': ['eslint --fix'],
    '*.{scss,less,styl,html}': ['stylelint --fix --allow-empty-input'],
  }
  
  
  package.json 配置
  "lint:lint-staged": "lint-staged",
  
  .husky/pre-commit 修改 (git代码提交时进行校验)
  npm run list:lint-staged --allow-empty

3. commitlint (是对git commit提交的注释进行校验的工具)

pnpm install @commitlint/cli @commitlint/config-conventional -D

新建 commitlint.config.js

 /** @type {import("@commitlint/types").UserConfig} */
 export default {
    ignores: [commit => commit.includes('init')],
    extends: ['@commitlint/config-conventional'],
    rules: {
      'body-leading-blank': [2, 'always'],
      'footer-leading-blank': [1, 'always'],
      'header-max-length': [2, 'always', 108],
      'subject-empty': [2, 'never'],
      'type-empty': [2, 'never'],
      'subject-case': [0],
      'type-enum': [
        2,
        'always',
        [
          'feat', // 新增功能
          'fix', // 修复缺陷
          'docs', // 文档变更
          'style', // 代码格式(不影响功能,例如空格、分号等格式修正)
          'refactor', // 代码重构(不包括 bug 修复、功能新增)
          'perf', // 性能优化
          'test', // 添加疏漏测试或已有测试改动
          'build', // 构建流程、外部依赖变更(如升级 npm 包、修改 webpack 配置等)
          'ci', // 修改 CI 配置、脚本
          'revert', // 回滚 commit
          'chore', // 对构建过程或辅助工具和库的更改(不影响源文件、测试用例)
        ],
      ],
    },
  }

4.Commitizen+cz-git 配置交互式提交模板

commitizen: 它提供了一个 git cz 的指令用于代替 git commit,从而对 Git 提交进行规范化处理cz-git: commitizen的交互性并不是太友好,因此国人开发了这一款工具,工程性更强,自定义更高,交互性更好。

pnpm i commitizen cz-git -D

修改commitlint.config.js

参考官网配置模版 cz-git.qbb.sh/zh/guide/in…


const { defineConfig } = require('cz-git')

module.exports = defineConfig({
    prompt: {
        alias: { fd: 'docs: fix typos' },
        messages: {
            type: 'Select the type of change that you\'re committing:',
            scope: 'Denote the SCOPE of this change (optional):',
            customScope: 'Denote the SCOPE of this change:',
            subject: 'Write a SHORT, IMPERATIVE tense description of the change:\n',
            body: 'Provide a LONGER description of the change (optional). Use "|" to break new line:\n',
            breaking: 'List any BREAKING CHANGES (optional). Use "|" to break new line:\n',
            footerPrefixesSelect: 'Select the ISSUES type of changeList by this change (optional):',
            customFooterPrefix: 'Input ISSUES prefix:',
            footer: 'List any ISSUES by this change. E.g.: #31, #34:\n',
            generatingByAI: 'Generating your AI commit subject...',
            generatedSelectByAI: 'Select suitable subject by AI generated:',
            confirmCommit: 'Are you sure you want to proceed with the commit above?',
        },
        types: [
            { value: 'feat', name: 'feat:     ✨  A new feature', emoji: ':sparkles:' },
            { value: 'fix', name: 'fix:      🐛  A bug fix', emoji: ':bug:' },
            { value: 'docs', name: 'docs:     📝  Documentation only changes', emoji: ':memo:' },
            { value: 'style', name: 'style:    💄  Changes that do not affect the meaning of the code', emoji: ':lipstick:' },
            { value: 'refactor', name: 'refactor: ♻️   A code change that neither fixes a bug nor adds a feature', emoji: ':recycle:' },
            { value: 'perf', name: 'perf:     ⚡️  A code change that improves performance', emoji: ':zap:' },
            { value: 'test', name: 'test:     ✅  Adding missing tests or correcting existing tests', emoji: ':white_check_mark:' },
            { value: 'build', name: 'build:    📦️   Changes that affect the build system or external dependencies', emoji: ':package:' },
            { value: 'ci', name: 'ci:       🎡  Changes to our CI configuration files and scripts', emoji: ':ferris_wheel:' },
            { value: 'chore', name: 'chore:    🔨  Other changes that don\'t modify src or test files', emoji: ':hammer:' },
            { value: 'revert', name: 'revert:   ⏪️  Reverts a previous commit', emoji: ':rewind:' },
        ],
        useEmoji: true,
        emojiAlign: 'center',
        useAI: false,
        aiNumber: 1,
        themeColorCode: '',
        scopes: [],
        allowCustomScopes: true,
        allowEmptyScopes: true,
        customScopesAlign: 'bottom',
        customScopesAlias: 'custom',
        emptyScopesAlias: 'empty',
        upperCaseSubject: false,
        markBreakingChangeMode: false,
        allowBreakingChanges: ['feat', 'fix'],
        breaklineNumber: 100,
        breaklineChar: '|',
        skipQuestions: [],
        issuePrefixes: [{ value: 'closed', name: 'closed:   ISSUES has been processed' }],
        customIssuePrefixAlign: 'top',
        emptyIssuePrefixAlias: 'skip',
        customIssuePrefixAlias: 'custom',
        allowCustomIssuePrefix: true,
        allowEmptyIssuePrefix: true,
        confirmColorize: true,
        scopeOverrides: undefined,
        defaultBody: '',
        defaultIssues: '',
        defaultScope: '',
        defaultSubject: '',
    },
})

4. 提交代码时触发校验

package.json中添加:

{  
  "scripts": {  
    "commit": "git add -A && git-cz"  
  },
    "config": {
      "commitizen": {
        "path": "./node_modules/cz-conventional-changelog"
      }
  },
}  

现在只需运行pnpm commit,就能看到酷炫的提交界面!

image.png

结语:你的现代化前端流水线已就绪

至此,你已经拥有了:

  • 🚀 闪电启动的Vite+Vue3项目
  • ✨ 严格却不死板的代码规范
  • 🤖 智能的Git提交工作流

互动话题:你在配置前端工程化时踩过哪些坑?欢迎评论区分享~ 💬
点赞收藏:如果本文帮你省了2小时,不妨点个赞支持作者!👍