Rush Stack商場部落格活動
跳到主要內容

你好,世界

此教學課程將指導您建立一個基本 Node.js 主控台專案從零開始並逐步新增每個任務步驟,以入門 Heft。實際上,您可能比較想使用現成的套件組。本教學課程的目標是說明 Heft 的基本概念和架構。有了這個基礎知識,您可以更輕鬆地了解複雜的組態並排除任何 возникающих 問題。

"秀出程式碼!"

如果您很趕時間,heft-node-basic-tutorialheft-webpack-basic-tutorial 資料夾示範了一個使用 Heft 進行建置的簡單專案的完整實務範例。

heft-node-rig-tutorialheft-web-rig-app-tutorial 資料夾說明如何使用 Rush Stack 套件組而非手動 Heft 組態來達成相同的結果。套件組使許多專案能夠共用一個標準組態,這極大幅地降低升級的維護成本。

我們將從建立一個沒有 Rush 的簡單獨立專案開始。(稍後,Rush 介面 教學課程將探討在 monorepo 中使用 Heft 時的差異。)

  1. 我們將為此示範使用 PNPM 套件管理員。它的命令列與 NPM 非常相似,因此您可以在這些步驟中用 npm 取代 pnpm。有 多種方式 可以安裝 PNPM,但最簡單的方式如下

    npm install --global pnpm
  2. 為我們的專案建立一個新的資料夾 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"
    }
    }
  3. 建立一個我們將編譯的 TypeScript 原始檔。

    my-app/src/start.ts

    console.log("Hello, world!");
  4. 幫你的專案安裝 @rushstack/heft@rushstack/heft-typescript-pluginTypeScript 作為 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
  5. 接下來,我們需要建立 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 組態的背景資料。

  6. 你可以用 ./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,確保使用的是正確的版本。

  7. 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.
  8. 現在我們展開我們的組態,加入一個稱為 "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" 之後,buildbuild-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"

  9. 讓我們嘗試呼叫 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.mapstart.d.ts.map - 原始碼對應檔,它讓偵錯工具等工具,可以找到輸出檔案特定項目的對應原始碼檔案/列
  10. 如果你還記得,我們的 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!
  11. 我們也可以在 package.json 檔案中新增一個 "build" 指令碼

    my-app/package.json

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

    有了這個變更,你也可以透過呼叫 pnpm run build (或 rushx build) 來編譯。這個與工具鏈無關的慣例,讓初學者更容易猜出如何編譯你的專案。當我們之後與 Rush 整合時,它也會很有用。