跳转到内容
Graft 标志:一个 G,横笔是插向圆心的箭头

园艺学 Effect 系统

Graft 在 Effect 上把应用养成一棵插件树。进程持续运行,任意一枝都可以加载、替换或卸载。放心修剪。

软件不是造出来的,是长出来的。

插件到来、生根、结果。有的被剪掉,有的在树不倒的情况下被换掉。好园丁从不担心一根枝条从哪里来,也不担心剪掉它会怎样。

Graft 给你这份确定。每个插件都嫁接在一个 scope 上,每个 fiber 都有归属,每个失败都能追溯到根。

热替换

不砍树,只换品种。热重载只替换受改动影响的插件,在一次事务中完成;新代码失败时保留旧代码。见 热重载。

干净卸载

每个插件都在自己的 Scope 中运行。插件消失时,依赖它的部分先停止,再执行它的 finalizer。失败保留完整的 Cause。见生命周期。

依赖受检查

服务是 Effect 的 Context 键,由 layer 或其他插件提供。插件在 inject 中列出所需服务,由编译器检查。见 服务。

import { Context, Effect, Option, Schema, Stream } from "effect"
import { Fork, Graft, Plugin } from "@graftland/graft"
class Greeter extends Context.Service<
Greeter,
{ readonly greet: (name: string) => Effect.Effect<void> }
>()("app/Greeter") {}
// Publishes a Greeter while it is loaded.
const greeter = Plugin.make({
name: "app/greeter",
config: Schema.Struct({ greeting: Schema.String }),
apply: ({ greeting }) =>
Graft.provide(Greeter, {
greet: (name) => Effect.log(`${greeting}, ${name}!`),
}),
})
// Starts once a Greeter exists, and stops before it goes away.
const hello = Plugin.make({
name: "app/hello",
inject: [Greeter],
apply: () => Effect.flatMap(Greeter, (greeter) => greeter.greet("world")),
})
const states = await Effect.runPromise(
Effect.gen(function* () {
const helloFork = yield* Graft.plugin(hello)
yield* helloFork.await
const waiting = yield* Stream.runHead(helloFork.state)
yield* Graft.plugin(greeter, { greeting: "Hello" })
const started = yield* helloFork.state.pipe(
Stream.filter(
(state) => state._tag !== "Pending" && state._tag !== "Loading",
),
Stream.runHead,
)
return [waiting, started]
}).pipe(Effect.scoped, Effect.provide(Graft.layer)),
)
states // => [Option.some(Fork.ForkState.Pending({ missing: ["app/Greeter"] })), Option.some(Fork.ForkState.Active())]

在别处运行插件

用 Remote 把某个插件放到子进程、worker 或另一台机器上运行,使用它的插件不必改动。

分区 页面 阅读目的
入门 快速开始、核心概念、从 cordis 迁移 了解模型并运行示例。
构建插件 插件、服务、事件 编写代码。
结构 生命周期、领域、Intercept、替换插件 控制插件之间的关系与变化。
应用 配置文件、命令行、热重载、在程序中使用 Graft 运行和维护应用。
Remote 概览、宿主条目、Runner、替换与停止 让插件在另一个进程或另一台机器上运行。
参考 Fork 句柄、Loader API、HMR API、错误 查阅确切行为。
项目 发布 检查并发布 Graft。
包 功能
@graftland/graft 基于 Effect 的插件框架:插件、fork、服务、隔离、事件和日志。
@graftland/loader 从配置项列表或 YAML 配置文件加载插件。
@graftland/hmr 在 Node.js 中重载插件模块,无需重启进程。
@graftland/cli 提供 graft 命令:start、create、add 和 remove。
@graftland/create 创建新的 Graft 项目:npm create @graftland 和 graft create。
@graftland/package-manager 使用 npm、pnpm 或 Yarn 安装依赖。安装失败时,通过快照回滚撤销。
@graftland/plugin-remote 让插件在子进程、worker 或另一台机器上运行。见 Remote。
@graftland/plugin-otlp 把一棵插件子树的 span 导出到 OpenTelemetry。见导出 span。
@graftland/plugin-http 共享 HTTP 服务器;路由和流随插件的生命周期加载和卸载。
@graftland/plugin-http-api 实时 HttpApi 路由组、类型化客户端和 OpenAPI 文档。
@graftland/plugin-mcp-server 把插件的工具提供给 MCP 客户端。见 MCP 服务器。

所有包共用同一个版本号,一同发布,并需要 effect 4.1.x。

园艺只出现在这一页。在其余文档和代码里,Scope 仍然叫 Scope。Graft的插件模型借鉴自 cordis。cordis 在时空中组合,Graft 只照料自己的园子。