@modern-js/runtime-utils 技术解析:Modern.js 运行时工具库的架构设计与能力演进 前端后端Web框架【免费下载链接】modern.jsA progressive web framework based on React and Rsbuild.项目地址https://gitcode.com/gh_mirrors/mo/modern.js点击查看免费下载modern-js/runtime-utils是 Modern.js 框架中承载运行时公共能力的工具包覆盖缓存cache、存储storer、请求解析request、路由与流式 SSRdeferred、文件读取FileReader等核心机制。本文以该包 CHANGELOG.md 的版本演进为主线结合 源码目录 与 测试用例深入讲解其模块划分、关键 API 的用法与底层实现帮助你理解 Modern.js 运行时是如何组织这些通用能力并在需要时正确使用它们。一、包定位从 v2.35.1 拆包到多子路径导出在 Modern.js v2.35.1提交6a1d46e中runtime utils 被从既有包中单独拆分成一个独立包即modern-js/runtime-utils。从此该包成为运行时runtime与服务器server之间共享工具能力的固定载体。从 package.json 的exports字段可以看出它采用按场景拆分子路径的设计这也是使用该包时最需要先理解的结构子路径对应源码适用场景modern-js/runtime-utils/routersrc/router.ts路由相关整体再导出 react-router并提供json/defer辅助函数modern-js/runtime-utils/router/rscsrc/rsc.tsRSCReact Server Component场景的路由工具modern-js/runtime-utils/browsersrc/browser/index.ts浏览器端嵌套路由渲染、deferred 数据modern-js/runtime-utils/nodesrc/node/index.tsNode 端SSR helpers、loader 上下文、序列化modern-js/runtime-utils/serversrc/server/index.ts服务器端嵌套路由匹配modern-js/runtime-utils/universal/requestsrc/universal/request.ts请求解析query、headers、cookie、hostmodern-js/runtime-utils/timesrc/time.ts高精度耗时测量modern-js/runtime-utils/parsedsrc/parsed.ts从 DOM 元素解析 JSONmodern-js/runtime-utils/storersrc/node/storer/index.ts带命名空间的存储抽象modern-js/runtime-utils/fileReadersrc/node/fileReader.ts带缓存的文件读取器modern-js/runtime-utils/urlsrc/url.ts路径归一化modern-js/runtime-utils/mergesrc/merge.ts深度合并对象modern-js/runtime-utils/cachesrc/universal/cache.tscache 函数与缓存容器exports中同时提供了modern:source指向src源码、types与defaultESM/CJS 产物三类入口注释明确说明ESM 由 runtime 包使用以便 tree-shaking。依赖方面该包直接依赖modern-js/types、modern-js/utils、lru-cache、react-router与serialize-javascript并声明react 18.3.1为可选 peer 依赖。二、模块划分browser / node / server / universal 四类场景从 src 目录结构 看源码按执行环境划分为四块browser/浏览器专用包含 nestedRoutes.tsx将约定式路由配置渲染为 react-router 路由元素与 deferreds.tsdeferred 数据实现fork 自 react-router v6 的 utils。node/Node 专用包含storer存储、fileReader.ts、serialize.ts 与loaderContextloader 上下文工厂。server/服务端入口目前提供 nestedRoutes.ts 中的matchEntry——将 URL pathname 按urlPath长度降序匹配到最具体的服务端路由。universal/跨端通用包含 async_storage、cache.ts 与 request.ts。这种按环境拆分子路径的做法是为了保证浏览器端产物不会意外携带 Node 依赖如serialize.ts的注释明确说明serialize-javascript只能在浏览器环境使用因此不通过index.ts导出只能走子路径引入这与 v2.62.1提交86213ae添加一个 server 目录用于存放通用的服务端工具函数的演进方向一致。三、SSR 缓存与全局存储storer 抽象与 MemoryContainerCHANGELOG 中最早的高价值功能点出现在v2.43.0提交d959200feat: support ssr cache, and global storer支持 SSR 缓存与全局存储器随后 v2.44.0提交0ed968c修正了缓存 container 的拼写。这一系列变更奠定了该包的存储基础设施。3.1 Storage Container 双层抽象存储能力由两层组成见 src/node/storerContainer底层键值容器接口定义get/set/has/delete/clear/forEach。Storage在容器之上叠加命名空间的封装所有 key 都会被转换为${namespace}:${key}并通过checkIsOwnkey在遍历时只暴露本命名空间的 key见 storage.ts。默认实现MemoryContainer基于lru-cachemax默认 256 MB、ttl默认 1 小时且sizeCalculation使用JSON.stringify(value).length估算条目体积见 container.ts。通过 createMemoryStorage 可快速创建一个带命名空间的内存存储import { createMemoryStorage } from modern-js/runtime-utils/storer; const storage createMemoryStorage{ count: number }(my-app); await storage.set(visits, { count: 1 }); await storage.get(visits); // { count: 1 } await storage.has(visits); // true await storage.delete(visits);3.2 cache 函数从 v2.65.2 到 v2.67.4 的持续强化缓存能力在 v2.65.2提交8837b85正式登场feat(runtime): support cache function getRequest function。此后经历多轮增强v2.65.5提交90a3c1c修复不同函数、相同参数的缓存串扰问题——实现中通过generateStableFunctionId对函数源码做哈希生成fn_${name}_${hash}前缀拼入缓存 key从机制上隔离不同函数v2.67.4提交3a66335/446939a/b00922e新增getKey、customKey、unstable_shouldDisable、缓存命中率统计onCache并支持plugin-router-v7。cache函数的核心实现位于 src/universal/cache.ts支持三种使用形态形态一不带 options 的请求内缓存服务端import { cache, withRequestCache } from modern-js/runtime-utils/cache; const getUser cache(async (id: string) fetchUser(id)); const handler withRequestCache(async (req: Request) { const a await getUser(1); const b await getUser(1); // 同一请求内命中缓存 return { a, b }; });实现上无 options 时通过getAsyncLocalStorage拿到当前请求上下文在requestCacheMapWeakMap以 Request 为键中为同一函数 同一参数缓存 Promise测试 cache-server.test.ts 验证了不同请求不共享缓存并发同参只执行一次嵌套 handler 复用缓存等行为。形态二带 options 的跨请求缓存import { cache, CacheTime, revalidateTag } from modern-js/runtime-utils/cache; const getPosts cache( async (page: number) fetchPosts(page), { tag: posts, // 标签支持 string | string[] maxAge: CacheTime.MINUTE * 5, // 新鲜期默认 5 分钟 revalidate: CacheTime.MINUTE, // 过期后的后台重新验证窗口 getKey: page posts:${page}, // 自定义 key 生成 onCache: info track(info), // 缓存统计回调 }, ); await revalidateTag(posts); // 使所有带 posts 标签的缓存失效选项完整说明来自 cache.ts 的类型定义与实现tag: string | string[]缓存标签。写入时会在存储中维护tag:${tag}→ key 列表的反向索引revalidateTag(tag)会遍历该列表删除对应缓存条目maxAge新鲜期默认CacheTime.MINUTE * 5revalidate在maxAge到maxAge revalidate区间内返回陈旧stale数据并触发后台重新验证通过ongoingRevalidations保证同一 key 只发起一次后台刷新getKey: (...args) string完全接管缓存 key 生成会覆盖默认的generateKey(args)customKey: ({ params, fn, generatedKey }) string在默认生成的 key 基础上做二次定制可用于让不同函数共享同一个缓存 key有对应测试用例onCache: (info: CacheStatsInfo) void每次命中的统计回调info.status为hit | stale | missmiss 时reason字段标注原因1当前请求禁用缓存、2未找到、3已过期、4解析失败、5执行出错unstable_shouldCache: ({ params, result }) boolean决定是否缓存本次结果例如只缓存 status ok 的响应unstable_shouldDisable配置级通过configureCache({ unstable_shouldDisable: ({ request }) ... })按请求动态关闭缓存如request.url包含no-cache时跳过缓存。配套常量CacheSizeKB/MB/GB与CacheTimeSECOND/MINUTE/HOUR/DAY/WEEK/MONTH也由该模块导出测试中还验证了 LRU 容量限制configureCache({ maxSize: 3 * CacheSize.KB })下大对象会挤掉旧缓存与对象体积估算estimateObjectSize行为。clearStore()可清空全部缓存与进行中的 revalidation。3.3 v2.57.0 的 mergeConfig 修复与 merge 函数v2.57.0提交916559a记录fix: mergeConfig function to return an object when the first configuration is not an object修复 mergeConfig使第一个配置非对象时返回对象。这正是 src/merge.ts 中merge函数的行为当target或source非纯对象isObject判定时直接跳过该次合并最终仍返回对象。merge的另一个关键设计是对复杂实例如 i18next 实例不做深合并isComplexInstance通过检测init/changeLanguage/t方法或isInitialized/language/store内部属性来识别遇到这类值直接整体替换而非递归合并从而避免破坏实例内部状态与循环引用导致的栈溢出。merge.test.ts 用 mock 的 i18next 实例与循环引用对象验证了这两个行为。四、请求上下文async storage、request 解析与 loader 上下文4.1 AsyncLocalStorage 请求上下文服务端请求上下文基于 Node 的async_hooks.AsyncLocalStorage实现见 async_storage.server.ts上下文对象承载monitors、headers、request、responseProxyheaders/status、activeDeferreds、deferredScriptKeys、serverPayload等字段。浏览器端入口 async_storage.ts 会直接报错提示不应在浏览器获取 async storage且通过动态import按环境加载服务端实现。该机制是 SSR 缓存按请求隔离、以及responseProxy控制响应头/状态码的基础——v2.52.0提交85ac453支持通过 data loader 控制页面状态码、v2.65.3提交58a1afd/087ae7c添加响应 API可设置响应头、状态码与重定向都依赖这一上下文传递。4.2 请求解析工具v2.65.2 的 getRequest 能力src/universal/request.ts 提供一组从标准Request对象提取信息的纯函数parseQuery(req)用URLSearchParams解析 query 为Recordstring, stringparseHeaders(request)将 headers 展开为普通对象getPathname(request)用正则^https?:\/\/[^/](\/[^?]*)提取 pathname注释说明 RegExp 比indexOf slice更快getHost(request)优先取X-Forwarded-Host回退Host并兼容多值逗号分隔parseCookie(req)将 Cookie 头解析为Recordstring, string。4.3 loader 上下文工厂src/node/loaderContext 提供createRequestContext基于一个Mapstring | symbol, unknown封装get/setkey 既可以是普通字符串也可以是带symbol与getDefaultValue()的LoaderContext对象createRequestCtx.ts用于在 data loader 之间传递共享数据。五、路由与流式 SSRdeferred、hydration fallback 与路径归一化5.1 router 子路径与 react-router 再导出v2.47.0提交9464c9c升级 react-router 相关依赖并导出所有 react-router APIv2.60.4提交c87813e更新 react-router 到最新版 只在 debug 模式下打印日志。src/router.ts 通过export * from react-router整体再导出并额外提供DEFERRED_SYMBOL标记 deferred 数据的 Symboljson(data, init?)与defer(data, init?)均标注deprecated建议改用Response.json其中defer在无init时直接返回原数据。5.2 deferred 数据与流式 SSR 补全v3.9.3src/browser/deferreds.ts fork 自 react-router v6 的实现核心是DeferredData类构造时遍历数据对象将 Promise 值包装为带_tracked/_data/_error标记的TrackedPromise通过AbortController支持取消并维护pendingKeysSet与subscribe订阅机制模块末尾还导出了activeDeferreds全局 Map用于跨请求跟踪活跃的 deferred 数据。最新的v3.9.3提交a9c110f修复了流式 SSR 场景的关键问题emit completion scripts for deferred fields serialized as pending during streaming SSR流式 SSR 中初始序列化为等待状态的 deferred 字段完成后发送通知。即在流式渲染时如果某个 deferred 字段在初始 HTML 中被序列化为 pending那么当它最终完成时服务端需要向浏览器追加发送完成脚本客户端才能正确 resolve 对应的 Promise。结合 nestedRoutes.tsx 中createLoader的逻辑可以看到完整链路loader 返回普通对象时会被privateDefer包装成DeferredData并注册进activeDeferreds服务端存在 async storage 的activeDeferreds中供流式渲染消费。5.3 hydration fallbackv3.9.1与 loading 组件v3.9.1提交2e6d853fix: use conventional route loading components as hydration fallbacks while initial route data is loading初始路由数据加载期间使用约定式路由的 loading 组件作为 hydration fallback。对应实现位于 nestedRoutes.tsx 的renderNestedRoute当路由配置了loading组件时会设置routeProps.hydrateFallbackElement nestedRoute.loading /让首屏数据未就绪时先渲染 loading 组件结合lazyImport与父级 loading会使用Suspense fallback{Loading /}包裹懒加载组件isLoadableComponent识别displayName Loadable的组件走fallbackprop 分支当组件为 undefined 时视为伪布局组件element直接渲染Outlet /并继承父级 loading。5.4 路径归一化normalizePathnameURL 相关能力在 CHANGELOG 中多次出现v2.48.1提交74749ae有时 url /a/ 应该等于 /av2.60.6提交c4894e6normalizePathname 应该处理好多个 / 的情况。src/url.ts 的实现用pathname.replace(/^\/|\/$/g, )去掉首尾多余斜杠后拼回前导/因此/api/与/api等价、//与/api//都会被归一化。url.test.ts 完整覆盖了这些边界用例。六、文件读取、序列化与耗时测量6.1 FileReader带存储缓存的文件读取v2.46.0、v2.65.4src/node/fileReader.ts 提供FileReader类readFile(path, encoding)先查缓存StorageBuffer | null命中则直接返回未命中时用fs.stat确认文件存在后读取并写入缓存文件不存在则缓存null。reset()清空整个缓存——这正是 v2.46.0提交78e2722修复的FileReader#reset 没有按预期清除缓存问题。v2.65.4提交f1cd095要求静态中间件始终使用系统 fs因此类内同时提供了readFile与readFileFromSystem两个方法后者始终走真实文件系统Fs。模块底部导出了单例fileReader new FileReader(createMemoryStorage(__file__system))。6.2 serializeJson 与 timeserialize.ts 导出serializeJson基于serialize-javascript的{ isJSON: true }模式序列化数据专用于服务端向浏览器注入数据时保证安全转义time.ts 的time()返回一个闭包计时函数首次调用记录基准时间再次调用返回毫秒级耗时s * 1e3 ns / 1e6。它在 nestedRoutes.tsx 的createLoader中被用于测量 loader 耗时并通过monitors.timing上报v2.65.2 提交1fe923c正是使用 monitors 代替 reporter 上报 Data Loader 耗时v2.67.4 提交03cf233则将 route id 中的/替换为_以保证 timing 名称合法。七、ESM 化与 React 版本策略v3.0.0、v3.6.0v3.0.0提交ecd247cfeat: esm runtime标志着运行时全面 ESM 化v3.6.0提交c34b53d则移除 React 17 支持并在浏览器运行时静态引入 react-dom/client。当前 package.json 中peerDependencies为react 18.3.1与react-dom 18.3.1均标记 optional便于纯 Node 工具场景使用与这一演进一致。此外 v2.58.2提交44c1bc4support esmserver、v2.49.0提交e8c8c5drefactor server以及 v3.8.0依赖更新b3a0709都属于围绕运行时与服务器适配的持续改造。八、版本演进速览与升级建议综合 CHANGELOG.md可将该包的关键能力按版本归纳如下版本关键变更能力含义2.35.1runtime utils 拆分为独立包包诞生2.43.0SSR cache global storer存储与缓存基础设施2.46.0FileReader#reset 修复文件缓存可靠性2.47.0升级 react-router 并导出全部 API路由能力对齐2.48.1 / 2.60.6URL 路径归一化修复/a/≡/a多斜杠处理2.52.0data loader 控制状态码响应控制2.57.0mergeConfig 非对象兼容、Runtime 插件通信工具健壮性2.62.1新增 server 目录模块划分完善2.65.2cache 函数 getRequest monitors缓存与观测体系建立2.65.3响应头/状态码/重定向 API响应控制扩展2.67.4getKey / customKey / unstable_shouldDisable / 缓存统计缓存能力完备化3.0.0esm runtime运行时 ESM 化3.6.0移除 React 17静态引入 react-dom/clientReact 版本基线提升3.9.1约定式 loading 组件作为 hydration fallback首屏体验优化3.9.3流式 SSR deferred 完成通知脚本流式渲染正确性对于使用 Modern.js 的开发者几点实用建议缓存优先选cache函数服务端无 options 形态天然按请求隔离适合同一请求内去重带 options 形态适合跨请求复用配合tagrevalidateTag做按业务维度的失效控制onCache可接入监控统计命中率理解不同函数同名参数隔离默认 key 包含函数身份哈希若希望跨函数共享缓存如同等语义的查询应显式使用customKeydeferred 数据依赖流式 SSR 补全机制升级到 v3.9.3 可修复流式场景下 deferred 字段完成通知缺失的问题使用前请确认服务端与浏览器端运行时版本一致子路径导入保持克制浏览器侧代码不要从modern-js/runtime-utils/node导入Node 侧注意serializeJson只能通过独立子路径使用避免把浏览器不兼容的依赖打进产物。本文涉及的源码与测试均可在当前仓库对应路径查看cache 实现 与 测试、storer、FileReader、deferreds、nestedRoutes、merge 及测试、url 及测试。赞分享前端后端Web框架【免费下载链接】modern.jsA progressive web framework based on React and Rsbuild.项目地址https://gitcode.com/gh_mirrors/mo/modern.js点击查看免费下载相关推荐Modern.js 运行时 modern-js/runtime 演进全解析Streaming SSR、路由运行时与插件体系Modern.js 运行时 modern js/runtime 演进全解析Streaming SSR、路由运行时与插件体系 本文以 Modern.js 仓库前端后端Web框架.NET MonoVM 运行时组件Runtime Components架构解析可插拔运行时能力的设计与实现指南.NET MonoVM 运行时组件Runtime Components架构解析可插拔运行时能力的设计与实现指南 导读 MonoVM 是 .NET 运行时在语言运行时标准库JIT编译编译器Modern.js Data Loader 全解析modern-js/plugin-data-loader 的构建期处理与服务端运行时机制Modern.js Data Loader 全解析modern js/plugin data loader 的构建期处理与服务端运行时机制 modern前端后端Web框架上一篇LinearDesign优化mRNA设计的革命性算法下一篇Synology HDD db技术方案突破群晖NAS硬盘兼容性限制的专业解决方案创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考