Rush Stack商店博客活动
跳至主要内容

添加更多任务

本节继续介绍来自 Hello World 教程的教程项目。

Heft 的 架构 是围绕插件包设计的。Heft 附带了一系列用于最常见构建任务的 官方插件包。它们的源代码可以在 rushstack/heft-plugins 中找到,如果你想创建自己的 Heft 插件,它是一个很好的参考。

继续我们的教程,让我们启用两个最常见的插件:Jest 用于单元测试,ESlint 用于样式检查。

将单元测试添加到您的项目

  1. 首先,我们需要为 Jest 安装 TypeScript 类型定义。这些步骤继续来自 Hello World 教程的 my-app 项目。回想一下,这个项目还没有使用 Rush,因此我们将直接调用 PNPM 将依赖项添加到我们的 package.json 文件中(而不是使用 rush add)。

    cd my-app

    # Because @types packages don't follow SemVer, it's a good idea to use --save-exact
    pnpm install --save-dev --save-exact @types/heft-jest
    pnpm install --save-dev @rushstack/heft-jest-plugin
  2. 在您的 Heft 配置文件中添加一个 "test" 部分,产生以下结果

    config/heft.json

    {
    "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json",

    "phasesByName": {
    // Define a phase whose name is "build"
    "build": {
    "phaseDescription": "This phase compiles the project source code.",

    // Before invoking the compiler, delete the "dist" and "lib" folders
    "cleanFiles": [{ "sourcePath": "dist" }, { "sourcePath": "lib" }],

    "tasksByName": {
    // Define a task whose name is "typescript"
    "typescript": {
    "taskPlugin": {
    // This task will invoke the TypeScript plugin
    "pluginPackage": "@rushstack/heft-typescript-plugin"
    }
    }
    }
    },

    // Define a phase whose name is "test"
    "test": {
    "phaseDescription": "This phase runs the project's unit tests.",

    // This phase requires the "build" phase to be run first
    "phaseDependencies": ["build"],

    "tasksByName": {
    // Define a task whose name is "jest"
    "jest": {
    "taskPlugin": {
    // This task will invoke the Jest plugin
    "pluginPackage": "@rushstack/heft-jest-plugin"
    }
    }
    }
    }
    }
    }

    有关这些设置的完整描述,请参阅 heft.json 模板。

    如果您运行 heft --help,您现在应该看到 testtest-watch 命令行操作,因为我们的第二阶段被命名为 "test"

  3. 由于 Jest 的 API 由全局变量组成,我们需要全局加载它们(而大多数其他 @types 包是通过您的源代码中的 import 语句加载的)。更新您的 tsconfig.json 文件,改为 "types": ["heft-jest", "node"],而不是 "types": ["node"]。结果应该如下所示

    my-app/tsconfig.json

    {
    "$schema": "http://json.schemastore.org/tsconfig",

    "compilerOptions": {
    "outDir": "lib",
    "rootDirs": ["src/"],

    "forceConsistentCasingInFileNames": true,
    "declaration": true,
    "sourceMap": true,
    "declarationMap": true,
    "inlineSources": true,
    "experimentalDecorators": true,
    "strict": true,
    "useUnknownInCatchVariables": false,
    "esModuleInterop": true,
    "noEmitOnError": false,
    "allowUnreachableCode": false,

    "types": ["heft-jest", "node"],
    "module": "commonjs",
    "target": "es2017",
    "lib": ["es2017"]
    },
    "include": ["src/**/*.ts"],
    "exclude": ["node_modules", "lib"]
    }
  4. 接下来,我们需要添加 jest.config.json 配置文件。此文件的存在会导致 Heft 调用 Jest 测试运行器。Heft 期望特定文件路径 config/jest.config.json。对于大多数情况,您的 Jest 配置只需扩展 Heft 的标准预设,如下所示

    my-app/config/jest.config.json

    {
    "extends": "@rushstack/heft-jest-plugin/includes/jest-shared.config.json",
    "collectCoverage": true,
    "coverageThreshold": {
    "global": {
    "branches": 50,
    "functions": 50,
    "lines": 50,
    "statements": 50
    }
    }
    }

    注意:对于 Web 项目,您可能希望使用 @rushstack/heft-jest-plugin/includes/jest-web.config.json 而不是 jest-shared.config.json 来支持 lib-commonjslib 文件夹的双输出。有关详细信息,请参阅 Jest 插件 文档。

  5. 现在我们需要添加一个单元测试。Jest 支持很多功能,但对于本教程,我们将创建一个简单的测试文件。.test.ts 文件扩展名会导致 Heft 在此文件中查找单元测试

    my-app/src/example.test.ts

    describe('Example Test', () => {
    it('correctly runs a test', () => {
    expect(true).toBeTruthy();
    });
    });
  6. 要运行测试,我们需要使用 heft test 操作,因为 heft build 通常会跳过测试以加快开发速度。

    # View the command line help
    heft test --help

    # Build the project and run tests
    heft test --verbose

    # Run Jest in watch mode
    heft test-watch

    哇,heft test --help 有很多命令行参数!它们从哪里来?它们是由 Jest 插件的 heft-plugin.json 清单文件添加的,因为我们在阶段中加载了该插件。

    (如果两个不同的插件定义了相同的命令行参数会发生什么?Heft 包含一个复杂的消除歧义机制,例如,如果其他一些插件也定义了 --update-snapshots 参数,则允许您使用 --jest:update-snapshots 而不是 --update-snapshots)。

  7. 我们应该更新我们的 package.json 脚本,以便 pnpm run test 将运行 Jest 测试

    my-app/package.json

    {
    . . .
    "scripts": {
    "build": "heft build --clean",
    "test": "heft test --clean",
    "start": "node lib/start.js"
    },
    . . .
    }

