前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【二】项目规范和项目管理

【二】项目规范和项目管理

原创
作者头像
思索
修改2024-09-24 14:40:13
980
修改2024-09-24 14:40:13
举报
文章被收录于专栏:从零开始写一套广告组件

前言

在这一章我们进行一个简单的项目规范和项目管理,为了更好的代码协同,我们选择使用 Git 对代码进行管理并通过一系列 npm 包配置相应的规范约束。

内容

本章内容涉及到的文档如下:

githttps://git-scm.com/

editorconfighttps://editorconfig.org/

EditorConfig for VS CodeEditorConfig for VS Code

配置Git

让我们打开项目,运行终端,现在开始执行第一个命令,让我们初始化 Git 仓库:

代码语言:shell
复制
$ git init   
已初始化空的 Git 仓库于 /Users/wangyang/Documents/eaui/.git/

接下来,让我们来添加远程仓库地址,并进行第一次初始化提交:

代码语言:shell
复制
$ git remote add origin git@github.com:oyo-cool/eaui.git
$ git add .
$ git commit -m "init"  
$ git push --set-upstream origin main

如果没有出现意外的话,您将会看到类似以下的输出:

代码语言:shell
复制
枚举对象中: 47, 完成.
对象计数中: 100% (47/47), 完成.
使用 12 个线程进行压缩
压缩对象中: 100% (42/42), 完成.
写入对象中: 100% (47/47), 64.76 KiB | 9.25 MiB/s, 完成.
总共 47(差异 0),复用 31(差异 0),包复用 0(来自  0 个包)
To github.com:oyo-cool/eaui.git
 + 150853f...d4e3320 main -> main (forced update)
分支 'main' 设置为跟踪 'origin/main'。

恭喜您,现在您已经成功的将代码推送到了远程的仓库上!不过这里还没有结束,我们避免不同系统之间的换行符的差异,所以这里我们增加个配置 .gitattributes,内容如下:

代码语言:txt
复制
*.ts    text eol=lf
*.vue   text eol=lf
*.tsx   text eol=lf
*.jsx   text eol=lf
*.html  text eol=lf
*.json  text eol=lf

配置规则

现在 Git 已经配置完成,接下来让我们一起来配置下项目的规范和约束,当前在最开始初始化项目的时候,vue脚手架已经帮我们配置好了ESlintPrettier ,不过那样远远不够,现在让我们根据自己的规则再来进行完善。

配置.editorconfig

EditorConfig 有助于为跨各种编辑器和 IDE 处理同一项目的多个开发人员保持一致的编码样式。

代码语言:shell
复制
root = true

[*]
indent_style = space
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[*.md]
trim_trailing_whitespace = false

[*.{ts,js,vue,css}]
indent_size = 2
配置Prettier

首先我们先对 Prettier 进行更新,强迫症患者又加上是新项目,刚好看看有没有坑,可以提前踩踩。

代码语言:shell
复制
$ pnpm up prettier

更新完成后,我们移除当前项目中的配置文件.prettierrc.json ,创建一个新的配置文件 .prettierrc.js ,配置内容如下:

代码语言:ts
复制
export default {
  // 一行最多 120 字符..
  printWidth: 120,
  // 使用 2 个空格缩进
  tabWidth: 2,
  // 不使用缩进符,而使用空格
  useTabs: false,
  // 行尾需要有分号
  semi: true,
  // 使用单引号
  singleQuote: true,
  // 对象的 key 仅在必要时用引号
  quoteProps: 'as-needed',
  // jsx 不使用单引号,而使用双引号
  jsxSingleQuote: false,
  // 末尾需要有逗号
  trailingComma: 'all',
  // 大括号内的首尾需要空格
  bracketSpacing: true,
  // jsx 标签的反尖括号需要换行
  jsxBracketSameLine: false,
  // 箭头函数,只有一个参数的时候,也需要括号
  arrowParens: 'always',
  // 每个文件格式化的范围是文件的全部内容
  rangeStart: 0,
  rangeEnd: Infinity,
  // 不需要写文件开头的 @prettier
  requirePragma: false,
  // 不需要自动在文件开头插入 @prettier
  insertPragma: false,
  // 使用默认的折行标准
  proseWrap: 'preserve',
  // 根据显示样式决定 html 要不要折行
  htmlWhitespaceSensitivity: 'css',
  // vue 文件中的 script 和 style 内不用缩进
  vueIndentScriptAndStyle: false,
  // 换行符使用 lf
  endOfLine: 'lf',
};

