使用Lint工具“武装”你的项目

avatar
前端组件库 @华为

DevUI是一支兼具设计视角和工程视角的团队,服务于华为云DevCloud平台和华为内部数个中后台系统,服务于设计师和前端工程师。
官方网站:devui.design
Ng组件库:ng-devui(欢迎Star)
官方交流:添加DevUI小助手(devui-official)
DevUIHelper插件:DevUIHelper-LSP(欢迎Star)

砰砰砰砰.png

引言

通过静态检查工具来规范自己项目的代码,让团队所有成员保持一致的编码风格,这样大家可以专注于核心特性的开发,提升整体开发效率。

以下将对DevUI组件库使用的各种lint工具进行介绍,并说明如何在代码提交阶段进行统一格式检查与修正。

通过阅读这篇指南,希望你也可以使用这些Lint工具来“武装”自己的项目。

DevUI组件库lint一致性主要使用以下工具保证:

  • prettier
  • tslint
  • stylelint
  • commitlint

在开始前,你可在项目目录下新建各lint配置文件:

/YourProject
├── ...
├── .prettierrc
├── tslint.json
├── .stylelintrc.json
├── .vscode
|  ├── extensions.json
|  └── settings.json
└── commitlint.config.js

1 文件基本格式约束 - prettier

Prettier的中文意思是“漂亮的、机灵的”,也是一个流行的代码格式化工具的名称,它能够解析代码,使用你自己设定的规则来重新打印出格式规范的代码。

Prettier具有以下几个有优点:

  1. 可配置化
  2. 支持多种语言
  3. 集成多数的编辑器
  4. 简洁的配置项

使用Prettier在code review时不需要再讨论代码样式,节省了时间与精力。

安装prettier:

npm i -D prettier

配置.prettierrc文件。

prettier配置参考

// 注释为对对应规则注释,复制到项目中可删除
{
  "tabWidth": 2, // 设定每个缩进为2个空格
  "semi": true, // 在语句末尾添加分号
  "singleQuote": true, // 使用单引号
  "jsxSingleQuote": true,
  "bracketSpacing": true, // 在括号间打印空格
  "jsxBracketSameLine": true, // 把多行'>'放在最后一行的末尾,而不是另起一行放置
  "printWidth":140, // 行长超过140将会换行
  "endOfLine": "auto",
  "proseWrap": "preserve",
  "trailingComma": "es5",
  "useTabs": false
}

2 TS格式约束 — tslint

TSLint 是一个开源 TypeScript 代码风格检查器,它能够在可读性、可维护性、代码正确性等方面为开发者提供帮助。TSLint 被广泛用于各种前端构建工具和编辑器中。

在编写代码时,编译器会根据 TSLint 抛出高亮提示,在代码编译时,编译工具可以运行 TSLint 然后及时抛出错误阻断编译的继续,防止不符合规范的代码进入生产环境。

安装tslint:

npm i -D tslint codelyzer

配置tslint.json文件。

tslint配置参考

