跳到內容

快速開始

需要 Node.js 22.19 或更新版本,這是 CLI 所用 Effect Node 轉接器要求的版本。該版本也提供熱重載所需的 module.registerHooks。

  1. 建立專案。按 Enter 接受每個預設值;命令會安裝相依套件:

    Terminal window
    npm create @graftland@latest my-app
    cd my-app

    先從這幾個檔案開始:

    檔案 用途
    graft.yml 設定檔,指定要載入的外掛及其設定。
    src/hello.ts 輸出設定中訊息的外掛。
    src/greeter.ts 發布 Greeter 服務的外掛。
    src/ticker.ts 注入 Greeter 並定時問候的外掛。
    tsconfig.json 供 npm run typecheck 做型別檢查。

    graft create 列出了所有問題、其他範本,以及跳過提問的選項。

  2. 啟動應用程式並監看檔案變更:

    Terminal window
    npm run dev

    hello 輸出 Hello from Graft!;ticker 透過 greeter 發布的 Greeter,每 3 秒輸出一次 Hello, Graft!。行程會持續執行,直到你按下

    Ctrl+C,此時 Graft 會卸載所有外掛。

  3. 在應用程式執行期間修改設定。開啟 graft.yml,修改問候語:

    - id: greeter
    name: ./src/greeter.ts
    config:
    greeting: Hi

    儲存後,Graft 先停止使用 Greeter 的 ticker,再用新問候語重新啟動 greeter,然後重新啟動 ticker。你會看到 Ticker stopped、Greeter stopped,接著是 Hi, Graft!。hello 不受影響。

  4. 在應用程式執行期間修改程式碼。把 src/ticker.ts 中的 "3 seconds" 改成 "1 second" 並儲存。Graft 匯入新模組,只重新啟動 ticker。如果新程式碼匯入或啟動失敗,舊版本會繼續執行,Graft 並記錄錯誤。

  5. 拿走一個相依項目。在 greeter 項目加上 disabled: true 並儲存。ticker 會停止,並以 Pending 狀態等待,直到 Greeter 再次出現。刪除這一行,它就恢復問候。

src/greeter.ts
import { Context, Effect, Schema } from "effect"
import { Graft, Plugin } from "@graftland/graft"
/** Greets by name. Other plugins list it in `inject` to use it. */
export class Greeter extends Context.Service<
Greeter,
{ readonly greet: (name: string) => Effect.Effect<void> }
>()("app/Greeter") {}
// Publishes a Greeter while it is loaded. Plugins that use it stop first.
export default Plugin.make({
name: "app/greeter",
config: Schema.Struct({ greeting: Schema.String }),
apply: ({ greeting }) =>
Effect.gen(function* () {
yield* Effect.addFinalizer(() => Effect.logInfo("Greeter stopped"))
yield* Graft.provide(Greeter, {
greet: (name) => Effect.logInfo(`${greeting}, ${name}!`),
})
}),
})
src/ticker.ts
import { Effect, Schedule, Schema } from "effect"
import { Plugin } from "@graftland/graft"
import { Greeter } from "./greeter.ts"
// Starts once a Greeter exists and greets on a schedule. The task belongs to
// the plugin, so it stops when the plugin stops or reloads.
export default Plugin.make({
name: "app/ticker",
config: Schema.Struct({ name: Schema.String }),
inject: [Greeter],
apply: ({ name }) =>
Effect.gen(function* () {
const greeter = yield* Greeter
yield* Plugin.fork(
greeter.greet(name).pipe(Effect.repeat(Schedule.spaced("3 seconds"))),
)
yield* Effect.addFinalizer(() => Effect.logInfo("Ticker stopped"))
}),
})

inject: [Greeter] 由編譯器檢查:刪掉它,npm run typecheck 就會回報 apply 使用了未宣告的服務。Node 會移除型別後直接執行這些 TypeScript 檔案,因此不需要建置步驟。外掛模組以預設匯出,或以名為 plugin 的匯出來提供它的外掛。匯入模組時不得啟動任何東西。請在 apply 內開啟連線、計時器和伺服器,這樣 Graft 才能釋放它們。請參閱外掛和服務。

Terminal window
npx graft add graft-plugin-review

graft add 使用專案的套件管理器安裝套件。如果安裝失敗,它會把 package.json 和鎖定檔還原成原來的樣子。安裝或復原期間,請不要編輯專案檔案,也不要執行其他安裝程式。還原會覆寫變更,不會合併它們。請參閱安裝的所有權與還原。接著在 graft.yml 中為該外掛新增一個項目。它的 name 可以是短名稱 review:Graft 先尋找 review 本身,再尋找 @graftland/plugin-review 和 graft-plugin-review;後兩者都已安裝時失敗。請參閱設定檔。

你想要… 請閱讀
了解各個組成部分 核心概念
撰寫自己的外掛 外掛
在外掛之間共用狀態 服務
設定更多項目 設定檔
在自己的程式中執行 Graft 在自己的程式中使用 Graft
讓外掛在另一個行程中執行 Remote
和程式設計代理一起開發 graft skill:npx skills add graftland/graft