1027 字
5 分钟
关于规范
叠甲
个人习惯,非最佳实践,非强制要求
当讨论规范的时候在讨论什么
讨论规范的时候一般指以下:
- style format(特指 prettier)
- linter(特指 ESLint)
- static type(特指 TypeScript)
- naming
- file structure
- misc…
会有什么工具链在什么环境处理与规范相关的事情
- git hook
- 项目命令/内部脚本
- IDE/文本编辑器的插件
- 开发服务器(构建工具)的插件
- CI
git hook
需要本地修改仓库 .git/hooks 目录下的脚本文件,不能同步到其他人的工作区。
ll .git/hookstotal 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 以及断言的话)