{
  "rulesDirectory": [
    "node_modules/codelyzer"
  ],
  "rules": {
    "arrow-return-shorthand": true, // 将()=>{return x}转换为()=>x
    "callable-types": true, // 可以将仅带有调用签名的接口或文字类型编写为函数类型
    "class-name": true, // 强制使用PascalCased类和接口名称
    "comment-format": [
      true,
      "check-space"
    ],           // 单行的评论前必须有一个空格
    "curly": true,  // 对于if/for/do/while语句强制需要花括号
    "deprecation": {
      "severity": "warn"
    },           // 使用了不推荐的APIs时发出警告
    "eofline": true, // 文件已换行符结尾
    "forin": true,  // 使用for..in语句过滤if语句
    "import-blacklist": [
      true,
      "rxjs/Rx"
    ],        // 导入黑名单,禁止直接导入rxjs/Rx,仅需导入所需的子模块
    "import-spacing": true, // import 的关键字之间添加空格
    "indent": [
      true,
      "spaces"
    ],       // 使用空格强制缩进
    "interface-over-type-literal": true, // 使用接口定义而不是(type T = { ... })
    "label-position": true, // 只允许将label放在合适的位置
    "max-line-length": [
      true,
      140
    ],              // 行长超过140之后换行
    "member-access": false, // 不需要类成员的显式可见性声明
    "member-ordering": [   // 对类成员的排序,使类更容易阅读、导航和编辑
      true,
      {
        "order": [
          "static-field",
          "instance-field",
          "static-method",
          "instance-method"
        ]
      }
    ],
    "no-arg": true, // 不允许使用arguments.callee
    "no-bitwise": true, // 不允许使用位运算符
    "no-console": [
      true,
      "debug",
      "info",
      "time",
      "timeEnd",
      "trace"
    ],          // 列出不允许使用的console方法
    "no-construct": true, // 不允许使用String,Number,Boolean构造函数
    "no-debugger": true, // 不允许使用debugger语句
    "no-duplicate-super": true, // super在一个构造函数中出现两次则发出警告
    "no-empty": false, // 允许使用空代码块
    "no-empty-interface": true, // 不允许使用空接口
    "no-eval": true,  // 不允许使用eval函数
    "no-inferrable-types": [
      true,
      "ignore-params"
    ], // 不允许对初始化为数字,字符串或布尔值的变量或参数进行显式类型声明,允许为函数参数指定不可推断的类型注释
    "no-misused-new": true, // 为接口或new类定义构造函数时发出警告
    "no-non-null-assertion": true,// 不允许使用!后缀运算符进行非null断言
    "no-redundant-jsdoc": true, // 禁止JSDoc复制TypeScript功能
    "no-shadowed-variable": true, // 禁止阴影变量声明
    "no-string-literal": false, // 允许使用obj["property"]方式获取对象属性
    "no-string-throw": true,  // 不允许直接throw字符串
    "no-switch-case-fall-through": true, // 不允许case语句下降
    "no-trailing-whitespace": true, // 不允许行尾尾随空格
    "no-unnecessary-initializer": true, // 不允许使用let时初始化值为undefined
    "no-unused-expression": true, // 不允许出现未使用的表达式
    "no-use-before-declare": true, // 不允许使用未声明的变量
    "no-var-keyword": true, // 不允许使用var关键字
    "object-literal-sort-keys": false, // 不对对象中的属性关键字排序
    "one-line": [
      true,
      "check-open-brace",
      "check-catch",
      "check-else",
      "check-whitespace"
    ],  // 要求指定的标记与它们之前的表达式位于同一行
    "prefer-const": true, // 尽量使用const而不是let
    "quotemark": [
      true,
      "single"
    ], // 强制字符串使用单引号
    "radix": true, // 使用parseInt时需要制定radix参数
    "semicolon": [
      true,
      "always"
    ],  // 句尾使用分号
    "triple-equals": [
      true,
      "allow-null-check"
    ], // 使用'==='和'!=='做判断,允许使用'=='和'!='判断null
    "typedef-whitespace": [
      true,
      {
        "call-signature": "nospace",
        "index-signature": "nospace",
        "parameter": "nospace",
        "property-declaration": "nospace",
        "variable-declaration": "nospace"
      }
    ], // 不允许为上述列出的类型定义使用空格
    "unified-signatures": true, // 当两个函数可以使用rest等方法合并时,发出警告
    "variable-name": false, // 不检查变量命名格式
    "whitespace": [
      true,
      "check-branch",
      "check-decl",
      "check-operator",
      "check-separator",
      "check-type",
      "check-module",
      "check-type-operator"
    ], // 设置空格的风格
    "no-output-on-prefix": true, // 命名事件不带前缀
    "use-input-property-decorator": true, 
    "use-output-property-decorator": true,
    "use-host-property-decorator": true, // 使用@HostProperty装饰器而不是@Component和@Directive元数据的host属性
    "no-input-rename": true, // 通过提供字符串给装饰器禁止重命名指令输入
    "no-output-rename": true,// 通过提供字符串给装饰器禁止重命名指令输出
    "use-life-cycle-interface": true, // 确保implement生命周期接口之后再使用
    "use-pipe-transform-interface": true,// 确保使用@Pipe装饰器实现PipeTransform接口
    "component-class-suffix": true,// 用@Component装饰的类必须带有Component后缀
    "directive-class-suffix": true // 用@Directive装饰的类必须带有Directive后缀
  }
}