注意:不要直接调用 jest 命令行。这样做会运行它在 lib/**/*.js 中找到的测试,但不会调用 Heft 更新这些输出文件所需的其余任务。

这就是设置 Jest 的全部内容!有关更多信息(包括测试调试说明),请参阅 Jest 插件 参考和 heft-node-jest-tutorial 示例项目。

启用代码风格检查

  1. 为了确保最佳实践并捕获常见错误,让我们也启用 @rushstack/eslint-config 标准规则集。首先,我们需要在 package.json 文件中添加一些额外的 NPM 依赖项。

    cd my-app

    # Add the ESLint engine
    pnpm install --save-dev eslint

    # Add Heft's plugin for ESLint
    pnpm install --save-dev @rushstack/heft-lint-plugin

    # Add Rush Stack's all-in-one lint ruleset
    pnpm install --save-dev @rushstack/eslint-config
  2. 更新您的 Heft 配置文件以添加一个在 heft build 阶段加载 @rushstack/heft-lint-plugin 的任务

    config/heft.json

    {
    "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json",

    "phasesByName": {
    // Define a phase whose name is "build"
    "build": {
    "phaseDescription": "Compiles the project source code",

    // Before invoking the compiler, delete the "dist" and "lib" folders
    "cleanFiles": [{ "sourcePath": "dist" }, { "sourcePath": "lib" }],

    "tasksByName": {
    // Define a task whose name is "typescript"
    "typescript": {
    "taskPlugin": {
    // This task will invoke the TypeScript plugin
    "pluginPackage": "@rushstack/heft-typescript-plugin"
    }
    },

    // Define a task whose name is "lint"
    "lint": {
    // This task should run after "typescript" has completed
    // because Heft optimizes ESLint by reusing the TypeScript
    // compiler's AST analysis
    "taskDependencies": ["typescript"],
    "taskPlugin": {
    // This task will invoke the ESLint plugin
    "pluginPackage": "@rushstack/heft-lint-plugin"
    }
    }
    }
    },
    // Define a phase whose name is "test"
    "test": {
    // This phase requires the "build" phase to be run first
    "phaseDependencies": ["build"],
    "tasksByName": {
    // Define a task whose name is "jest"
    "jest": {
    "taskPlugin": {
    // This task will invoke the Jest plugin
    "pluginPackage": "@rushstack/heft-jest-plugin"
    }
    }
    }
    }
    }
    }

    有关这些设置的完整描述,请参阅 heft.json 模板。

  3. 接下来,创建 .eslintrc.js 配置文件。对于本教程,我们将只使用官方 Rush Stack 规则集

    my-app/.eslintrc.js

    // This is a workaround for https://github.com/eslint/eslint/issues/3458
    require('@rushstack/eslint-config/patch/modern-module-resolution');

    module.exports = {
    extends: ['@rushstack/eslint-config/profile/node'],
    parserOptions: { tsconfigRootDir: __dirname }
    };

    注意:如果您的项目使用 React 框架,您还应该从 "@rushstack/eslint-config/mixins/react" 混入中扩展。有关 @rushstack/eslint-config "配置文件" 和 "混入" 的详细信息,请参阅 文档

  4. 为了测试它,尝试更新您的 start.ts 源文件以引入代码风格检查问题

    my-app/src/start.ts

    console.log('Hello, world!');

    export function f() {
    // <--- oops
    }

    当您运行 pnpm run build 时,您应该看到类似以下的日志消息

    -------------------- Finished (3.555s) --------------------
    Encountered 1 warning
    [build:lint] src/start.ts:3:8 - (@typescript-eslint/explicit-function-return-type) Missing return type on function.

    要解决此问题,请修复代码以添加缺少的返回类型,现在它应该成功构建

    my-app/src/start.ts

    console.log('Hello, world!');

    export function f(): void {
    // <--- okay
    }
  5. @rushstack/eslint-config 规则集旨在与 Prettier 代码格式化程序一起使用。要设置它,请参阅 Rush 网站上的 启用 Prettier 文章。

这就是 ESLint 的全部内容!更多详细信息可以在 Lint 插件 参考中找到。