配置好之后,让我们来试试运行命令会有什么样的结果:

代码语言:shell
复制
$ pnpm format 
> eaui@0.0.0 format /Users/wangyang/Documents/eaui
> prettier --write src/

src/App.vue 57ms (unchanged)
src/assets/base.css 6ms (unchanged)
src/assets/main.css 2ms (unchanged)
src/components/__tests__/HelloWorld.spec.ts 7ms (unchanged)
src/components/HelloWorld.vue 21ms (unchanged)
src/components/icons/IconCommunity.vue 3ms (unchanged)
src/components/icons/IconDocumentation.vue 1ms (unchanged)
src/components/icons/IconEcosystem.vue 2ms (unchanged)
src/components/icons/IconSupport.vue 1ms (unchanged)
src/components/icons/IconTooling.vue 1ms (unchanged)
src/components/TheWelcome.vue 7ms (unchanged)
src/components/WelcomeItem.vue 5ms (unchanged)
src/main.ts 3ms (unchanged)
src/stores/counter.ts 4ms (unchanged)

好的,很完美,目前看来好像没有出现什么坑。

配置ESlint

这里我们需要安装的插件比较多,不过其中有一些是脚手架已经安装过的,每个插件具体的用处,可查看对应的文档来了解,这里不一一解释。

eslint-config-prettierhttps://www.npmjs.com/package/eslint-config-prettier

eslint-plugin-prettierhttps://www.npmjs.com/package/eslint-plugin-prettier

eslint-plugin-playwrighthttps://www.npmjs.com/package/eslint-plugin-playwright

eslint-plugin-vue-scoped-csshttps://www.npmjs.com/package/eslint-plugin-vue-scoped-css

eslint-plugin-vuehttps://www.npmjs.com/package/eslint-plugin-vue

eslint-config-airbnb-basehttps://www.npmjs.com/package/eslint-config-airbnb-base

eslint-config-typescripthttps://www.npmjs.com/package/@vue/eslint-config-typescript

@typescript-eslint/eslint-pluginhttps://www.npmjs.com/package/@typescript-eslint/eslint-plugin

eslint-plugin-simple-import-sorthttps://www.npmjs.com/package/eslint-plugin-simple-import-sort

@typescript-eslint/parserhttps://www.npmjs.com/package/@typescript-eslint/parser

@typescript-eslint/eslint-pluginhttps://www.npmjs.com/package/@typescript-eslint/eslint-plugin

代码语言:shell
复制
pnpm add -D eslint-config-prettier eslint-plugin-prettier eslint-plugin-playwright eslint-plugin-vue-scoped-css eslint-plugin-vue eslint-config-airbnb-base @vue/eslint-config-typescript @typescript-eslint/eslint-plugin eslint-plugin-simple-import-sort @typescript-eslint/parser @typescript-eslint/eslint-plugin

安装完插件后,我们先配置下忽略文件 .eslintignore

代码语言:txt
复制
dist
lib
es
esm
node_modules
static
cypress
playwright-report
tests-results
static/
!.prettierrc.js

配置好忽略文件之后,先移除当前的配置文件 .eslintrc.cjs,再创建一个全新的配置文件 .eslintrc ,内容如下:

