如何在 lerna monorepo 中使用 lint-staged 来 运行 所有包中的相同命令?

How to use lint-staged in a lerna monorepo to run the same command in all packages?

我有以下根 package.json:

{
  "name": "project",
  "private": true,
  "workspaces": [
    "packages/*"
  ],
  "scripts": {
    "build": "lerna run build",
    "dev": "lerna run start --stream --parallel",
    "format": "yarn prettier --write",
    "prettier": "prettier --ignore-path .gitignore \"**/*.+(ts|tsx|json)\"",
    "test": "lerna run test --"
  },
  "husky": {
    "hooks": {
      "pre-commit": "yarn format && yarn test"
    }
  },
  "devDependencies": {
    "husky": "^4.2.5",
    "lerna": "^3.22.1",
    "prettier": "^2.0.5"
  }
}

问题是使用此设置,当我仍在处理文件时无法提交,要解决此问题,我可以使用 lint-staged 模块,我的问题是,如何设置它以便我目前的命令仍然 运行 但仅在暂存文件上没有在每个项目中安装命令的所有依赖项?测试命令也可能是一个问题,因为它在每个项目中 运行s tsc --noEmit,我可以强制它也只检查暂存文件吗?

对此有一个替代解决方案,因为截至目前,lint-staged 不能很好地与 lerna 命令一起用于测试。

解决方案涉及在package.json中使用git命令来存储未跟踪和未暂存的文件,执行测试,然后在测试后重新实现未跟踪和未暂存的文件上演。

此方法的一个例外是,git看到文件更改被带回为需要手动合并的合并冲突。

以下是要进行的更改:

文件: ./package.json

{
  "name": "project",
  "private": true,
  "workspaces": [
    "packages/*"
  ],
  "scripts": {
    "build": "lerna run build",
    "dev": "lerna run start --stream --parallel",
    "format": "yarn prettier --write",
    "prettier": "prettier --ignore-path .gitignore \"**/*.+(ts|tsx|json)\"",
    "test": "lerna run test",
    "test:staged": "git stash -k --include-untracked; yarn test; git stash apply;"
  },
  "lint-staged": {
    "packages/**/*.{ts,js,json,md}": [
      "prettier --write"
    ]
  },
  "husky": {
    "hooks": {
      "pre-commit": "yarn format && yarn test:staged"
    }
  },
  "devDependencies": {
    "husky": "^4.2.5",
    "lerna": "^3.22.1",
    "prettier": "^2.0.5"
  }
}

更具体地说,这一行:

{
   "test:staged": "git stash -k --include-untracked; yarn test; git stash apply;"
}

您可能希望将 lint-staged 安装在当前正在开发的那些包中,而不是在您的根项目中。

意见:

One package may be typescript based, while others may be still flow based, for instance, so you definitely don't want your setting files to be on your root project.

假设您有两个包裹:

packages/
  shared-abc
  app-abc

您需要在您和您的团队正在处理的软件包上安装 lint-staged

$ npx lerna add --dev lint-staged --scope=@my-abc/app-abc

然后在你安装的包lint-staged上你要定义配置文件.lintstagedrc,例如:

{
  "*.{js,jsx,ts,tsx}": ["eslint --fix"]
}

顺便说一句,您可能还想在每个 lerna package 上安装 eslintprettier 或两者(不在根项目中)。

$ npx lerna add --dev eslint --scope=@my-abc/app-abc

The configuration file above tells lint-staged to run eslint --fix against each file that has been staged inside that package.

这种方法允许您为不同的包创建单独的 .eslintrc.js.prettierrc 文件,其中包含不同的 linting 或 prettier 设置。

如果您在项目根目录中安装了 lint-stagedeslintprettier 等,对于每个暂存文件,您的 git 钩子(或 husky)将可能 运行 eslint --fix 在不同的包上使用相同的设置,可能有非常具体的环境要求。您的 .eslintrc.js 可能会很乱并且充满了覆盖。

结论

所以在你的包中安装 lint-staged 之后,你希望你的 git 钩子(或 husky)到 运行 以下带有 lerna 的命令行:

npx lerna run lint-staged

现在您仍然需要将此脚本添加到您想要的软件包的 package.json 文件中。

{
...
scripts: {
   ...
   "lint-staged": "lint-staged",      
   ...
}
...
}

因此 lerna 将 运行 脚本 lint-staged 在所有具有脚本 lint-staged 的包上添加到 package.json 文件的 scripts 条目中。