@envelop/graphql-modules 使用指南:在 GraphQL Yoga 中正确接入 graphql-modules 依赖注入
后端API设计【免费下载链接】graphql-yoga Rewrite of a fully-featured GraphQL Server with focus on easy setup, performance great developer experience. The core of Yoga implements WHATWG Fetch API and can run/deploy on any JS environment.项目地址https://gitcode.com/gh_mirrors/gr/graphql-yoga点击查看免费下载导读本文围绕envelop/graphql-modules插件展开讲解如何把 graphql-modules 的模块化组织与依赖注入DI能力接入 Envelop / GraphQL Yoga 的执行流程。读完本文你将掌握该插件的安装方式、完整的envelop()组合配置、在 resolver 中通过context.injector获取 Provider 的写法以及插件如何借助onPluginInit、onExecute、onSubscribe等生命周期钩子确保Injector在正确的时机被创建与销毁。一、为什么需要这个插件graphql-modules 是一个模块化的 GraphQL 组织方案它允许开发者把 Schema、resolver、Provider 按业务模块拆分并通过装饰器Injectable与 ScopeOperation、Singleton、Transient管理依赖注入。当这类应用运行在 Envelop 管线中时会遇到一个关键问题Injector的生命周期必须与 GraphQL 执行流程对齐——它需要在每次操作Query/Subscription开始时创建在操作结束后销毁否则会出现 Provider 实例泄漏、跨请求共享状态等隐患。envelop/graphql-modules正是为此设计的它将 graphql-modules 的执行生命周期execution lifecycle接入 Envelop 的 GraphQL 执行流程。如果你正在使用 graphql-modules 的依赖注入能力这一配置是必需的它用来保证Injector在正确的时间被创建和销毁。该插件的完整实现位于仓库 packages/envelop/plugins/graphql-modules/src/index.ts核心逻辑非常精简通过 Envelop 的生命周期钩子把 graphql-modules 的Application能力注入进来。二、安装与版本要求在项目中安装插件yarn add envelop/graphql-modules从 package.json 可以看到它的依赖与兼容范围peerDependenciesenvelop/core与当前仓库版本如 5.x配套graphql^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0即 GraphQL.js 14~17 均受支持graphql-modules^1 || ^2.0.0 || ^3.0.0enginesnode 18.0.0包同时提供 ESMdist/esm/index.js与 CommonJSdist/cjs/index.js产物并声明type: module。该插件要求项目中同时安装graphql-modules例如仓库内 devDependencies 使用graphql-modules3.1.1与reflect-metadata因为 graphql-modules 的装饰器能力依赖反射元数据。三、基本用法组合进 Envelop 管线在envelop()中注册插件并把通过createApplication创建的 graphql-modules 应用传给它import { execute, parse, specifiedRules, subscribe, validate } from graphql import { createApplication } from graphql-modules import { envelop, useEngine } from envelop/core import { useGraphQLModules } from envelop/graphql-modules const myApp createApplication({ modules: [ /* ... 你的业务模块 ... */ ] }) const getEnveloped envelop({ plugins: [ useEngine({ parse, validate, specifiedRules, execute, subscribe }), // ... 其他插件 ... useGraphQLModules(myApp) ] })几点说明useEngine({ parse, validate, specifiedRules, execute, subscribe })显式声明 GraphQL 引擎函数确保管线内使用与 graphql-modules 一致的执行实现。useEngine的实现位于 packages/envelop/core/src/plugins/use-engine.ts它会在onExecute与onSubscribe钩子中通过setExecuteFn/setSubscribeFn替换默认执行函数。useGraphQLModules(myApp)接收Application实例并返回一个 EnvelopPlugin你可以把它与其他插件任意排序组合。在 Envelop 之上构建的 GraphQL Yoga 同样适用插件本身不依赖具体的 HTTP 服务层。四、在 Resolver 中使用 Injector插件接入后graphql-modules 的injector会被注入到 GraphQL context 中你可以直接在 resolver 里通过context.injector.get(...)获取 Provider 实例const resolvers { Query: { foo: (root, args, context, info) { const myProviderInstance context.injector.get(/* ... */) } } }context.injector的可用性正是该插件存在的意义——Injector的创建与销毁时机由 graphql-modules 的Application与 Envelop 的执行钩子协同管理因此在 resolver 中无需关心 Provider 的实例化与清理细节。五、源码级原理插件到底做了什么整个插件的实现只有一份很短的源码位于 packages/envelop/plugins/graphql-modules/src/index.tsexport const useGraphQLModules (app: Application): Plugin { return { onPluginInit({ setSchema }) { setSchema(app.schema); }, onExecute({ setExecuteFn, executeFn }) { setExecuteFn( app.createExecution({ execute: executeFn as any, }), ); }, onSubscribe({ setSubscribeFn, subscribeFn }) { setSubscribeFn( app.createSubscription({ subscribe: subscribeFn as any, }), ); }, }; };它依次做了三件事onPluginInit({ setSchema })在插件初始化阶段通过setSchema(app.schema)把 graphql-modules 应用内部的 Schema 设置为 Envelop 的 Schema。从 packages/envelop/core/src/orchestrator.ts 可以看到Envelop 在初始化时会依次遍历所有插件触发onPluginInit并传入setSchema回调用于替换 Schema。onExecute({ setExecuteFn, executeFn })用app.createExecution(...)包装 Envelop 传入的executeFn得到新的执行函数并通过setExecuteFn注册。这样每次 Query 执行时graphql-modules 会为本次操作创建Injector并在执行结束后销毁它。onSubscribe({ setSubscribeFn, subscribeFn })对 Subscription 操作做同样的处理用app.createSubscription(...)包装订阅函数保证每个订阅会话的Injector生命周期正确。也就是说插件并不改变 Schema 定义或 resolver 逻辑本身而是接管执行/订阅函数的注册点让 graphql-modules 的依赖注入生命周期包裹每一次操作。六、测试验证Query、Subscription 与上下文合并插件的行为在 packages/envelop/plugins/graphql-modules/test/use-graphql-modules.spec.ts 中有完整的测试覆盖可以当作真实的集成示例来读1. Query 操作的 Injector 销毁测试里定义了一个Scope.Operation的TestProvider其onDestroy()回调会把isDestroyed置为true。执行query { foo }后断言结果result.data?.foo testFooProvider 正常工作isDestroyed true操作结束后Injector及其Operation作用域的 Provider 已被正确销毁。这验证了创建与销毁在正确时机的核心承诺。2. Subscription 操作同样用Operation作用域的 Provider 构造了一个subscription { bar }通过envelop/testing提供的assertStreamExecutionValue与collectAsyncIteratorValues收集流式结果断言订阅值正确且会话结束后Injector被销毁。3. 与 Envelop 上下文合并Singleton Provider测试展示了如何把 graphql-modules 的 Provider 与 Envelop 的 context 打通一个Scope.Singleton的IdentifierProvider通过ExecutionContext()注入 Envelop 构建的 context读取context.identifier然后 resolver 再拼接useExtendContext注入的identifierSuffix与identifierPrefix最终得到henlo-bob-bye。这说明Singleton 作用域的 Provider 能读取到 Envelop 上下文中由其他插件如useExtendContext注入的数据useExtendContext与useGraphQLModules可以共存并正确合并上下文。4. 异步并发下的上下文隔离最后一个测试模拟两个并发操作getAsyncIdentifiers分别传入identifier: first与identifier: second断言各自解析过程中从 Singleton Provider 读到的都是自己那一次操作的 context 值没有出现跨请求串扰。结合 CHANGELOGpackages/envelop/plugins/graphql-modules/CHANGELOG.md中 9.1.0 版本Bind context to async execution avoiding race-conditions的变更记录可以确认插件已针对异步执行做了上下文绑定避免竞态条件。七、常见组合场景与注意事项与useEngine的关系useEngine提供引擎函数注册useGraphQLModules在其基础上进一步包装执行与订阅函数两者配合使用是最标准的组合方式顺序上建议先useEngine再useGraphQLModules。与其他 Envelop 插件共存该插件只拦截执行/订阅层不影响解析、校验、上下文构建等其他插件。测试中还出现了useExtendContext与其共存的用例证明插件体系可以自由叠加。GraphQL 版本支持graphql14~17仓库测试环境使用的是graphql17.0.2与graphql-modules3.1.1见 package.json。装饰器与反射使用 graphql-modules 的Injectable、ExecutionContext等装饰器时记得引入reflect-metadata测试文件同样在入口处import reflect-metadata。运行时要求Node.js 18 及以上engines字段约束。八、快速验证用测试环境跑一遍如果你想在本地观察插件行为仓库已内置完整的测试基础设施# 在仓库根目录安装依赖pnpm workspace 项目 pnpm install # 运行该插件的测试 pnpm jest packages/envelop/plugins/graphql-modules/test/use-graphql-modules.spec.ts测试基于envelop/testing的createTestkit无需启动真实 HTTP 服务即可验证 Query、Subscription、上下文合并与并发隔离四类场景是理解插件行为的快速入口。小结envelop/graphql-modules是一个小而关键的桥接插件它把 graphql-modules 的模块化 DI 能力接入 Envelop / GraphQL Yoga 的执行管线通过setSchema、setExecuteFn、setSubscribeFn三个钩子保证Injector的创建与销毁时机正确并让 resolver 可以随时通过context.injector.get(...)获取 Provider。配合 源码实现、测试用例 与 变更记录你可以安全地把既有 graphql-modules 项目迁移到 Envelop 或 GraphQL Yoga 之上而无需重写业务模块。赞分享后端API设计【免费下载链接】graphql-yoga Rewrite of a fully-featured GraphQL Server with focus on easy setup, performance great developer experience. The core of Yoga implements WHATWG Fetch API and can run/deploy on any JS environment.项目地址https://gitcode.com/gh_mirrors/gr/graphql-yoga点击查看免费下载相关推荐envelop/graphql-modules 插件解析在 GraphQL Yoga / Envelop 中接入 graphql-modules 依赖注入生命周期envelop/graphql modules 插件解析在 GraphQL Yoga / Envelop 中接入 graphql modules 依赖注入生后端API设计LunaTranslator 如何为中文源文本启用分词与拼音注音LunaTranslator 如何为中文源文本启用分词与拼音注音 用 LunaTranslator 翻译中文游戏或视觉小说时如果希望在译文显示区看到源文本被后端API设计GraphQL Yoga / Envelopenvelop/apollo-federation 插件接入 Apollo Federation Gateway 全解GraphQL Yoga / Envelopenvelop/apollo federation 插件接入 Apollo Federation Gateway后端API设计上一篇如何从零开始构建AI社会模拟AgentSociety终极指南下一篇eSearch万向滚动截屏一屏装不下的内容一次滚动全部截完创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考