代码语言:js
复制
{
  "extends": [
    "plugin:@typescript-eslint/recommended",
    "eslint-config-airbnb-base",
    "@vue/typescript/recommended",
    "plugin:vue/vue3-recommended",
    "plugin:vue-scoped-css/base",
    "plugin:prettier/recommended",
  ],
  "env": {
    "browser": true,
    "node": true,
    "jest": true,
    "es6": true,
  },
  "globals": {
    "defineProps": "readonly",
    "defineEmits": "readonly",
  },
  "plugins": ["vue", "@typescript-eslint", "simple-import-sort"],
  "parserOptions": {
    "parser": "@typescript-eslint/parser",
    "sourceType": "module",
    "allowImportExportEverywhere": true,
    "ecmaFeatures": {
      "jsx": true,
    },
  },
  "settings": {
    "import/extensions": [".js", ".jsx", ".ts", ".tsx"],
    "eslint.packageManager": "pnpm",
  },
  "rules": {
    "no-console": "off",
    "no-continue": "off",
    "no-restricted-syntax": "off",
    "no-plusplus": "off",
    "no-param-reassign": "off",
    "no-shadow": "off",
    "guard-for-in": "off",
    "camelcase": [
      "error",
      {
        "ignoreDestructuring": true,
        "properties": "never",
      },
    ],

    "import/extensions": "off",
    "import/no-unresolved": "off",
    "import/no-extraneous-dependencies": "off",
    "import/prefer-default-export": "off",
    "import/first": "off", // https://github.com/vuejs/vue-eslint-parser/issues/58
    "@typescript-eslint/no-explicit-any": "off",
    "@typescript-eslint/explicit-module-boundary-types": "off",
    "vue/first-attribute-linebreak": 0,
    "class-methods-use-this": "off",

    "@typescript-eslint/no-unused-vars": [
      "error",
      {
        "argsIgnorePattern": "^_",
        "varsIgnorePattern": "^_",
      },
    ],
    "no-unused-vars": [
      "error",
      {
        "argsIgnorePattern": "^_",
        "varsIgnorePattern": "^_",
      },
    ],
    "no-use-before-define": "off",
    "@typescript-eslint/no-use-before-define": "off",
    "@typescript-eslint/ban-ts-comment": "off",
    "@typescript-eslint/ban-types": "off",
    "simple-import-sort/imports": "error",
    "simple-import-sort/exports": "error",
  },
  "overrides": [
    {
      "files": [
        "e2e/**/*.{test,spec}.{js,ts,jsx,tsx}"
      ],
      "extends": [
        "plugin:playwright/recommended"
      ]
    },
    {
      "files": ["*.vue"],
      "rules": {
        "vue/component-name-in-template-casing": [2, "kebab-case"],
        "vue/require-default-prop": 0,
        "vue/multi-word-component-names": 0,
        "vue/no-reserved-props": 0,
        "vue/no-v-html": 0,
        "vue-scoped-css/enforce-style-type": ["error", { "allows": ["scoped"] }],
      },
    },
    {
      "files": ["*.ts", "*.tsx"], // https://github.com/typescript-eslint eslint-recommended
      "rules": {
        "constructor-super": "off", // ts(2335) & ts(2377)
        "getter-return": "off", // ts(2378)
        "no-const-assign": "off", // ts(2588)
        "no-dupe-args": "off", // ts(2300)
        "no-dupe-class-members": "off", // ts(2393) & ts(2300)
        "no-dupe-keys": "off", // ts(1117)
        "no-func-assign": "off", // ts(2539)
        "no-import-assign": "off", // ts(2539) & ts(2540)
        "no-new-symbol": "off", // ts(2588)
        "no-obj-calls": "off", // ts(2349)
        "no-redeclare": "off", // ts(2451)
        "no-setter-return": "off", // ts(2408)
        "no-this-before-super": "off", // ts(2376)
        "no-undef": "off", // ts(2304)
        "no-unreachable": "off", // ts(7027)
        "no-unsafe-negation": "off", // ts(2365) & ts(2360) & ts(2358)
        "no-var": "error", // ts transpiles let/const to var, so no need for vars any more
        "prefer-const": "error", // ts provides better types with const
        "prefer-rest-params": "error", // ts provides better types with rest args over arguments
        "prefer-spread": "error", // ts transpiles spread to apply, so no need for manual apply
        "valid-typeof": "off", // ts(2367)
      },
    },
  ],
}

然后我们故意在代码中,做一些违反规则的代码,然后在 package.json 中的 scripts 增加以下命令:

