
fusion-core双端兼容架构深度解析同一个App类如何在Server与Browser间无缝切换【免费下载链接】fusion-coreMigrated to https://github.com/fusionjs/fusionjs项目地址: https://gitcode.com/gh_mirrors/fu/fusion-corefusion-core 是 FusionJS 框架的核心运行库它用一个App类同时搞定服务端渲染SSR和浏览器端渲染——这就是经典的双端兼容架构。你写一份new App(el, render)在 Node 服务器里它跑 SSR 输出 HTML在浏览器里它执行客户端渲染与水合业务代码几乎零改动。本文带你快速看懂这个架构是如何实现的以及它的依赖注入 中间件设计为什么能让同一套插件在两端无缝运行。它解决什么问题传统项目里服务端和浏览器端往往要维护两套入口一个渲染 HTML 字符串一个操作 DOM。fusion-core 的思路是把差异封装在框架内部对外只暴露一个App类️Server 端基于 Koa 的 HTTP 应用负责 SSR 生成 HTML 页面Browser 端客户端渲染 水合hydration接管服务端产出的 DOM共享逻辑所有插件、中间件、Token 注册代码两端通用架构总览1 个入口 1 个基类 2 个子类整个双端兼容结构非常清晰一共只有 3 层层级文件职责入口选择src/index.js根据运行环境返回ClientApp或ServerApp公共基类src/base-app.jsFusionAppToken 注册、依赖解析、中间件编排服务端子类src/server-app.js内置 Koa、SSR 决策与服务器渲染器浏览器端子类src/client-app.js内置水合逻辑与客户端渲染器入口处的选择逻辑只有一行见 src/index.jsexport default (__BROWSER__ ? clientApp() : serverApp());__BROWSER__是编译期常量打包工具在构建浏览器 bundle 时把它替换为true构建 Node 产物时替换为false。也就是说—— 不是运行时如果判断而是打包时就确定了拿哪个类两端各自只保留自己需要的代码最终产物里没有死分支。package.json 中的browser字段还会把dist下的服务端文件映射为浏览器版本双重保险。基类 FusionApp双端兼容的公约数所有跨端能力都沉淀在 src/base-app.js 的FusionApp基类里它提供 4 个统一 APIregister第 50 行注册插件或配置值配合 Token 形成依赖注入middleware第 113 行注册中间件两端通用enhance第 119 行增强已有依赖例如定制 SSR 判断逻辑resolve第 143 行按依赖图解析所有插件循环依赖直接报错Token 是这个系统的接口命名定义在 src/tokens.jsElementToken应用的根元素RenderToken如何执行渲染服务端渲染成字符串 / 浏览器渲染进 DOMSSRDeciderToken控制哪些请求走 SSRHttpServerToken需要访问底层 HTTP 服务时注入正因为渲染函数只是RenderToken的一个实现基类代码完全不关心你在哪一端、用什么虚拟 DOM 库——这就是框架无关的关键。Server 端SSR 服务端渲染是怎么跑的ServerApp在构造函数里src/server-app.js做了三件事创建一个 Koa 实例并开启proxy注册请求上下文中间件 src/plugins/server-context.js注册 SSR 中间件 src/plugins/ssr.js它依赖SSRDeciderToken决定是否渲染SSR 决策的默认规则很实用src/plugins/ssr.js静态资源路径.js/.png/.json等→ 直接放行不渲染搜索引擎爬虫user-agent 匹配bot/crawler/spider→ 强制 SSR保证 SEO普通请求 → 只有Accept头包含text/html才走 SSRfetch/XHR 请求自动跳过渲染本身由 src/plugins/server-renderer.js 完成调用render(ctx.element)得到 HTML 字符串写入ctx.rendered最后拼进完整页面模板含head、body、预加载提示等。整个过程还内置了 Timing 计时帮你观测渲染耗时。 想跳过某些路由的 SSR用app.enhance(SSRDeciderToken, ...)增强即可无需改动框架。Browser 端水合与客户端渲染ClientAppsrc/client-app.js对称地注册了水合中间件 src/plugins/client-hydrate.js从服务端序列化的全局变量__ROUTE_PREFIX__读取路由前缀把根元素写入ctx.element客户端渲染器 src/plugins/client-renderer.js在resolve()阶段注入负责把虚拟 DOM 渲染进真实页面它最巧妙的地方在callback()第 27 行浏览器没有 Koa于是它手工构造了一个轻量 ctxurl、element、body然后走同一条中间件链。这样一来服务端中间件写出来的逻辑比如往ctx.template里塞数据在浏览器端原样可用。为什么同一份插件能两端运行答案在中间件的抽象上。Fusion 的中间件是(ctx, next) Promise形态借鉴 Koa其中next()调用 虚拟 DOM 渲染发生的时刻服务端ctx继承完整 Koa 能力request / response / cookies / redirect浏览器端ctx提供精简版属性业务代码里如需环境分支用__NODE__编译期常量即可例如官方 README 中的示例const render el __NODE__ ? renderToString(el) // 服务端渲染成 HTML 字符串 : ReactDOM.render(el); // 浏览器渲染进 DOM打包时死分支会被剔除双端产物都保持精简。双端一致性如何验证项目用成对的测试文件守护两端行为值得学习服务端测试src/tests/index.node.js——覆盖 SSR 决策、爬虫识别、HTML 转义、重定向等浏览器端测试src/tests/index.browser.js——覆盖水合 ctx 构造、渲染调用次数同一套断言风格分别在 Node 与浏览器unitest --browser--node中执行任何一端的行为漂移都会被立刻发现。历史 API 变化也记录在 docs/migrations/00043.md方便排查旧写法。总结双端兼容架构的 3 个设计要点设计要点实现方式收益编译期选端__BROWSER__三元 package.jsonbrowser 字段产物零冗余接口下沉基类Token DI 中间件统一收敛在FusionApp插件两端通用行为对齐两端都实现register / middleware / callbackAPI 心智负担最小一句话总结fusion-core 的双端兼容不是if 浏览器 else 服务器的粗暴分支而是用依赖注入把环境差异变成可插拔的 Token 实现——基类稳定不动Server 与 Browser 各自只补上自己那几块拼图于是同一个App类就能在两端无缝切换了。 想动手体验克隆仓库git clone https://gitcode.com/gh_mirrors/fu/fusion-core从 src/index.js 的入口一路读下去十分钟就能看懂全貌。【免费下载链接】fusion-coreMigrated to https://github.com/fusionjs/fusionjs项目地址: https://gitcode.com/gh_mirrors/fu/fusion-core创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考