快速开始
需要 Node.js 22.19 或更高版本,这是 CLI 所用 Effect
Node 适配器要求的版本。该版本也提供热重载所需的 module.registerHooks。
-
创建项目。每个问题按 Enter 接受默认值即可,命令会安装依赖:
Terminal window npm create @graftland@latest my-appcd my-app先看这几个文件:
文件 用途 graft.yml配置文件,指定要加载的插件及其配置。 src/hello.ts输出配置中消息的插件。 src/greeter.ts发布 Greeter服务的插件。src/ticker.ts注入 Greeter并定时问候的插件。tsconfig.json供 npm run typecheck做类型检查。graft create列出了各个问题、其他模板,以及跳过提问的选项。 -
启动应用并监听文件变化:
Terminal window npm run devhello输出Hello from Graft!;ticker通过greeter发布的Greeter,每 3 秒输出一次Hello, Graft!。进程会持续运行,直到你按下Ctrl+C,此时 Graft 会卸载所有插件。
-
在应用运行期间修改配置。打开
graft.yml,修改问候语:- id: greetername: ./src/greeter.tsconfig:greeting: Hi保存后,Graft 先停止使用
Greeter的ticker,再用新问候语重启greeter,然后重新启动ticker。你会看到Ticker stopped、Greeter stopped,然后是Hi, Graft!。hello不受影响。 -
在应用运行期间修改代码。把
src/ticker.ts中的"3 seconds"改为"1 second"并保存。Graft 导入新模块,只重启ticker。如果新代码导入或启动失败,旧版本会继续运行,Graft 会把错误记录到日志中。 -
拿走一个依赖。给
greeter配置项加上disabled: true并保存。ticker会停止,并以Pending状态等待,直到Greeter再次出现。删除这一行,它就恢复问候。
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}!`), }) }),})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 能够释放这些资源。参见插件和服务。
从 npm 添加插件
Section titled “从 npm 添加插件”npx graft add graft-plugin-reviewgraft 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 |