文章目录
一、项目初始化
- 初始化package.json
pnpm init
- 创建pnpm-workspace.yaml文件
packages:
- "apps/*"
- "packages/*"
- 创建apps、packages文件夹,apps表示应用文件夹,packages表示公共依赖文件夹
二、规范化配置
1、eslint配置
① 安装依赖
"eslint": "9.7.0",
"@eslint/js": "9.7.0",
"globals": "15.8.0",
"eslint-plugin-vue": "9.27.0",
"vue-eslint-parser": "9.4.3",
"@typescript-eslint/parser": "7.16.1",
"eslint-plugin-simple-import-sort": "12.1.1"
② 创建eslint.config.js
import js from "@eslint/js";
import importSort from "eslint-plugin-simple-import-sort";
import pluginVue from "eslint-plugin-vue";
import globals from "globals";
import vueEslintParser from "vue-eslint-parser";
import tsParser from "@typescript-eslint/parser";
export default [
{
languageOptions: {
globals: {
...globals.browser,
computed: "readonly",
defineEmits: "readonly",
defineExpose: "readonly",
defineProps: "readonly",
onMounted: "readonly",
onUnmounted: "readonly",
reactive: "readonly",
ref: "readonly",
shallowReactive: "readonly",
shallowRef: "readonly",
toRef: "readonly",
toRefs: "readonly",
watch: "readonly",
watchEffect: "readonly",
},
},
name: "xxx/vue/setup",
plugins: {
vue: pluginVue,
},
},
{
files: ["**/*.{ts,tsx,vue}"],
ignores: [],
rules: {
...js.configs.recommended.rules,
...pluginVue.configs["flat/recommended"].rules,
"no-unused-vars": "error",
"no-undef": "warn",
"no-console": "error",
"simple-import-sort/imports": "error",
"simple-import-sort/exports": "error",
"vue/valid-define-emits": "error",
},
languageOptions: {
parser: vueEslintParser,
parserOptions: {
extraFileExtensions: [".vue"],
// ecmaVersion: 'latest',
ecmaFeatures: {
jsx: true,
},
parser: tsParser,
sourceType: "module",
project: [
path.join(import.meta.dirname, "tsconfig.eslint.json"),
path.join(import.meta.dirname, "../../**/*/tsconfig.json"),
],
// project: path.join(import.meta.dirname, "tsconfig.eslint.json"),
tsconfigRootDir: import.meta.dirname,
},
},
plugins: {
vue: pluginVue,
"simple-import-sort": importSort,
},
},
];
③ 在最外层目录添加eslint脚本
"lint:vue": "eslint --fix"
④ 测试eslint
pnpm run lint:vue
⑤ eslint无法直接检测vue文件,如何处理
- 下面这个配置之后也只能检测vue中的js,ts等
import js from "@eslint/js";
import {} from "globals";
import pluginVue from "eslint-plugin-vue";
import vueEslintParser from "vue-eslint-parser";
export default [
{
files: ["**/*.{ts,tsx,vue}"],
rules: {
...js.configs.recommended.rules,
...pluginVue.configs["flat/recommended"].rules,
"no-console": "error",
},
languageOptions: {
parser: vueEslintParser,
},
},
];
- 如何检测vue中的模板,可以使用vue-official,vscode中的插件来检测
2、stylelint
① 安装依赖
"stylelint": "16.7.0",
"stylelint-config-standard-vue": "1.0.0",
"stylelint-config-standard": "36.0.0",
"stylelint-config-standard-scss": "13.1.0"
② 编写stylelint.config.js配置文件
export default {
extends: ["stylelint-config-standard"],
overrides: [
{
files: ["*.scss", "**/*.scss"],
extends: ["stylelint-config-standard-scss"],
},
{
files: ["*.vue", "**/*.vue"],
extends: [
"stylelint-config-standard-scss",
"stylelint-config-recommended-vue",
],
},
],
};
③ 编写.stylelintignore文件
**/node_modules/
**/dist/
**/public/
**/build/
**/vendor/
**/*.min.css
**/*.map
④ package.json中添加脚本命令
"lint:style": "stylelint \"{packages,apps}/**/*.{css,scss}\" --color --cache --fix"
⑤ 执行命令判断是否成功
pnpm run lint:style
3、安装cspell对单词拼写进行校验
① 安装依赖
"cspell": "8.11.0"
② 编写cspell.json配置文件
{
"import": ["@cspell/dict-lorem-ipsum/cspell-ext.json"],
"caseSensitive": false,
"dictionaries": ["custom-words"],
"dictionaryDefinitions": [
{
"name": "custom-words",
"path": "./.cspell/custom-words.txt",
"addWords": true
}
],
"ignorePaths": [
"**/node_modules/**",
"**/dist/**",
"**/lib/**",
"**/docs/**",
"**/stats.html",
"**/language/**",
"**/language.ts",
"**/package.json",
"**/MOCK_DATA.ts",
"eslint.config.js"
]
}
根据上面的配置文件,需要创建文件夹 .cspell 和 custom-words.txt 文件,存放我们自定义的单词,可以绕过校验
③ 配置拼写检查脚本
"spellcheck": "cspell lint --dot --color --cache --show-suggestions \"(packages|apps)/**/*.@(html|js|cjs|mjs|ts|tsx|css|scss|md|vue)\""
4、配置.editorconfig文件
root = true
[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false
5、配置prettier代码美化工具
① 安装依赖
"prettier": "3.6.2",
"eslint-config-prettier": "10.1.5",
"eslint-plugin-prettier": "5.5.1"
② 创建.prettierrc文件
{
"$schema": "https://json.schemastore.org/prettierrc",
"semi": false,
"tabWidth": 2,
"singleQuote": true,
"printWidth": 100,
"trailingComma": "none"
}
③ 创建.prettierignore文件
/dist
*.yaml
④ 添加脚本
"prettier": "prettier --check {packages,apps}/**/*.{ts,tsx,js,vue,css,scss,json,yaml,md}",
6、创建.gitignore文件
node_modules
**/.vitepress
**/dist
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
.DS_Store
dist
dist-ssr
coverage
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
*.tsbuildinfo
7、提交规范检查
① 安装依赖
"cz-git": "1.9.4",
"@commitlint/cli": "19.3.0",
"@commitlint/config-conventional": "19.2.2",
"commitizen": "4.3.0",
"husky": "9.1.6",
"fast-glob": "3.3.2"
② 配置commitizen,在package.json中添加config
"config": {
"commitizen": {
"path": "node_modules/cz-git"
}
},
③ 配置commitlint.config.js文件(这个文件cz-git和commitlint共用该配置)
import fg from 'fast-glob'
const getPackages = (packagePath) =>
fg.sync('*', { cwd: packagePath, onlyDirectories: true, deep: 2 })
const scopes = [
...getPackages('packages'),
...getPackages('apps'),
...getPackages('apps/frontend'),
...getPackages('apps/backend'),
...getPackages('demos'),
'docs',
'project',
'style',
'ci',
'dev',
'deploy',
'other'
]
// Emoji
/** @type {import('cz-git').UserConfig} */
export default {
extends: ['@commitlint/config-conventional'], // extends can be nested
parserPreset: 'conventional-changelog-conventionalcommits',
rules: {
'scope-enum': [2, 'always', scopes]
},
prompt: {
settings: {},
messages: {
skip: ':skip',
max: 'upper %d chars',
min: '%d chars at least',
emptyWarning: 'can not be empty',
upperLimitWarning: 'over limit',
lowerLimitWarning: 'below limit'
},
types: [
{ value: 'feat', name: 'feat: ✨ A new feature', emoji: '✨ ' },
{ value: 'fix', name: 'fix: 🐛 A bug fix', emoji: '🐛 ' },
{ value: 'docs', name: 'docs: 📝 Documentation only changes', emoji: '📝 ' },
{
value: 'style',
name: 'style: 💄 Changes that do not affect the meaning of the code',
emoji: '💄 '
},
{
value: 'refactor',
name: 'refactor: 📦️ A code change that neither fixes a bug nor adds a feature',
emoji: '📦️ '
},
{
value: 'perf',
name: 'perf: 🚀 A code change that improves performance',
emoji: '🚀 '
},
{
value: 'test',
name: 'test: 🚨 Adding missing tests or correcting existing tests',
emoji: '🚨 '
},
{
value: 'build',
name: 'build: 🛠 Changes that affect the build system or external dependencies',
emoji: '🛠 '
},
{
value: 'ci',
name: 'ci: 🎡 Changes to our CI configuration files and scripts',
emoji: '🎡 '
},
{
value: 'chore',
name: "chore: 🔨 Other changes that don't modify src or test files",
emoji: '🔨 '
},
{ value: 'revert', name: 'revert: ⏪️ Reverts a previous commit', emoji: ':rewind:' }
],
useEmoji: true,
confirmColorize: true,
emojiAlign: 'center',
questions: {
scope: {
description: 'What is the scope of this change (e.g. component or file name)'
},
subject: {
description: 'Write a short, imperative tense description of the change'
},
body: {
description: 'Provide a longer description of the change'
},
isBreaking: {
description: 'Are there any breaking changes?'
},
breakingBody: {
description:
'A BREAKING CHANGE commit requires a body. Please enter a longer description of the commit itself'
},
breaking: {
description: 'Describe the breaking changes'
},
isIssueAffected: {
description: 'Does this change affect any open issues?'
},
issuesBody: {
description:
'If issues are closed, the commit requires a body. Please enter a longer description of the commit itself'
},
issues: {
description: 'Add issue references (e.g. "fix #123", "re #123".)'
}
}
}
}
// 汉化
// /** @type {import('cz-git').UserConfig} */
// module.exports = {
// rules: {
// // @see: https://commitlint.js.org/#/reference-rules
// },
// prompt: {
// alias: { fd: 'docs: fix typos' },
// messages: {
// type: '选择你要提交的类型 :',
// scope: '选择一个提交范围(可选):',
// customScope: '请输入自定义的提交范围 :',
// subject: '填写简短精炼的变更描述 :\n',
// body: '填写更加详细的变更描述(可选)。使用 "|" 换行 :\n',
// breaking: '列举非兼容性重大的变更(可选)。使用 "|" 换行 :\n',
// footerPrefixesSelect: '选择关联issue前缀(可选):',
// customFooterPrefix: '输入自定义issue前缀 :',
// footer: '列举关联issue (可选) 例如: #31, #I3244 :\n',
// generatingByAI: '正在通过 AI 生成你的提交简短描述...',
// generatedSelectByAI: '选择一个 AI 生成的简短描述:',
// confirmCommit: '是否提交或修改commit ?'
// },
// types: [
// { value: '特性', name: '特性: 新增功能' },
// { value: '修复', name: '修复: 修复缺陷' },
// { value: '文档', name: '文档: 文档变更' },
// { value: '格式', name: '格式: 代码格式(不影响功能,例如空格、分号等格式修正)' },
// { value: '重构', name: '重构: 代码重构(不包括 bug 修复、功能新增)' },
// { value: '性能', name: '性能: 性能优化' },
// { value: '测试', name: '测试: 添加疏漏测试或已有测试改动' },
// { value: '构建', name: '构建: 构建流程、外部依赖变更(如升级 npm 包、修改 webpack 配置等)' },
// { value: '集成', name: '集成: 修改 CI 配置、脚本' },
// { value: '回退', name: '回退: 回滚 commit' },
// { value: '其他', name: '其他: 对构建过程或辅助工具和库的更改(不影响源文件、测试用例)' }
// ],
// useEmoji: false,
// emojiAlign: 'center',
// useAI: false,
// aiNumber: 1,
// themeColorCode: '',
// scopes: [],
// allowCustomScopes: true,
// allowEmptyScopes: true,
// customScopesAlign: 'bottom',
// customScopesAlias: '以上都不是?我要自定义',
// emptyScopesAlias: '跳过',
// upperCaseSubject: false,
// markBreakingChangeMode: false,
// allowBreakingChanges: ['feat', 'fix'],
// breaklineNumber: 100,
// breaklineChar: '|',
// skipQuestions: [],
// issuePrefixes: [
// // 如果使用 gitee 作为开发管理
// { value: 'link', name: 'link: 链接 ISSUES 进行中' },
// { value: 'closed', name: 'closed: 标记 ISSUES 已完成' }
// ],
// customIssuePrefixAlign: 'top',
// emptyIssuePrefixAlias: '跳过',
// customIssuePrefixAlias: '自定义前缀',
// allowCustomIssuePrefix: true,
// allowEmptyIssuePrefix: true,
// confirmColorize: true,
// maxHeaderLength: Infinity,
// maxSubjectLength: Infinity,
// minSubjectLength: 0,
// scopeOverrides: undefined,
// defaultBody: '',
// defaultIssues: '',
// defaultScope: '',
// defaultSubject: ''
// }
// }
④ 初始化husky
npx husky init
修改pre-commit脚本
#!/usr/bin/env bash
npx lint-staged && pnpm spellcheck && pnpm typecheck
⑤ package.json中添加提交代码脚本
"commit": "git-cz",
8、配置lint-staged
① 安装依赖
"lint-staged": "15.2.10",
② package.json中配置lint-staged
"lint-staged": {
"*.{md,json}": [
"prettier --cache --write --no-error-on-unmatched-pattern"
],
"*.{css,less}": [
"prettier --cache --write"
],
"*.{js,jsx}": [
"eslint --fix",
"prettier --cache --write"
],
"*.{ts,tsx}": [
"eslint --fix",
"prettier --cache --parser=typescript --write"
]
},
9、配置turbo
① 安装依赖
"turbo": "2.2.3",
② 配置turbo.json
{
"$schema": "https://turbo.build/schema.json",
"tasks": {
"build:watch": {
"cache": false,
"persistent": true
},
"build": {
"dependsOn": ["^build"],
"outputs": []
},
"dev": {
"cache": false,
"persistent": true
},
"typecheck": {
"cache": false,
"persistent": true
}
},
"ui": "tui",
"cacheDir": ".turbo/cache"
}
③ package.json中编写turbo脚本
// 构建并且观察
"build:watch": "turbo build:watch",
// 构建
"build": "turbo build",
// 开发
"dev": "turbo dev",
"typecheck": "turbo typecheck",
10、typescript配置
tsconfig.json
{
"compilerOptions": {
"alwaysStrict": false,
"declaration": true,
"declarationMap": true,
"downlevelIteration": true,
"importHelpers": true,
"inlineSources": true,
"isolatedModules": true,
"lib": ["ESNext"],
"moduleResolution": "node",
"noErrorTruncation": true,
"noFallthroughCasesInSwitch": true,
"noImplicitReturns": true,
"noUnusedLocals": false,
"noUnusedParameters": false,
"preserveWatchOutput": true,
"sourceMap": true,
"strict": true,
"strictBindCallApply": false,
"target": "es2018",
"noUncheckedIndexedAccess": true,
"skipLibCheck": true,
"esModuleInterop": true,
"resolveJsonModule": true,
"noEmit": true,
"baseUrl": "."
},
"include": ["packages/**/*", "apps/**/*"],
"exclude": ["node_modules", "**/*.spec.ts"]
}
tsconfig.eslint.json
{
"root": true,
"ignorePatterns": ["**/*.js"],
"overrides": [
{
"files": ["*.ts", "*.tsx"],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"project": "./tsconfig.json",
"createDefaultProgram": true,
"ecmaVersion": 2020,
"sourceType": "module"
},
"plugins": ["@typescript-eslint/eslint-plugin"],
"extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended", "prettier"],
"rules": {
"@typescript-eslint/no-explicit-any": ["warn"],
"@typescript-eslint/no-unused-vars": ["error", { "argsIgnorePattern": "^_" }],
"@typescript-eslint/no-empty-function": ["off"],
"prefer-const": ["error"],
"no-console": ["warn"]
}
}
]
}