1027 字
5 分钟
关于规范
叠甲
个人习惯,非最佳实践,非强制要求
当讨论规范的时候在讨论什么
讨论规范的时候一般指以下:
- style format(特指 prettier)
- linter(特指 ESLint)
- static type(特指 TypeScript)
- naming
- file structure
- misc…
会有什么工具链在什么环境处理与规范相关的事情
- git hook
- 项目命令/内部脚本
- IDE/文本编辑器的插件
- 开发服务器(构建工具)的插件
- CI
git hook
需要本地修改仓库 .git/hooks
目录下的脚本文件,不能同步到其他人的工作区。
ll .git/hooks
total 120
-rwxr-xr-x 1 kitsch staff 478B May 11 14:55 applypatch-msg.sample
-rwxr-xr-x 1 kitsch staff 896B May 11 14:55 commit-msg.sample
-rwxr-xr-x 1 kitsch staff 4.6K May 11 14:55 fsmonitor-watchman.sample
-rwxr-xr-x 1 kitsch staff 189B May 11 14:55 post-update.sample
-rwxr-xr-x 1 kitsch staff 424B May 11 14:55 pre-applypatch.sample
-rwxr-xr-x 1 kitsch staff 1.6K May 11 14:55 pre-commit.sample
-rwxr-xr-x 1 kitsch staff 416B May 11 14:55 pre-merge-commit.sample
-rwxr-xr-x 1 kitsch staff 1.3K May 11 14:55 pre-push.sample
-rwxr-xr-x 1 kitsch staff 4.8K May 11 14:55 pre-rebase.sample
-rwxr-xr-x 1 kitsch staff 544B May 11 14:55 pre-receive.sample
-rwxr-xr-x 1 kitsch staff 1.5K May 11 14:55 prepare-commit-msg.sample
-rwxr-xr-x 1 kitsch staff 2.7K May 11 14:55 push-to-checkout.sample
-rwxr-xr-x 1 kitsch staff 3.6K May 11 14:55 update.sample
引入 husky 通过修改 core.hookspath
的配置重定向配置路径到仓库跟踪的 .husky
目录来同步 hook 脚本。
git config --local --list
# ...
core.hookspath=.husky
# ...
每次都全量 lint 或者 format 不合理,引入 lint-staged 仅对工作区的文件进行上述两个操作。
lint-staged 不同声明方式
// 在 `package.json` 中声明
{
"lint-staged": {
"*.{ts,svelte}": "eslint --fix --max-warnings=0",
"*.{ts,js,css,md,html,svelte}": "prettier --write"
}
}
// 通过 `.lintstagedrc.mjs` 声明
import { ESLint } from "eslint";
const removeIgnoredFiles = async (files) => {
const eslint = new ESLint();
const isIgnored = await Promise.all(
files.map((file) => eslint.isPathIgnored(file))
);
const filteredFiles = files.filter((_, i) => !isIgnored[i]);
return filteredFiles.join(" ");
};
export default {
"**/*.{ts,svelte}": async (files) => {
const filesToLint = await removeIgnoredFiles(files);
return [`eslint --max-warnings=0 ${filesToLint}`];
},
"*.{ts,js,css,md,html,svelte}": "prettier --write",
};
项目命令/内部脚本
依赖包通过 package.json
的 bin
字段指定命令入口
- tsc
- prettier
- eslint
- …
举些 🌰
- 直接写 Node.js 脚本供手动调用,如 rtc-connect 项目的
version.js/publish.js
用于约束版本与发布 - 内部脚本供 lint-stage 调用,如 oasis 项目的
update-change-log/init-slug
用于更新变更记录、变化 slug 等流程自动化 - 内部 package 注册 bin 供 workspace 调用,如 aigc 项目的 emit-dts 包用于构建流程中生成 svelte 组件的类型文件
- …
IDE/文本编辑器的插件
让协作成员感受相同的开发体验才是规范
extensions.json/settings.json
提供插件建议以及配置偏好
{
"eslint.validate": ["svelte"],
"typescript.tsdk": "node_modules/typescript/lib",
"svelte.plugin.svelte.compilerWarnings": {
"a11y-click-events-have-key-events": "ignore",
"a11y-aria-attributes": "ignore",
"a11y-incorrect-aria-attribute-type": "ignore",
"a11y-unknown-aria-attribute": "ignore",
"a11y-hidden": "ignore",
"a11y-misplaced-role": "ignore",
"a11y-unknown-role": "ignore",
"a11y-no-abstract-role": "ignore",
"a11y-no-redundant-roles": "ignore",
"a11y-role-has-required-aria-props": "ignore",
"a11y-accesskey": "ignore",
"a11y-autofocus": "ignore",
"a11y-misplaced-scope": "ignore",
"a11y-positive-tabindex": "ignore",
"a11y-invalid-attribute": "ignore",
"a11y-missing-attribute": "ignore",
"a11y-img-redundant-alt": "ignore",
"a11y-label-has-associated-control": "ignore",
"a11y-media-has-caption": "ignore",
"a11y-distracting-elements": "ignore",
"a11y-structure": "ignore",
"a11y-mouse-events-have-key-events": "ignore",
"a11y-missing-content": "ignore",
"a11y-no-static-element-interactions": "ignore"
}
}
开发服务器(构建工具)的插件
IDE 插件影响了个体编码的体验,而开发服务器插件影响项目所有成员的编码体验
一个简单案例
export default {
input: "src/index.ts",
output: [
{
file: "build/bundle.js",
format: "cjs",
name: "Vesperia",
},
],
external: [],
plugins: [
eslint({ throwOnWarning: true, throwOnError: true }),
svelte({
// transpile ts to js in .svelte file
preprocess: sveltePreprocess(),
emitCss: false,
onwarn: (warning, handler) => {
if (warning.code.indexOf("a11y-") !== -1) {
return;
}
handler(warning);
},
}),
resolve({ browser: true, dedupe: ["svelte"] }),
commonjs(),
// ts transpiler
typescript({ sourceMap: false }),
/**
* .svelte =sveltePreprocess=> es6+ =babel=> traget
* .ts =typescript=> es6 =babel=> target
* .mjs(svelte API from node_modules) =babel=> target
*/
babel({ extensions: [".ts", ".mjs", ".svelte"], babelHelpers: "bundled" }),
],
};
CI
开放命题
在不同环境中应用的态度
IDE/Text Editor | Command Line/pre-commit hook | Dev-Server(moduler bundler) | Continuous Integration | |
---|---|---|---|---|
style format | 😐 中立 | 😀 必须 | ☹️ 不建议 | ☹️ 不建议 |
linter | 🙂 建议 | 😀 必须 | 😐 中立 | 😐 不建议 |
static type check | 😀 必须 | 🙂 建议 | 🙂 建议 | 😐 中立 |
linter:推荐在 hook 中 block 非规范代码并启用 IDE 插件,开发服务器集成容易阻断开发思路,持中立态度
style format:仅在 hook 中自动格式化,IDE 插件看个人习惯
static type check:推荐启用 IDE 插件(VSCode 默认),开发服务器或者命令行看适合选择一个即可
规范的收益
style format:“你也不想看到格式混乱的代码吧.jpg”
linter:能帮助非经验开发能快速避开调试黑洞,建议非经验开发能多查看 rule 原因
static type check:极大降低代码理解成本,重构成本以及对调试的依赖(不随意声明 any 以及断言的话)