heft コマンド
Microsoft 謹製、TypeScript 向け monorepo 管理ツール郡 Rush Stack の使い方勉強
heft コマンドのドキュメントを読んだメモ
Heft is a config-driven toolchain that invokes other popular tools such as TypeScript, ESLint, Jest, Webpack, and API Extractor. You can use it to build web applications, Node.js services, command-line tools, libraries, and more. Heft builds all your JavaScript projects the same way: A way that works.
DeepL + 意訳
Heft は、TypeScript、ESLint、Jest、Webpack、API Extractor などの有名なツールを呼び出す設定駆動型のツールチェインです。Web アプリケーション、Node.js サービス、コマンドラインツール、ライブラリなどを構築するために使用できます。Heft は、あなたの JavaScript プロジェクトをすべて同じ方法でビルドします。言い換えれば、一つの動作に集約します。
Rush で管理された複数のプロジェクトをまたがって、重複する package.json
の "build"
スクリプトを管理したくないよね
-> heft を使うと共通化できて嬉しい、とのこと
heft コマンドライン
-
clean
プロジェクトのビルド成果を破棄する -
build
プロジェクトをビルドする -
start
プロジェクトのローカルサーバーを起動する -
test
プロジェクトをビルドし、テストをする
heft チュートリアル
npm install --global pnpm
Rush Stack 全体的に pnpm 推し。
複数プロジェクトにまたがった共通パッケージをシンボリックリンクで配置して、ストレージ効率が良いとかなんとか。
TypeScript プロジェクトを開始にあたって最低限のファイル配置
{
"name": "my-app",
"version": "1.0.0",
"description": "A Heft tutorial project",
"license": "MIT",
"main": "lib/start.js",
"typings": "lib/start.d.ts",
"scripts": {
"start": "node lib/start.js"
}
}
console.log("Hello, world!");
依存のインストール
pnpm install --save-dev @rushstack/heft
pnpm install --save-dev typescript
# 型定義のインストールは --save-exact オプションを常に付けるように
pnpm install --save-dev --save-exact @types/node
TypeScript の設定
{
"$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,
"esModuleInterop": true,
"types": ["node"],
"module": "commonjs",
"target": "es2017",
"lib": ["es2017"]
},
"include": ["src/**/*.ts"],
"exclude": ["node_modules", "lib"]
}
プロジェクトローカルの node_modules
にインストールされた heft
バイナリでも動作するけど、グローバルインストールしておくのが吉。
ローカルとグローバルでバージョンが異なっても、適切な方を勝手に選んで実行してくれるらしい。
pnpm install --global @rushstack/heft
heft
コマンドでビルド
heft build
走らす
pnpm run start
# rush が導入済みなら
rushx start
# も OK
# だけどこのチュートリアルでは未導入のはずなので覚えておくだけ
NPM スクリプトに "build"
を足しておくと、後で rush との連携に効くらしい。
{
. . .
"scripts": {
"build": "heft build --clean",
"start": "node lib/start.js"
},
. . .
}
heft clean
コマンドが適切にビルド成果を削除できるように、以下の設定を済ます。
/**
* Defines configuration used by core Heft.
*/
{
"$schema": "https://developer.microsoft.com/json-schemas/heft/heft.schema.json",
"eventActions": [
{
/**
* The kind of built-in operation that should be performed.
* The "deleteGlobs" action deletes files or folders that match the
* specified glob patterns.
*/
"actionKind": "deleteGlobs",
/**
* The stage of the Heft run during which this action should occur. Note that actions specified in heft.json
* occur at the end of the stage of the Heft run.
*/
"heftEvent": "clean",
/**
* A user-defined tag whose purpose is to allow configs to replace/delete handlers that were added by other
* configs.
*/
"actionId": "defaultClean",
/**
* Glob patterns to be deleted. The paths are resolved relative to the project folder.
*/
"globsToDelete": ["dist", "lib", "temp"]
}
],
/**
* The list of Heft plugins to be loaded.
*/
"heftPlugins": [
// {
// /**
// * The path to the plugin package.
// */
// "plugin": "path/to/my-plugin",
//
// /**
// * An optional object that provides additional settings that may be defined by the plugin.
// */
// // "options": { }
// }
]
}
やたらコメント付き JSON が出てくるので、VSCode を使っている場合は .json
の関連を変えておいたほうが楽かもしれない
{
. . .
"files.associations": {
"*.json": "jsonc"
},
. . .
}
Heft から Jest ユニットテスト、ESLint を呼ぶhttps://rushstack.io/pages/heft_tutorials/adding_tasks/
Jest
型定義インストール
# 型定義のときは --save-exact オプション付き
pnpm install --save-dev --save-exact @types/heft-jest
型定義を足したときは tsconfig.json
も直す
{
. . .
"types": ["heft-jest", "node"],
. . .
}
Jest 呼び出しの設定
たいていは標準プリセットを呼ぶだけ
{
"preset": "./node_modules/@rushstack/heft/includes/jest-shared.config.json"
}
テストを書く
describe('Example Test', () => {
it('correctly runs a test', () => {
expect(true).toBeTruthy();
});
});
実行
heft test
heft test
コマンドは、テスト前にビルドもしてくれるので、package.json
の "build"
コマンドを heft build
から差し替えておくと、ビルドのたびにテストを通してくれてステキ。
{
. . .
"scripts": {
"build": "heft test --clean", // --clean オプション ビルド成果を破棄して新規ビルド
"start": "node lib/start.js"
},
. . .
}
ESLint
pnpm install --save-dev eslint
pnpm install --save-dev @rushstack/eslint-config
// 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"
もextends
に含める。@rushstack/eslint-config
の "profile "と "mixins "の詳細についてはドキュメントを見る
例えば start.ts
に、返り値の型を指定しない空の関数を作ると、
console.log('Hello, world!');
export function f() {
// <--- あらら
}
pnpm run build
( = heft test --clean
) の中で Linting されて警告が吐かれる
. . .
---- Compile started ----
[copy-static-assets] Copied 0 static assets in 0ms
[typescript] Using TypeScript version 3.9.7
[eslint] Using ESLint version 7.5.0
[eslint] Encountered 1 ESLint error:
[eslint] ERROR: src\start.ts:3:8 - (@typescript-eslint/explicit-function-return-type) Missing return type on function.
. . .
返り値の型を正しく void
に指定すると
console.log('Hello, world!');
export function f(): void {
// <--- 勝ったなこれ
}
pnpm run build
の警告が消える。
Heft のツールチェーンをカスタマイズして、その上で NPM スクリプト "build"
で呼ぶコマンドを heft *
に統一すれば、パッケージを跨いだ共通処理にできてラクチンよってことか。
更にここまでの設定を "rig package" なる NPM パッケージにまとめて、それを各プロジェクトで extends して使うことで、"rig package" 定義の heft の動作をリポジトリ全体に伝播できるし、プロジェクトローカルで設定のオーバーライドもできてオイシイと。