代码语言:json
复制
{
"scripts": {
    "lint": "eslint --ext .vue,.js,.jsx,.ts,.tsx ./ --max-warnings 0",
    "lint:fix": "eslint --ext .vue,.js,jsx,.ts,.tsx ./ --max-warnings 0 --fix",
 }
}

然后我们在终端中运行命令 pnpm lint 进行验证:

代码语言:shell
复制
 $ pnpm lint                                                                                                  
> eaui@0.0.0 lint /Users/wangyang/Documents/eaui
> eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts ./ --max-warnings 0

/Users/wangyang/Documents/eaui/src/App.vue
  7:7  error  Identifier 't_s' is not in camel case                                           camelcase
  7:7  error  't_s' is assigned a value but never used. Allowed unused vars must match /^_/u  @typescript-eslint/no-unused-vars
  7:7  error  't_s' is assigned a value but never used. Allowed unused vars must match /^_/u  no-unused-vars

✖ 3 problems (3 errors, 0 warnings)

 ELIFECYCLE  Command failed with exit code 1.

很好,现在看来我们配置的 ESlint 规则已经生效,那么我们接下来可以继续配置其他的规则了。

配置Stylelint

在配置之前,我们同样需要安装一些插件,插件列表如下:

stylelinthttps://stylelint.io/

stylelinthttps://www.npmjs.com/package/stylelint

stylelint-config-standardhttps://www.npmjs.com/package/stylelint-config-standard

stylelint-orderhttps://www.npmjs.com/package/stylelint-order

postcss-htmlhttps://www.npmjs.com/package/postcss-html

postcss-lesshttps://www.npmjs.com/package/postcss-less

代码语言:shell
复制
$ pnpm add -D stylelint stylelint-config-standard stylelint-order postcss-html postcss-less

安装完成后,我们先增加一个忽略配置 .stylelintignore ,内容如下:

代码语言:txt
复制
*.min.css

# 其他类型文件
*.js
*.jpg
*.woff

接下来就是正主了,添加配置文件 stylelint.config.js,内容如下:

代码语言:js
复制
export default {
  defaultSeverity: 'error',
  extends: ['stylelint-config-standard'],
  plugins: ['stylelint-less'],
  rules: {
    'no-descending-specificity': null,
    'import-notation': 'string',
    'no-empty-source': null,
    'custom-property-pattern': null,
    'selector-class-pattern': null,
    'selector-pseudo-class-no-unknown': [
      true,
      {
        ignorePseudoClasses: ['deep'],
      },
    ],
    'media-query-no-invalid': null, // https://stylelint.io/user-guide/rules/media-query-no-invalid/#options
  },
  overrides: [
    {
      files: ['**/*.html', '**/*.vue'],
      customSyntax: 'postcss-html',
    },
    {
      files: ['**/*.less'],
      customSyntax: 'postcss-less',
    },
  ],
};

最后在 package.json 中增加以下命令:

代码语言:json
复制
{
   "scripts": {
    "stylelint": "stylelint src/**/*.{html,vue,sass,less}",
    "stylelint:fix": "stylelint --fix src/**/*.{html,vue,vss,sass,less}",
   }
}

同样的,我们在代码中搞一些不符合规则的东西,然后再运行命令检查:

代码语言:shell
复制
$ pnpm stylelint       

> eaui@0.0.0 stylelint /Users/wangyang/Documents/eaui
> stylelint src/**/*.{html,vue,sass,less}


src/components/WelcomeItem.vue
  34:3  ✖  Unexpected empty line before declaration  declaration-empty-line-before
  42:3  ✖  Unexpected empty line before declaration  declaration-empty-line-before

✖ 2 problems (2 errors, 0 warnings)
  2 errors potentially fixable with the "--fix" option.

 ELIFECYCLE  Command failed with exit code 2.

现在再让我们尝试下,运行修复命令看看是否可以正常修复:

代码语言:shell
复制
$  pnpm stylelint:fix       

> eaui@0.0.0 stylelint:fix /Users/wangyang/Documents/eaui
> stylelint --fix src/**/*.{html,vue,css,sass,less}

