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.jsonbin 字段指定命令入口

  • 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 EditorCommand Line/pre-commit hookDev-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 以及断言的话)

关于规范
https://www.hzhi.top/posts/basic/about-standard/
作者
Jim的独立博客
发布于
2024-10-25
许可协议
CC BY-NC-SA 4.0