3 css/scss格式约束 - stylelint

stylelint 是一个强大和现代的 CSS 审查工具,有助于开发者推行统一的代码规范,避免样式错误。

stylelint 由 PostCSS 提供技术支持,所以它也可以理解 PostCSS 解析的语法,比如 SCSS。

安装stylelint:

npm i -D stylelint stylelint-config-recommended-scss stylelint-config-standard

配置.stylelintrc.json。

stylelint-config-standard规则参考

stylelint-config-recommended规则参考

{
  "extends": ["stylelint-config-standard", "stylelint-config-recommended-scss"],
  "plugins": ["stylelint-scss"],
  "rules": {
    "string-quotes": "single",
    "property-no-unknown": true,
    "selector-pseudo-class-no-unknown": true,
    "at-rule-empty-line-before": [
      "always",
      {
        "except": ["blockless-after-same-name-blockless", "first-nested", "inside-block"],
        "ignore": ["after-comment", "first-nested"]
      }
    ],
    "rule-empty-line-before": [
      "always",
      {
        "except": ["after-single-line-comment", "first-nested"]
      }
    ],
    "block-no-empty": true,
    "selector-pseudo-element-no-unknown": [
      true,
      {
        "ignorePseudoElements": ["ng-deep"]
      }
    ],
    "selector-type-no-unknown": [
      true,
      {
        "ignoreTypes": ["/^d-/"]
      }
    ],
    "color-hex-length": "long",
    "no-descending-specificity": null,
    "font-family-no-missing-generic-family-keyword": null,
    "no-duplicate-selectors": null,
    "declaration-block-no-duplicate-properties": [
      true,
      {
        "ignore": ["consecutive-duplicates"]
      }
    ]
  }
}

4 git message约束 - commitlint

和 Tslint 一样的是,commitlint 自身只提供了检测的功能和一些最基础的规则。使用者需要根据这些规则配置出自己的规范。

对于 Conventional Commits 规范,社区已经整理好了 @commitlint/config-conventional 包,我们只需要安装并启用它就可以了。

安装commitlint:

npm i -D @commitlint/cli @commitlint/config-conventional

配置commitlint.config.js:

const types = ['feat', 'fix', 'docs', 'style', 'refactor', 'perf', 'test', 'build', 'release', 'chore', 'revert'];

module.exports = {
  extends: ['@commitlint/config-conventional'],
  rules: {
    'type-empty': [2, 'never'],
    'type-enum': [2, 'always', types],
    'scope-case': [0, 'always'],
    'subject-empty': [2, 'never'],
    'subject-case': [0, 'never'],
    'header-max-length': [2, 'always', 88],
  },
};

配置以上lint后,即可对提交message进行约束。

message格式参考

5 配置npm script

我们若要进行修正格式命令配置,则需在package.json中配置对应命令。

package.json 对scripts:

{
 ...
 "scripts": {
    ...
    "lint:devui": "tslint -p devui/tsconfig.lint.json -c devui/tslint.json \"devui/**/*.ts\"",
    "lint:devui:fix": "tslint --fix -p devui/tsconfig.lint.json -c devui/tslint.json \"devui/**/*.ts\"",
    "prettier": "prettier --config ./.prettierrc --write \"{devui,src}/**/*.html\"",
    "stylelint": "stylelint \"{devui,src}/**/*.{scss,css}\"  --fix",
    ...
  },
 ...
 }

配置后即可使用如npm run lint:devui进行文件lint自动修正。

6 配置git 提交代码自动修正

我们要在git提交阶段对暂存区代码进行自动修正,可以通过配置git 钩子关联(可参考Git 钩子),首先我们需要安装:

npm i -D lint-staged husky

