搜索/构建与另一个Web框架行为一致的兼容层

构建与另一个Web框架行为一致的兼容层

在多个运行时中重新实现另一个Web框架的行为时使用。先移植该框架的测试,保持请求处理顺序和运行时边界,统一文件路径写法,只通过所有检查都已通过的pull request合并。

要使用这个AI规则
## 把目标框架的测试和代码当作规范 把兼容性视为证据问题。目标框架的测试和实现比直觉更可靠地定义了预期行为。 每次增加功能或修复缺陷时: 1. 广泛搜索上游的单元测试和端到端测试套件,包括相关名称、错误、无效输入和边界情况。 2. 阅读对应实现,了解执行顺序、默认值和失败行为。 3. 如果代码无法说明某项行为是否有意为之,就搜索 issue 或以前的设计讨论。 4. 在实现更改之前移植相关测试用例,并将每个移植用例链接到其上游测试。 5. 在更改说明中记录证据。 使用本地浅克隆快速搜索源代码和测试。只有在无法使用该克隆,或问题需要参考当前讨论时,才使用远程代码搜索。 如果兼容层出于安全、部署或平台原因需要有意采用不同的行为,应明确记录这项决定。绝不能把意外偏差伪装成功能。 ## 先写失败的测试,并一起修复开发、生产和edge入口 先编写一个会失败的针对性测试,再实现满足已验证契约的最小更改。 - 运行所更改子系统的测试文件以及与其直接耦合的测试。 - 为集成行为添加 fixture 输入;将示例保留用于面向用户的演示。 - 迭代期间使用测试名称筛选器。 - 除非更改影响共享路由、构建基础设施、虚拟模块或通用测试辅助程序,否则让 CI 运行完整套件。 - 更改共享基础设施时,只将本地验证扩展到受影响的横切范围。 让验证与所有权对应:垫片需要垫片测试,路由需要路由顺序测试,缓存需要缓存测试,构建或部署更改需要构建测试。 请求处理往往分别存在于开发、生产、服务端渲染和边缘入口点中。检查拥有同一行为的每项实现,并在同一项更改中修复对等差距,不要留下已知的重复问题。 ## 跨运行时边界明确传递请求数据,并保持生成代码精简 相互分离的构建或渲染环境可能拥有彼此独立的模块图和模块状态。绝不要假设在一个环境中设置请求状态会改变另一个环境。 - 跨环境边界显式传递 pathname、参数、标头、cookie 和其他请求上下文。 - 在渲染前一刻初始化上下文,并在渲染后清理。 - 将请求作用域状态和轻量公共门面与重量级实现分开。 - 同时验证流式消费和清理时机。 生成的入口模块应只包含特定于路由的 import、manifest 和精简连接代码。将请求编排、缓存策略、方法分派、重定向、错误处理、标头合并和其他可测试行为移入普通的类型化模块。 直接对提取出的辅助程序进行单元测试。生成代码测试应断言委派和连接关系,而不是匹配大段实现字符串。 在底层 bundler plugin 与兼容层之间保持清晰的所有权边界。plugin 可以负责转换、序列化、多环境构建、CSS 处理和 hydration 引导,而兼容层负责路由、请求生命周期、布局组合、导航、缓存和 API 垫片。 ## 统一文件路径,并用完整的多环境流水线构建 用作模块 ID 或生成 import 的文件系统路径需要在所有操作系统上采用一套规范分隔符策略。 - 在源代码中使用既保留原生语义又返回规范标识符的路径抽象。 - 只规范化外部来源的值,例如 process 工作目录、已解析模块、真实路径、glob 输出和 bundler 报告的 ID。 - 不要反复规范化已经由规范路径层生成的值。 - 将 URL 反斜杠清理与文件系统路径处理分开。 - 记录任何确实需要的原生路径例外,并用 lint 检查。 测试应使用原生路径 API 构造输入,让 Windows 提供真实的反斜杠。只对预期输出进行规范化。完全使用正斜杠构建的跨平台测试无法检测 Windows 规范化回归。 生产构建必须使用框架 plugin 完整的多环境 builder 流水线。通用的单环境构建调用可能在不发出提示的情况下跳过必需的 server、renderer 和 client 阶段。 工具链发生大版本变更时,应优先采用其当前的 transformer、dependency optimizer 和 bundler option 系列。将旧版 option 名称视为迁移目标。 虚拟模块还需要显式处理带根前缀的 ID、已经解析的 null 前缀,以及不存在物理模块位置时的绝对 import。 ## 让常见请求保持轻量,并明确缓存行为 不要让特定功能的运行时进入常见请求路径。 - 在动态 import 可选行为之前,使用低成本的请求或路由 metadata 判断是否适用。 - 不需要运行时代码时使用 type-only import。 - 在 JavaScript handler 运行之前筛选 bundler hook,排除依赖项、生成的运行时、prebundle 和不可能匹配的语法目标。 - 将轻量状态和注册模块与缓存、导航或渲染实现分开。 - 重用已计算的缓存键和请求派生值。 - 将不可变表达式和表提升到外部。 - 尽可能将确定性解析和资产选择移到构建时。 在所有权、失效策略和运行时对等性明确之前,不要添加缓存。如果更小的模块图会造成陈旧代码、不同的运行时条件或损坏的平台 bundle,就不能算作收益。 保持存储 handler 简单,并将增量再生成策略置于其上层。分别定义 stale-while-revalidate 行为、single-flight 再生成、再验证 metadata 和 tag 失效。 超过时限的条目可以在再生成期间以陈旧状态返回;显式失效的条目则应删除。以声明方式选择 backend,保留安全的默认项,并在首次使用前注册可选 adapter。 ## 按目标框架的顺序处理请求 将目标框架的请求生命周期建模为有序契约: 1. 静态配置标头针对原始请求求值。 2. 静态重定向针对原始请求求值。 3. middleware 运行,并可能 rewrite、redirect 或修改标头。 4. 文件系统处理前的 rewrite 针对 middleware 处理后的状态求值。 5. 解析静态路由和文件系统路由。 6. 运行文件系统处理后的 rewrite。 7. 解析动态路由。 8. 运行 fallback rewrite。 不要仅仅因为最终响应看起来等效就移动某个阶段。当 middleware 修改请求时,条件匹配也可能发生变化。 记录已知的对等差距,而不是将其隐藏。保留有意设定的差异,例如哪些静态资产绕过 middleware,哪些公共文件经过它。 对于持续演进的 API,只有当兼容性契约同时要求新旧访问模式时,才支持两者。例如,附加了解析后字段的 promise 可以同时支持 await 后的参数访问和直接参数访问。 使用公共 API import 的第三方库可能通过 alias 或扩展名规范化来运行。依赖构建 plugin 或内部 API 的库需要显式集成;仅安装并 import 并不足够。 ## 不绕过lockfile,只通过检查全部通过的pull request合并 在无人值守安装期间,绝不要绕过 frozen lockfile。如果依赖解析确实需要更改 lockfile,应停止操作,并请用户亲自执行或授权该操作。精确版本和 integrity hash 是供应链边界。 绝不要直接推送到受保护的默认分支、绕过分支保护或使用管理员权限强制合并。请按以下顺序操作: 1. 创建范围明确的 feature branch。 2. 进行最小且连贯的更改,并运行针对性检查。 3. 按照仓库要求的消息约定 commit。 4. 推送该分支并创建 pull request。 5. 等待每一项必需的 format、type、unit 和 end-to-end 检查通过。 6. 修复失败,而不是绕过失败。 7. 通过批准的方法合并并删除该分支。 让发布自动化从 conventional commit 中导出 changelog metadata。只有在有意进行追溯性重新分类时,才使用文档规定的覆盖机制;不要手工编辑生成的发布产物。 进行大型重构时,采用小型 stacked change:每项更改提取一处内聚边界、添加针对性的辅助程序测试并更新委派断言。 针对不受信任贡献的 CI 必须在没有 secret 且只有只读权限的条件下运行。携带 secret 的 preview workflow 必须跳过 fork,除非获授权的 maintainer 通过设有身份门禁的 command 明确触发。 每个已部署示例都需要注册到 build matrix,并配备验证预期 route、status 和 content 的 smoke test。只有必需检查和部署后证据都通过,才算完成发布或部署。