资讯详情

Egg 内部库 @eggjs/module-common 解读:上下文 Symbol、4.0 破坏性变更与生命周期钩子演进

📅 2026/10/10 5:48:48 | 华诺云谱 👁 阅读
Egg 内部库 @eggjs/module-common 解读:上下文 Symbol、4.0 破坏性变更与生命周期钩子演进
后端Web框架【免费下载链接】egg Born to build better enterprise frameworks and apps with Node.js Koa. https://codewiki.google/github.com/eggjs/egg项目地址https://gitcode.com/gh_mirrors/eg/egg点击查看免费下载导读eggjs/module-common是 Egg基于 Node.js 与 Koa 的企业级 Web 框架tegg 模块体系中的一个内部公共库其发布历史记录在 tegg/plugin/common/CHANGELOG.md 中。本文以这份变更日志为主线索结合仓库源码与测试讲清这个库的核心职责——导出三个贯穿 tegg 运行时的上下文 Symbol并完整解读 4.0.0 的破坏性变更与 3.8.0 引入的EggObjectLifecycle钩子能力。读完本文你将掌握TEGG_CONTEXT/EGG_CONTEXT/ROOT_PROTO三个符号在 Egg 请求生命周期中的实际定位以及如何从源码与测试层面验证这些底层约定。这份 CHANGELOG 记录了什么首先需要明确一个事实eggjs/module-common并非面向业务开发者的插件其 README.md 开头就明确说明This is an internal tegg library, you probably shouldnt use it directly.即它是 tegg 体系内部使用的库普通应用开发者一般不会直接引用它。因此它的 CHANGELOG 也带有典型的 monorepo 自动生成特征——从0.2.0到4.0.0-beta.4的数十条版本记录中绝大多数条目都标注为Version bump only for package eggjs/egg-module-common意味着该版本本身没有独立变更仅是随整个 tegg 仓库本仓库对应目录为 tegg整体发版而做的版本号对齐。但这并不意味着这份日志没有信息量恰恰相反它浓缩了三个关键事实包的真实面目这是一个只导出少量约定符号的协议定义层几乎零业务逻辑4.0.0 的破坏性变更对 Node.js 版本与 Egg 主版本提出了硬性要求3.8.0 的功能里程碑实现了EggObjectLifecycle钩子影响整个对象创建链路。下面逐层展开。包的本质仅导出三个上下文 Symbol 的协议层该库的全部源码只有 src/index.ts 一个文件、三行导出// ctx[TEGG_CONTEXT] is the tegg context, aka teggCtx export const TEGG_CONTEXT: symbol Symbol.for(context#teggContext); // teggCtx.get(EGG_CONTEXT) is the egg context, aka ctx export const EGG_CONTEXT: symbol Symbol.for(context#eggContext); // teggCtx.get(ROOT_PROTO) is the root proto, equivalent to ctx[ROOT_PROTO] export const ROOT_PROTO: symbol Symbol.for(context#rootProto);三个导出均为Symbol.for(...)全局注册表符号这意味着只要各个包通过eggjs/module-common拿到同一符号它们在任何模块实例间都能共享同一键不会因重复打包或双份依赖而产生键不一致的问题。这正是module-common的common意义所在它为 tegg 各模块提供了一套稳定的上下文约定而约定本身是符号而非字符串天然规避命名冲突。测试用例 也印证了这一点——它通过 vitest 快照断言了导出集合的稳定性import { expect, test } from vitest; import * as exports from ../src/index.ts; test(should export stable, async () { expect(exports).toMatchSnapshot(); });对应的快照文件期望导出集合精确等于EGG_CONTEXT: Symbol(context#eggContext), ROOT_PROTO: Symbol(context#rootProto), TEGG_CONTEXT: Symbol(context#teggContext),快照测试的存在说明这三个符号是跨包共享的稳定协议任何意外改动改名、删除、替换都会立刻被测试捕获。这与 CHANGELOG 中多数版本只有 version bump 相互印证契约一旦稳定代码层面便很少需要变更。三个 Symbol 在 tegg 运行时中的实际角色虽然这个库自身只有三行代码但它导出的符号被整个 tegg 插件栈深度使用。从源码结构可以梳理出各自的分工TEGG_CONTEXT定位 tegg 上下文ctx[TEGG_CONTEXT]存放的是当前请求对应的 tegg 运行时上下文对象。在 tegg/plugin/tegg/src/lib/EggContextImpl.ts 中构造器把自身挂到 egg 的ctx上constructor(ctx: Context) { super(); this.set(EGG_CONTEXT, ctx); ctx[TEGG_CONTEXT] this; const tracer ctx.tracer as { traceId: string } | undefined; this.id IdenticalUtil.createContextId(tracer?.traceId); }在 tegg/plugin/tegg/src/app/extend/context.ts 中扩展出的ctx.teggContextgetter 直接从该符号取值并在上下文尚未就绪时抛出明确错误get teggContext(): TEggContext { const ctx this as unknown as Context; if (!ctx[TEGG_CONTEXT]) { throw new Error(tegg context have not ready, should call after teggCtxLifecycleMiddleware); } return ctx[TEGG_CONTEXT] as TEggContext; }请求入口中间件 tegg/plugin/tegg/src/lib/ctx_lifecycle_middleware.ts 会先判断ctx[TEGG_CONTEXT]是否已存在以避免重复创建然后基于该符号完成 tegg 上下文的初始化、执行与销毁。此外 tegg/plugin/tegg/src/lib/run_in_background.ts 在劫持ctx.runInBackground时也用它判断当前是否处于 tegg 上下文内从而决定走 tegg 的后台任务链路还是 Egg 原生链路。EGG_CONTEXT从 tegg 上下文回溯 egg 上下文EGG_CONTEXT是反向映射从 tegg 上下文对象取回原始 eggctx。在 tegg/plugin/tegg/src/lib/EggContextHandler.ts 中可以看到它被用来在 tegg 运行时中恢复 egg 上下文并注入异步存储async runR(eggContext: EggContext, fn: () PromiseR): PromiseR { const ctx eggContext.get(EGG_CONTEXT); return await this.app.ctxStorage.run(ctx, fn); }在 tegg/plugin/controller/src/lib/AgentControllerObject.ts 中SSE 流式响应处理同样依赖它取出真实eggCtx如关闭自动响应、操作ctx.res等。而 tegg/plugin/eventbus/src/lib/EggEventContext.ts 中eventbus 通过createAnonymousContext()创建匿名 egg 上下文再同样用这两个符号完成双向挂载——可见该协议不只服务于 HTTP 请求还覆盖事件总线等场景。ROOT_PROTO请求对象创建入口ROOT_PROTO记录了当前上下文应创建的根原型root proto用于兼容原生 Egg Controller 的 tegg 对象创建。它由 tegg/plugin/controller/src/app/middleware/tegg_root_proto.ts 这一全局中间件写入export default (): MiddlewareFunc { return async function teggRootProto(ctx, next) { ctx[ROOT_PROTO] ctx.app.rootProtoManager.getRootProto(ctx); return next(); }; };随后 tegg/plugin/tegg/src/lib/EggContextCompatibleHook.ts 与 tegg/plugin/aop/src/lib/AopContextHook.ts 在preCreate阶段检查该符号若存在根 proto就按根 proto 创建对象否则回退到逐条ctx.addProtoToCreate的方式。这与 ctx_lifecycle_middleware.ts 中teggCtx.set(ROOT_PROTO, rootProto)的传递逻辑一起构成了Egg Controller 兼容模式下对象创建的完整链路。4.0.0破坏性变更的硬性要求CHANGELOG 中专门设置了## 4.0.0段落这是本包为数不多的人工维护内容包含两条破坏性变更* drop Node.js 22.18.0 support * only support egg4并在末尾注明这是 [eggjs/egg] 仓库 issue #5434 的一部分。也就是说eggjs/module-common从 4.0.0 起最低 Node.js 版本提升到 22.18.0——这一要求可以在 package.json 的 engines 字段中直接验证engines: { node: 22.18.0 }同时整个包的 package.json 已切换为 ESM 生态配置type: modulemain/module/types统一指向./dist/index.js与./dist/index.d.ts开发期exports则直接指向./src/index.ts发布时通过publishConfig切换回 dist 产物。仅支持 egg4 主版本——这与整个仓库正在推进的 Egg 4.x 主线CHANGELOG 顶部提示后续发版统一走 GitHub Releases 与 release.yml 发布工作流保持一致。对于仍在 egg3 上运行旧版 tegg 的应用本包 4.x 不在其兼容范围内。因此如果你的项目正在升级 tegg 相关依赖并看到本包进入 4.x应确保运行环境满足 Node.js ≥ 22.18.0并且应用基于 egg4。3.8.0 功能里程碑EggObjectLifecycle 钩子在满屏 version bump 中3.8.0 是少数携带真实功能变更的版本其记录为* impl EggObjectLifecycle hook in decorator这意味着从该版本起tegg 在装饰器层实现了对象生命周期钩子。所谓EggObjectLifecycle是 EggObject 从创建到销毁过程中暴露的预置回调点。从 tegg/core/runtime/src/impl/EggObjectImpl.ts 的调用顺序可以推断完整链路先是EggObjectLifecycleUtil.objectPreCreate触发preCreate钩子随后按原型元数据依次调用postConstruct、preInject注入完成后触发postInject与objectPostCreate整个流程由EggObjectLifecycleUtil统一调度。AOP 模块就是该钩子的直接受益者之一。tegg/core/aop-runtime/src/EggObjectAopHook.ts 通过EggObjectLifecycleProto()注册为生命周期钩子并在postCreate阶段为对象装配切面代理而 tegg/plugin/aop/src/lib/AopContextHook.ts 则通过EggContextLifecycleProto()在上下文级preCreate时按需注入请求级切面。可以推断3.8.0 的这次实现是把此前散落在各运行时的生命周期逻辑统一收敛到 decorator/runtime 层为后续 aop、background-task 等模块复用同一套钩子机制奠定了基础。如何阅读这份版本历史从0.2.02022-01-20到4.0.0-beta.42025-03-15本包的版本演进大致可以分为三段0.2.0随最初 tegg 发版首次进入版本管理3.x 主线3.8.0 ~ 3.52.0绝大多数为随仓库的同步 version bump唯一的实质性功能变更集中在 3.8.0EggObjectLifecycle 钩子其余保持契约稳定4.0.0-beta.x 及 4.0.0切换发布渠道、提升 Node 基线、锁定 egg4进入新的主版本周期。对维护者或想要深入 tegg 源码的读者来说遇到这种几乎全是 version bump的 changelog 不必惊讶——它是 monorepo 采用 Conventional Commits 与 lerna/lerna-lite 类工具自动生成、逐包对齐版本的正常产物CHANGELOG 中已声明采用 Conventional Commits 提交规范。真正值得关注的是那些不标注 version bump 的条目它们才是本包功能演进的真实脉搏。在仓库中验证与跟进若想自行验证以上结论仓库中提供了完整的证据链包定义与元信息tegg/plugin/common/package.json引擎要求、ESM 配置、发布配置全部实现源码tegg/plugin/common/src/index.ts仅三个 Symbol 导出导出稳定性测试tegg/plugin/common/test/index.test.ts 及其快照符号的实际消费者主要在 tegg/plugin/tegg 插件、tegg/plugin/controller 插件、tegg/plugin/eventbus 插件以及 tegg/core/runtime 中。包内自带的 npm script 只有typecheck执行tsc --noEmit说明其代码量之小而稳定。由于它是纯内部库官方不推荐直接使用如需了解其运行时语义从 EggContextImpl 和 ctx_lifecycle_middleware.ts 这两个入口开始阅读是最直接的路径。赞分享后端Web框架【免费下载链接】egg Born to build better enterprise frameworks and apps with Node.js Koa. https://codewiki.google/github.com/eggjs/egg项目地址https://gitcode.com/gh_mirrors/eg/egg点击查看免费下载相关推荐Pydantic 版本政策全解析V1/V2/V3 演进、破坏性变更边界与实验性功能生命周期Pydantic 版本政策全解析V1/V2/V3 演进、破坏性变更边界与实验性功能生命周期 Pydantic 是当前 Python 生态中使用最广泛的数据校验后端序列化JAX 变更日志深度指南读懂版本演进、弃用周期与破坏性变更以 0.4.31 为例JAX 变更日志深度指南读懂版本演进、弃用周期与破坏性变更以 0.4.31 为例 本文基于 JAX 仓库的官方变更日志 CHANGELOG.md http机器学习深度学习Rebass 4.0 完整 Changelog 解读从 2.x 到 4.0.7 的组件库演进与破坏性变更迁移指南Rebass 4.0 完整 Changelog 解读从 2.x 到 4.0.7 的组件库演进与破坏性变更迁移指南 导读 本篇以 Rebass 仓库的 CHANUI组件前端设计系统上一篇Windows Cleaner面向现代Windows系统的智能资源管理架构下一篇显卡驱动彻底清理终极指南为什么你需要Display Driver Uninstaller创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