好了,现在让我们继续开始下面的配置。

配置commitlint

老生常谈了,先安装插件,插件内容如下:

commitlint.jshttps://commitlint.js.org/

conventionalcommitshttps://www.conventionalcommits.org/zh-hans/v1.0.0/

clihttps://github.com/conventional-changelog/commitlint/tree/master/%40commitlint/cli

config-conventionalhttps://github.com/conventional-changelog/commitlint/tree/master/%40commitlint/config-conventional

代码语言:shell
复制
$ pnpm add -D  @commitlint/{cli,config-conventional}

安装完成后,我们来配置一下:

代码语言:shell
复制
echo "export default { extends: ['@commitlint/config-conventional'] };" > commitlint.config.js

为了更好的限制,我们增加下类型枚举,具体的含义建议直接访问 conventionalcommits 进行查看,配置内容如下:

代码语言:js
复制
export default {
  extends: ['@commitlint/config-conventional'],
  rules: {
    'type-enum': [
      2,
      'always',
      ['build', 'chore', 'ci', 'docs', 'feat', 'fix', 'perf', 'refactor', 'revert', 'style', 'test', 'types'],
    ],
  },
};

不过这样好像还不够,接下来我们再通过 commitizen 来进行限制。

配置commitizen

cz-clihttps://commitizen.github.io/cz-cli/

代码语言:shell
复制
$  pnpm add -D commitizen 
$  npx commitizen init cz-conventional-changelog --pnpm --save-dev --save-exact   

好了,接下来要到我们最关键的配置了,husky

配置husky

huskyhttps://github.com/typicode/husky

huskyhttps://www.npmjs.com/package/husky

lint-stagedhttps://github.com/lint-staged/lint-staged

lint-stagedhttps://www.npmjs.com/package/lint-staged

代码语言:shell
复制
$ pnpm add -D husky lint-staged
$ pnpm exec husky init
$ echo "pnpm lint-staged" > .husky/pre-commit  
$ echo "pnpm dlx commitlint --edit \$1" > .husky/commit-msg
$ echo "exec < /dev/tty && npx cz --hook || true" > .husky/prepare-commit-msg

package.json 中增加 lint-staged 的配置,配置内容如下:

代码语言:json
复制
{
 "lint-staged": {
    "*.{js,jsx,vue,ts,tsx}": [
      "prettier --write",
      "pnpm lint:fix"
    ],
    "*.{html,vue,vss,sass,less}": [
      "pnpm stylelint:fix"
    ]
  }
}

测试

现在基本的已经配置完成,我们来进行看看。

代码语言:shell
复制
$ git add .
$ git commit -m "this will fail"

运行结果如下:

代码语言:shell
复制
✔ Preparing lint-staged...
⚠ Running tasks for staged files...
  ❯ package.json — 27 files
    ❯ *.{js,jsx,vue,ts,tsx} — 14 files
      ✔ prettier --write
      ✖ pnpm lint:fix [FAILED]
    ✔ *.{html,vue,vss,sass,less} — 4 files
↓ Skipped because of errors from tasks.
✔ Reverting to original state because of errors...
✔ Cleaning up temporary files...

✖ pnpm lint:fix:

> eaui@0.0.0 lint:fix /Users/wangyang/Documents/eaui
> eslint --ext .vue,.js,jsx,.ts,.tsx ./ --max-warnings 0 --fix "/Users/wangyang/Documents/eaui/.prettierrc.js" "/Users/wangyang/Documents/eaui/commitlint.config.js" "/Users/wangyang/Documents/eaui/e2e/vue.spec.ts" "/Users/wangyang/Documents/eaui/playwright.config.ts" "/Users/wangyang/Documents/eaui/src/App.vue" "/Users/wangyang/Documents/eaui/src/components/HelloWorld.vue" "/Users/wangyang/Documents/eaui/src/components/TheWelcome.vue" "/Users/wangyang/Documents/eaui/src/components/WelcomeItem.vue" "/Users/wangyang/Documents/eaui/src/components/__tests__/HelloWorld.spec.ts" "/Users/wangyang/Documents/eaui/src/main.ts" "/Users/wangyang/Documents/eaui/src/stores/counter.ts" "/Users/wangyang/Documents/eaui/stylelint.config.js" "/Users/wangyang/Documents/eaui/vite.config.ts" "/Users/wangyang/Documents/eaui/vitest.config.ts"