lint-staged可以使我们在暂存区上运行lint命令,仅对需要提交的内容进行格式化操作。

husky可以让我们关联git钩子,并执行需要的命令操作。

  1. package.json中添加lint-staged项:
{
...
"lint-staged": {
    "devui/**/*.ts": [
      "tslint --fix -p devui/tsconfig.lint.json -c devui/tslint.json \"*.ts\"",
      "git add"
    ],
    "src/**/*.ts": [
      "tslint --fix  -c src/tslint.json \"*.ts\"",
      "git add"
    ],
    "{devui,src}/**/*.html": [
      "prettier --config ./.prettierrc --write",
      "git add"
    ],
    "{devui,src}/**/*.{scss,css}": [
      "stylelint --fix",
      "git add"
    ]
  },
...
}
  1. package.json中husky添加lint-staged关联:
{
...
"husky": {
    "hooks": {
      "commit-msg": "commitlint -E HUSKY_GIT_PARAMS && node ./scripts/commit-lint/commit-lint.js HUSKY_GIT_PARAMS",
      "pre-commit": "lint-staged"
     }
  },
...
}

以上配置完成,即可在git代码提交阶段对.ts等文件进行自动格式修正与错误拦截。

7 为VSCode进行项目统一配置

VSCode提供了对项目进行统一设置能力,只需在.vscode目录下书写对应配置项即可。

配置.vscode/extensions.json,设置统一插件:

{
	// See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations.
	// Extension identifier format: ${publisher}.${name}. Example: vscode.csharp
	// List of extensions which should be recommended for users of this workspace.
	"recommendations": [
		/*使用最新版VSCODE,打开项目后右下角有提示安装所有插件,左侧插件栏目有列出工作空间插件*/
		/*Angular开发神器*/
		"angular.ng-template",
		/*Angular,typescript, html等语法填充*/
		"mikael.angular-beastcode",
		/*DevUI组件库悬停提示,自动补全插件*/
		"sspkudevui.devuihelper",
		/*检查代码中的单词拼写是否有误*/
		"streetsidesoftware.code-spell-checker",
		/*ts静态检查*/
		"ms-vscode.vscode-typescript-tslint-plugin",
		/*style静态检查,初期暂不要求*/
		"stuartzhang.stylelint-stzhang",
		/*彩色括号配对*/
		"coenraads.bracket-pair-colorizer-2",
		/*代码中出现git修改记录*/
		"eamodio.gitlens",
		/*markdown检查*/
		"davidanson.vscode-markdownlint",
		/*重复代码检测*/
		"paulhoughton.vscode-jscpd",
		/*中文包*/
		"ms-ceintl.vscode-language-pack-zh-hans"
	],
	// List of extensions recommended by VS Code that should not be recommended for users of this workspace.
	"unwantedRecommendations": []
}

配置.vscode/settings.json,配置当前项目设置:

{
    "jscpd.files":"devui/*/*",
    "editor.codeActionsOnSave": {
        "source.organizeImports": true  // 对各import进行格式化
    }
}

小结

本文介绍了ng-devui组件库如何进行项目lint格式约束,介绍了当前使用的各lint工具,以及如何通过关联,设置git提交门禁与格式自动修复。

更多地,如果你使用VSCode,提供了对项目进行VSCode进行统一配置参考。

通过本文中提供方法与步骤,即可让你的项目具备lint一致性约束能力。

注:

  • 本文中提及的TSLint工具已停止更新,当前更加建议使用ESLint,ng-devui也已在进行切换。

  • ng-devui package.json 完整参考:github.com/DevCloudFE/…

加入我们

我们是DevUI团队,欢迎来这里和我们一起打造优雅高效的人机设计/研发体系。招聘邮箱:muyang2@huawei.com

文/DevUI 砰砰砰砰

往期文章推荐

《跟着华为DevUI开源组件库学写单元测试用例》

《现在开始为你的Angular应用编写测试(二)》

《在瀑布下用火焰烤饼:三步法助你快速定位网站性能问题(超详细)》