热替换
不砍树,只换品种。热重载只替换受改动影响的插件,在一次事务中完成;新代码失败时保留旧代码。见 热重载。
软件不是造出来的,是长出来的。
插件到来、生根、结果。有的被剪掉,有的在树不倒的情况下被换掉。好园丁从不担心一根枝条从哪里来,也不担心剪掉它会怎样。
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())]| 分区 | 页面 | 阅读目的 |
|---|---|---|
| 入门 | 快速开始、核心概念、从 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 只照料自己的园子。