编码

Rush Stack 项目实践

by Cheng, 2022-05-01


命令

rush 支持两种类型的命令机制:autoinstallerbulk

autoinstaller

初始化

在使用 autoinstaller 之前需要执行 rush init-autoinstaller --name AUTOINSTALLER_NAME 进行初始化。例如:rush init-autoinstaller --name rush-prettier 创建一个在项目级别运行的 eslint 命令。

在初始化完毕之后,可以在对应的 autoinstaller 中安装所需的依赖,并且在后续进行调用。

安装依赖

首先进入到 autoinstaller 对应的目录下:

cd <projectRoot>/common/autoinstallers/rush-prettier

安装所需要的依赖:

pnpm install prettier
pnpm install pretty-quick

更新对应的 autoinstaller 并确保 autoinstaller 中的 pnpm-lock.yaml 为最新。

rush update-autoinstaller --name rush-prettier

注册命令

不管是 autoinstaller 还是 bulk 命令都是在 <projectRoot>/common/config/rush/command-line.json文件里注册的。

对于 autoinstaller,除了要制定 commandKind 为 global 之外,还需要指定 autoinstallerName。

. . .
  "commands": [
    {
      "name": "prettier",
      "commandKind": "global",
      "summary": "Used by the pre-commit Git hook. This command invokes Prettier to reformat staged changes.",
      "safeForSimultaneousRushProcesses": true,

      "autoinstallerName": "rush-prettier",

      // This will invoke common/autoinstallers/rush-prettier/node_modules/.bin/pretty-quick
      "shellCommand": "pretty-quick --staged"
    }
. . .

这里的 shellCommand 可以是之前安装的依赖中导出的 shell 命令,即在 node_moudules/.bin文件夹中的命令。

这样就可以通过 rush COMMAND_NAME来运行对应的命令了,例如这里的 rush prettier。命令的执行上下文环境为项目的根目录,这样意味着我们可以像平常一样把配置写到项目的根目录。这里我们可以在项目的根目录写入 .prettierrc.js

bulk

注册为 bulk 类型的命令,会在执行的时候依次调用所有在 rush.json 中注册的 package 中的 package.json同名的 script。

. . .
  "commands": [
    {
      "name": "test",
      "commandKind": "bulk",
      "summary": "Invoke test command in each packages registered",
      "enableParallelism": true
    },
. . .

如果注册的 package 中没有找到同名的 script 则会报错,那么只需要简单的注册一个空的 script 即可。

...
"scripts": {
    "test": ""
  },
....

Heft

Heft 是一个配置驱动的工具链。通过 Heft 我们可以调用 TypeScriptESlintJest、Webpack 和 API Extractor

rig packages

Heft 通过 rig packages 机制让项目共享通用的配置,同时也能在通用配置的基础上进行扩展。

rig package 也支持 profile 机制,用于提供不同环境的配置。

这里我们创建一个名为 config rig package。项目位于 <projectRoot>/rig/config

\---config
    |   package.json
    |
    \---profiles
        +---development
        |       tsconfig.json
        |
        \---production
                tsconfig.json

这里提供了两个 profile:developmentproduction。在其他的 package 中可以通过 extend 的方式应用并拓展相关的配置。

{
  "extends": "./node_modules/@demo/config-rig/profiles/development/tsconfig.json"
}

Storybook

Heft 提供了 @rushstack/heft-storybook-plugin插件让我们在项目中集成 Storybook。为了避免每一个需要集成 Storybook 的 package 去直接依赖 Storybook 及其关联的包,如:@storybook/react@rushstack/heft-storybook-plugin@rushstack/heft-storybook-plugin 提供了一种 storykit 的机制,来解决这个问题。具体来说就是创建一个 package 并注册在 rush.json 中,在这个 package 中安装所有需要的依赖。讲这个 package 传入到 @rushstack/heft-storybook-pluginstorykitPackageName 选项中@rushstack/heft-storybook-plugin会将 storykit 中的 node_modules软连接到所有使用 Storybook的 package 的 .storybook 目录下,达到解决隔离依赖的目的。

Image

具体的实现可以参考文件 StorybookPlugin.ts

// Example:
//   LINK FROM: "/path/to/my-project/.storybook/node_modules"
//   TARGET:    "/path/to/my-project/node_modules/my-storykit/node_modules"
//
// For node_modules links it's standard to use createSymbolicLinkJunction(), which avoids
// administrator elevation on Windows; on other operating systems it will create a symbolic link.
await FileSystem.createSymbolicLinkJunctionAsync({
  newLinkPath: dotStorybookModuleFolder,
  linkTargetPath: storykitModuleFolder,
  alreadyExistsBehavior: AlreadyExistsBehavior.Overwrite
});
Monorepo工程化Rush Stack

作者: Cheng

2025 © typecho & elise & Cheng