/Users/wangyang/Documents/eaui/src/App.vue
  7:7  error  Identifier 't_s' is not in camel case                                           camelcase
  7:7  error  't_s' is assigned a value but never used. Allowed unused vars must match /^_/u  @typescript-eslint/no-unused-vars
  7:7  error  't_s' is assigned a value but never used. Allowed unused vars must match /^_/u  no-unused-vars

✖ 3 problems (3 errors, 0 warnings)

 ELIFECYCLE  Command failed with exit code 1.
husky - pre-commit script failed (code 1)

从结果来看已经生效了,现在让我们按着提示先把检测出来的问题进行修复,再次运行命令进行查看:

代码语言:shell
复制
$ git add .
$ git commit -m "this will fail"
✔ Preparing lint-staged...
✔ Running tasks for staged files...
✔ Applying modifications from tasks...
✔ Cleaning up temporary files...
cz-cli@4.3.0, cz-conventional-changelog@3.3.0

? Select the type of change that you're committing: feat:     A new feature
? What is the scope of this change (e.g. component or file name): (press enter to skip) 
? Write a short, imperative tense description of the change (max 94 chars):
 (20) code and style rules
? Provide a longer description of the change: (press enter to skip)
 some rules for project 
? Are there any breaking changes? No
? Does this change affect any open issues? No
Packages: +108
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Progress: resolved 108, reused 107, downloaded 1, added 108, done
[main 10f75d9] feat: code and style rules
 29 files changed, 3356 insertions(+), 239 deletions(-)
 create mode 100644 .editorconfig
 create mode 100644 .eslintignore
 create mode 100644 .eslintrc
 delete mode 100644 .eslintrc.cjs
 create mode 100644 .gitattributes
 create mode 100644 .husky/commit-msg
 create mode 100644 .husky/pre-commit
 create mode 100644 .husky/prepare-commit-msg
 create mode 100644 .prettierrc.js
 delete mode 100644 .prettierrc.json
 create mode 100644 .stylelintignore
 create mode 100644 commitlint.config.js
 create mode 100644 stylelint.config.js
 
 $ git push
 
  枚举对象中: 59, 完成.
  对象计数中: 100% (59/59), 完成.
  使用 12 个线程进行压缩
  压缩对象中: 100% (31/31), 完成.
  写入对象中: 100% (36/36), 43.00 KiB | 7.17 MiB/s, 完成.
  总共 36(差异 16),复用 3(差异 0),包复用 0(来自  0 个包)
  remote: Resolving deltas: 100% (16/16), completed with 16 local objects.
  To github.com:oyo-cool/eaui.git
     d4e3320..10f75d9  main -> main

完美,现在我们配置的所有规则都可以通过 husky 来进行触发了。

总结

在这一章里面,我们根据自己的情况配置了git.editorconfigPrettierESlintStylelint

commitlintcommitizenhusky ,在这些规则的约束下能让我们更好的协同,也能写出更好的代码,当然了实际中也需要书面的一些规范约束,不过我们这里不进行展开。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 内容
    • 配置Git
      • 配置规则
        • 配置.editorconfig
        • 配置Prettier
        • 配置ESlint
        • 配置Stylelint
        • 配置commitlint
        • 配置commitizen
        • 配置husky
    • 测试
    • 总结
    相关产品与服务
    项目管理
    CODING 项目管理(CODING Project Management,CODING-PM)工具包含迭代管理、需求管理、任务管理、缺陷管理、文件/wiki 等功能,适用于研发团队进行项目管理或敏捷开发实践。结合敏捷研发理念,帮助您对产品进行迭代规划,让每个迭代中的需求、任务、缺陷无障碍沟通流转, 让项目开发过程风险可控,达到可持续性快速迭代。
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档