你好,世界
此教學課程將指導您建立一個基本 Node.js 主控台專案從零開始並逐步新增每個任務步驟,以入門 Heft。實際上,您可能比較想使用現成的套件組。本教學課程的目標是說明 Heft 的基本概念和架構。有了這個基礎知識,您可以更輕鬆地了解複雜的組態並排除任何 возникающих 問題。
"秀出程式碼!"
如果您很趕時間,heft-node-basic-tutorial 和 heft-webpack-basic-tutorial 資料夾示範了一個使用 Heft 進行建置的簡單專案的完整實務範例。
heft-node-rig-tutorial 和 heft-web-rig-app-tutorial 資料夾說明如何使用 Rush Stack 套件組而非手動 Heft 組態來達成相同的結果。套件組使許多專案能夠共用一個標準組態,這極大幅地降低升級的維護成本。
我們將從建立一個沒有 Rush 的簡單獨立專案開始。(稍後,Rush 介面 教學課程將探討在 monorepo 中使用 Heft 時的差異。)
我們將為此示範使用 PNPM 套件管理員。它的命令列與 NPM 非常相似,因此您可以在這些步驟中用
npm
取代pnpm
。有 多種方式 可以安裝 PNPM,但最簡單的方式如下npm install --global pnpm
為我們的專案建立一個新的資料夾 my-app,並建立 package.json 檔案,如下所示
my-app/package.json
{
"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"
}
}建立一個我們將編譯的 TypeScript 原始檔。
my-app/src/start.ts
console.log("Hello, world!");
幫你的專案安裝 @rushstack/heft、@rushstack/heft-typescript-plugin 和 TypeScript 作為
devDependenices
cd my-app
pnpm install --save-dev @rushstack/heft
pnpm install --save-dev @rushstack/heft-typescript-plugin
pnpm install --save-dev typescript
# Since this project will use the console.log() API, we also need to add the TypeScript
# typings for Node.js. Typings should always use "--save-exact" version specifiers.
pnpm install --save-dev --save-exact @types/node接下來,我們需要建立 TypeScript tsconfig.json 檔案。這個檔案的存在,會導致 Heft 呼叫 TypeScript 編譯器。現在我們會建立一個簡單的獨立 **tsconfig.json** 檔案;稍後會示範如何跨許多專案共用一個可重複使用的組態。
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": ["node"],
"module": "commonjs",
"target": "es2017",
"lib": ["es2017"]
},
"include": ["src/**/*.ts"],
"exclude": ["node_modules", "lib"]
}要注意的是,
"types": ["node"]
參照的是上面所安裝的@types/node
套件。這是需要的,因為 Node.js 是全域性的環境,所以它的類型必須在全域性做載入。大多數其他的@types
套件,都可以在你的原始碼中,透過import
陳述句來載入。參閱 TypeScript 擴充功能 文件,以了解更多有關用 Heft 設定 TypeScript 組態的背景資料。
你可以用
./node_modules/.bin/heft
來呼叫 Heft,但更方便的方法是,把它也安裝到全域,這樣它就會隨時在你的殼層PATH
中。# Install the Heft tool globally
npm install --global @rushstack/heft如果全域安裝的
heft
執行檔版本不正確,怎麼辦?就像 Rush,Heft 執行了「版本選擇器」功能,它會自動偵測你的本機
node_modules
資料夾,並呼叫./node_modules/.bin/heft
,確保使用的是正確的版本。Heft 是由組態驅動的,也就是說他在專案資料夾中的行為,是由資料(組態檔)來定義的,而不是程式碼(任意指令碼)。如果您需要擴充建置流程,加入程式邏輯,我們強烈建議將該程式碼移到 Heft 外掛程式套件中,而它應該使用 TypeScript、ESLint 和程式碼檢閱,來開發為專業軟體。這個方式較麻煩,但隨著你的 monorepo 規模擴大,它會大大簡化維護。
Heft 的主要組態檔是 config/heft.json。我們從一個最簡單的檔案開始
config/heft.json
{
"$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json",
}如果你執行
heft --help
,應該會看見如下輸出的內容usage: heft [-h] [--debug] [--unmanaged] <command> ...
Heft is a pluggable build system designed for web projects.
Positional arguments:
<command>
clean Clean the project, removing temporary task folders and
specified clean paths.
run Run a provided selection of Heft phases.
run-watch Run a provided selection of Heft phases in watch mode..
Optional arguments:
-h, --help Show this help message and exit.現在我們展開我們的組態,加入一個稱為
"build"
的簡單階段,它呼叫一個名為"typescript"
的任務來編譯你的程式碼。(關於這些術語的定義,請參考 架構 筆記。)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"
}
}
}
}
}
}關於這些設定的完整說明,請參閱 heft.json 範本。
如果你執行
heft --help
,現在你會看到,自從我們的階段被稱為"build"
之後,build
和build-watch
動作已經新增到你的命令列中。usage: heft [-h] [--debug] [--unmanaged] <command> ...
Heft is a pluggable build system designed for web projects.
Positional arguments:
<command>
clean Clean the project, removing temporary task folders and
specified clean paths.
run Run a provided selection of Heft phases.
build Runs to the build phase, including all transitive dependencies.
run-watch Run a provided selection of Heft phases in watch mode..
build-watch
Runs to the build phase, including all transitive dependencies,
in watch mode.
Optional arguments:
-h, --help Show this help message and exit.如果你執行
heft build --help
,會列印出"phaseDescription"
。讓我們嘗試呼叫 Heft 的 命令列 來建置我們的專案。
# Make sure we're in your project folder
cd my-app
# View the command line help
heft --help
heft build --help
# Build the project
heft build
# To see more detail about what Heft is doing, add you can the "--verbose" flag
heft build --verbose呼叫
heft build --verbose
應該會產生如下主控台輸出內容Project: my-app@1.0.0
Project build folder: C:\my-app
Heft version: 0.56.2
Node version: v16.15.1
Executing a maximum of 4 simultaneous tasks...
---- lifecycle started ----
[lifecycle:start] Applying lifecycle plugins
---- build started ----
[build] Applying task plugins
[build:typescript] Loaded plugin from "C:\my-app\node_modules\...\@rushstack\heft-typescript-plugin\lib\TypeScriptPlugin"
[build:typescript] Starting task execution
[build:typescript] Looking for tsconfig at C:/my-app/tsconfig.json
[build:typescript] Resolved "typescript" as a direct devDependency of the project.
[build:typescript] Using TypeScript version 5.1.6
[build:typescript] Configure: 17.34340000152588ms
[build:typescript] I/O Read: 16.67810034751892ms (98 files)
[build:typescript] Parse: 491.7621006965637ms (98 files)
[build:typescript] Program (includes Read + Parse): 581.9542999267578ms
[build:typescript] Analyze: 1135.4448999166489ms
[build:typescript] Bind: 189.5981993675232ms
[build:typescript] Check: 929.5596989393234ms
[build:typescript] Transform: 4.200200080871582ms (2 files)
[build:typescript] Print: 12.058799982070923ms (1 files) (Includes Transform)
[build:typescript] Emit: 12.5ms (Includes Print)
[build:typescript] I/O Write: 0ms (0 files)
[build:typescript] Finished task execution (1964.6486999988556ms)
---- build finished (2.014s) ----
---- lifecycle finished (2.018s) ----
-------------------- Finished (2.02s) --------------------注意:報告診斷訊息時(例如編譯錯誤),Heft 會列印相對於專案資料夾的檔案路徑。這可以使用 RUSHSTACK_FILE_ERROR_BASE_FOLDER 環境變數來自訂。
建置完成後,確認它在你的
lib
資料夾中產生了幾個輸出檔案- start.js - 編譯的 JavaScript 程式碼
- start.d.ts - TypeScript 類型,供可能會匯入這個模組的外部程式庫使用
- start.js.map 和 start.d.ts.map - 原始碼對應檔,它讓偵錯工具等工具,可以找到輸出檔案特定項目的對應原始碼檔案/列
如果你還記得,我們的 package.json 檔案有一個
"scripts"
區段,裡面有指定"start": "node lib/start.js"
。我們來試試看使用pnpm run
來執行已編譯的程式碼。# Invoke the "start" script from package.json
pnpm run start
# If you have Rush installed, you can also use this slightly shorter equivalent
rushx start你應該會看到類似的輸出
> my-app@1.0.0 start C:\my-app
> node lib/start.js
Hello, world!我們也可以在 package.json 檔案中新增一個
"build"
指令碼my-app/package.json
{
. . .
"scripts": {
"build": "heft build --clean",
"start": "node lib/start.js"
},
. . .
}有了這個變更,你也可以透過呼叫
pnpm run build
(或rushx build
) 來編譯。這個與工具鏈無關的慣例,讓初學者更容易猜出如何編譯你的專案。當我們之後與 Rush 整合時,它也會很有用。