前言
最近,进入新公司的架构部,日常开发中,涉及到挺多的 cli 项目。在开发的过程中发现,大家觉得 cli 的项目比较小的,时间也比较赶,都是随手创建一个项目,直接开发。对于代码规范,提交规范,这些都没有去处理。有时觉得使用 ts 比较好,也不想花时间搭建环境。做为一个乐于帮助团队的程序猿,帮助大家搭建一个基础项目模板还是很乐意,也挺有成就感。大家思考一下自己的团队是否也缺少这样的项目模板,动手起来吧。
搭建项目
初始化项目
首先在 github 或 公司私有 gitlab 上创建一个仓库,然后 clone 到本地。
git clone https://github.com/LBINGXIN/ts-cli-template.git
进入 ts-cli-template 目录中,执行 yarn init (可以在后面添加-y
跳过询问的信息) 初始化 package.json 文件
yarn init -y
安装 typescript 依赖
yarn add typescript -D
执行 npx tsc --init,初始化 tsconfig.json
npx tsc --init
生成 tsconfig.json 含有大量被注释的配置, 并且含有注释
根据注释和官方文档,选择保留我们需要的配置就行:
{
"compileOnSave": true, // 让IDE在保存文件的时候根据tsconfig.json重新生成文件
"compilerOptions": {
"target": "ES2018", // 指定 ECMAScript 目标版本
"module": "commonjs", // 指定生成哪个模块系统代码:"None","CommonJS" "AMD","System", "UMD","ES6"或"ES2015"
"moduleResolution": "node", // 决定如何处理模块。或者是"Node"对于Node.js/io.js,或者是"Classic"(默认)
"experimentalDecorators": true, // 启用实验性的ES装饰器
"emitDecoratorMetadata": true, // 给源码里的装饰器声明加上设计类型元数据
"inlineSourceMap":true, // 生成单个sourcemaps文件,而不是将每sourcemaps生成不同的文件
"noImplicitThis": true, // 当 this表达式的值为 any类型的时候,生成一个错误
"noUnusedLocals": true, // 若有未使用的局部变量则抛错
"stripInternal": true, // 不对具有 /** @internal */ JSDoc注解的代码生成代码
"pretty": true, // 给错误和消息设置样式,使用颜色和上下文
"declaration": true, // 生成相应的 .d.ts文件
"outDir": "lib", // 重定向输出目录
"baseUrl": "./", // 解析非相对模块名的基准目录
"paths": { // 模块名到基于 baseUrl的路径映射的列表
"*": ["src/*"]
}
},
"exclude": [ // 排除编译文件
"lib",
"node_modules"
]
}
使用 typescript, 当然少不了 @types/node 依赖包,这个包包含 Node.js ( nodejs.org/ ) 的类型定义。
yarn add @types/node -D
安装 ts-node-dev 依赖包,当文件发生变化时,自动重新编译。
yarn add ts-node-dev -D
在 package.json 添加脚本命令, 开发时,执行 yarn dev 或 npm run dev 即可
"scripts": {
"dev": "ts-node-dev --respawn --transpile-only src/index.ts"
}
代码规范
为什么需要代码规范
- 提高代码整体的可读性、可维护性、可复用性
- 保证代码风格的一致性
- 提升团队整体效率
Eslint + Prettier
这个项目模板主要用来开发 cli 类的 npm 包,纯 js, 不涉及到样式,所以这两个就够了。
Eslint 作用
JavaScript 是一个动态的弱类型语言,在开发中比较容易出错。因为没有编译程序,为了寻找 JavaScript 代码错误通常需要在执行过程中不断调试。像 ESLint 这样的可以让程序员在编码的过程中发现问题而不是在执行的过程中。帮助我们提高开发效率。
Eslint 使用
Eslint 所有规则都是可插拔的,给了足够的自由性,每个团队有自己的代码规范。同时也出现很多很优秀的开源规范,比如 eslint-config-airbnb、eslint-config-alloy、eslint-config-standard 等等,cli 项目不是很复杂,我就采用 slint-config-standard 规范,使用方式:
npx eslint --init
- 选择“使用流行的风格指南”。
- 选择“标准”。
- 选择配置文件格式。
- 如果出现提示,请确认安装必要的依赖项。
npx eslint --init
根据自己的需求,选择对应的配置选项。
执行完毕,会在根目录下自动生成 .eslintrc.js, 对应内容如下:
module.exports = {
"env": {
"browser": true,
"es2021": true,
"node": true
},
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": "latest",
"sourceType": "module"
},
"plugins": [
"@typescript-eslint"
],
"rules": {
}
}
接下来在 package.json 添加命令, 执行 npm run eslint, 会对 src 目录下后缀为 .ts 的文件进行自动修复,不接受警告类型错误。
"scripts": {
"eslint": "eslint --fix src --ext .ts --max-warnings=0"
}
Prettier
Prettier 是什么
Prettier 根据官方解释,是一个“有态度”的代码格式化工具,支持大量编程语言格式化,包含:
- JavaScript (including experimental features)
- JSX
- Angular
- Vue
- Flow
- TypeScript
- CSS, Less, and SCSS
- HTML
- JSON
- GraphQL
- Markdown, including GFM and MDX
- YAML
为什么需要 Prettier
- ESLint:代码检测工具;可以检测出你代码中潜在的问题,比如使用了某个变量却忘记了定义;
- Prettier:代码格式化工具;作为代码格式化工具,能够统一你或者你的团队的代码风格。
- 使用 ESLint 与 eslint-plugin-prettier 的结果是最终得到的代码是充分尊重 Prettier 的结果,而 prettier-eslint-cli 则是先执行 Prettier 然后再自动使用 eslint --fix 将与 ESLint 规则冲突的代码修正成 ESLint 想要的结果。这样其实引入 Prettier 不会影响你原有的设置。
Prettier 使用
安装 prettier
yarn add prettier -D
在根目录新建 .prettierrc.js,配置如下:
module.exports = {
// 一行最多 80 字符
printWidth: 80,
// 使用 2 个空格缩进
tabWidth: 2,
// 不使用 tab 缩进,而使用空格
useTabs: false,
// 行尾需要有分号
semi: true,
// 使用单引号代替双引号
singleQuote: true,
// 对象的 key 仅在必要时用引号
quoteProps: 'as-needed',
// jsx 不使用单引号,而使用双引号
jsxSingleQuote: false,
// 末尾使用逗号
trailingComma: 'all',
// 大括号内的首尾需要空格 { foo: bar }
bracketSpacing: true,
// jsx 标签的反尖括号需要换行
jsxBracketSameLine: false,
// 箭头函数,只有一个参数的时候,也需要括号
arrowParens: 'always',
// 每个文件格式化的范围是文件的全部内容
rangeStart: 0,
rangeEnd: Infinity,
// 不需要写文件开头的 @prettier
requirePragma: false,
// 不需要自动在文件开头插入 @prettier
insertPragma: false,
// 使用默认的折行标准
proseWrap: 'preserve',
// 根据显示样式决定 html 要不要折行
htmlWhitespaceSensitivity: 'css',
// 换行符使用 lf
endOfLine: 'lf'
}
接下来在 package.json 添加命令, 执行 npm run prettier, 会对 src 目录下后缀为 .ts 的文件进行代码格式。
scripts: {
"prettier": "prettier --write \"src/**/*.ts\""
}
在 vscode 中使用
截至目前,需要手动运行命令 npm run eslint、npm run prettier 才能对代码进行格式化,还是挺麻烦的,也不是人人都会去手动执行,所以我们可以借助 vscode 插件,实现保存时自动格式化代码。
安装 Eslint 和 Prettier 插件
在 setting.json 配置如下内容,可以保存时自动格式化。
{
"files.eol": "\n",
"editor.tabSize": 2,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"eslint.validate": [
"javascript",
"javascriptreact",
"vue",
"typescript",
"typescriptreact"
],
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
"editor.formatOnSave": true
}
这些配置目前只存在自己的 vscode, 我们可以将这些配置集成到我们的项目里面,让团队也能快速拥有跟自己一样的配置。在根目录创建 .vscode 文件夹,创建 settings.json 和 extensions.json, 并做相应配置。
settings.json 代码保存自动化,配置跟上面一致
extensions.json vscode 插件推荐
{
"recommendations": ["dbaeumer.vscode-eslint", "esbenp.prettier-vscode"]
}
可以通过,插件筛选查看推荐安装的插件
commitlint
git 的代码提交规范也是不可或缺的。清晰规范的 git 提交记录,可以保存我们的更改记录,对于代码回退,团队的 code Review 也是有益的,同时后续也能速生成开发日志,从某一方面提供的团队的开发效率,增强了代码的可维护性。
安装 commitlint 工具 和 conmmitlint 常用配置。
yarn add @commitlint/cli @commitlint/config-conventional -D
在项目根目录下新建 commitlint.config.js 并设置校验规则
module.exports = {
extends: ['@commitlint/config-conventional']
};
@commitlint/config-conventional 验证提交是否满足Angular 规范,具体规范可查看阮一峰老师的这篇文章 《Commit message 和 Change log 编写指南》-阮一峰,以下是常用的 type 标识。
- feat: 新功能(feature)
- fix: 修补 bug
- docs: 文档(documentation)
- style: 格式(不影响代码运行的变动)
- refactor: 重构(即不是新增功能,也不是修改bug的代码变动)
- test: 增加测试
- perf: 优化相关
- chore: 构建过程或辅助工具的变动
commitizen
考虑到有些人不熟悉 Angular 规范 ,可能需要频繁的去查看文档,有点繁琐,可以借助 commitizen, 提供一个可视化界面,用户根据选项一步一步操作就可以了。
commitizen 配置根据 文档 操作就可以了。
npx commitizen init cz-conventional-changelog --yarn --dev --exact
初始化时主要做了三件事:
- 在项目中安装 cz-conventional-changelog 适配器依赖
- 将适配器依赖保存到 package.json 的 devDependencies 对象中
- 在 package.json 中新增 config.commitizen 字段,主要用于配置 cz 工具的适配器路径
{
"devDependencies": {
"cz-conventional-changelog": "^3.3.0"
},
"config": {
"commitizen": {
"path": "./node_modules/cz-conventional-changelog"
}
}
}
然后在 package.json 的 scripts 中增加如下内容
"scripts": {
"commit": "cz"
}
提交代码时,git commit 改成 yarn commit;
根据选项和提示,选择和输入,即可得到符合规范的 commit message;
生成提交日志
安装 conventional-changelog-cli
yarn global add conventional-changelog-cli
然后在 package.json 的 scripts 中增加如下内容
{
"scripts": {
"changelog": "conventional-changelog -p angular -i CHANGELOG.md -s"
}
}
执行 yarn changelog 会在根目录下生成 CHANGELOG.md,包含提交日志,跟版本号挂钩
husky@8 和 lint-staged
目前我们虽然实现了代码规范,git 提交规范,但这都是需要成员去遵守才行,总有人不想去遵守我们的规范,所以我们还需要提供一个拦截器,不符合规范,就没办法提交代码。husky 和 lint-staged 就是为我们提供 git 提交拦截作用。
husky 帮助我们更好的实现 git 的钩子。 lint-staged 对暂存的 git 文件运行 linter
安装 husky 和 lint-staged
yarn add husky lint-staged -D
package.json 添加 lint-staged 配置
"lint-staged": {
"*.ts": [
"npm run eslint",
"npm run prettier"
]
}
package.json 添加命令
scripts: {
"prepare": "husky install"
}
执行 yarn prepare,会在根目录下生成 .husky 文件夹
yarn prepare
生成 git 提交前的钩子文件,执行 lint-staged,自动执行 npm run eslint 和 npm run prettier
npx husky add .husky/pre-commit "npx --no-install lint-staged"
生成 git message 检测钩子,执行 commitlint
npx husky add .husky/commit-msg "npx --no-install commitlint --edit $1"
现在就具有 git 提交的拦截功能,每次提交都会去触发 pre-commit 钩子, 执行 lint-staged 从而执行到我们配置的 npm run eslint 和 npm run prettier 去做代码质量检测和代码格式化,也会触发 commit-msg 钩子,去执行 commitlint, 去检测提交的 commit message 是否规范。
构建
在 package.json 中添加如下内容:
scripts: {
"build": "npm run eslint && npm run prettier && rm -rf lib && tsc --build"
}
执行 npm run build
命令,实现项目构建,构建结果输出到 lib 目录中
小结
通过如上配置,一个符合我们开发 cli 或者 npm 包的项目模板已经算是实现完成了,该项目模板提交到 github
下一步就是实现一个脚手架工具来拉取我们的项目模板,实现方式可以看以下我写的这篇文章
搭建从git拉取项目模板的脚手架 ts-cli,并且发布到 npm