练习时长两年半的 boss:RazorVue,你的梦想还在吗?
练习时长两年半的 boss:RazorVue,你的梦想还在吗
当初的愿望实现了吗,事到如今只好祭奠吗。两年半之后,RazorVue 已经从一组探索方案变成了一条有明确输入、输出和边界的生产管线。
最初的梦想
Jazor 的目标一直是:用 C# 写前端,编译成浏览器可以执行的 JavaScript。静态 C# 模块已经有完整的 Roslyn IOperation、SemanticWalker、白名单和 Emit 管线;RazorVue 则把同一套编译能力接到官方 Razor Source Generator 的结果上。
这里有一个容易混淆的地方:RazorVue 不是把 Blazor 运行时搬到浏览器,也不是把 Razor 文件转换成另一个 .vue 文件。它保留 Razor 的创作入口,最终交给 Vue 的运行时,并输出 Vue render-function 模块。
一、RazorVue 的正式入口
Razor SDK 负责处理 Razor 语法和组件绑定。官方 Source Generator 完成后,RazorVue 取得最终 Compilation,从生成的 BuildRenderTree 方法对应的 Roslyn IOperation 开始分析:
Razor 源码
-> 官方 Razor Source Generator
-> GeneratorDriver 完成后的 final Compilation
-> Jazor.Vue hook / analyzer payload
-> BuildRenderTree 的 Roslyn IOperation
-> Jazor.Compiler / SemanticWalker
-> Vue render-function .mjs
-> Jazor.Emit 物化、manifest 和 bundle
这个边界很重要。当前实现不读取 Razor IR、RazorCodeDocument 或 RazorCSharpDocument,不二次解析生成的 C# 文本,也不依赖 IL 织入来改变 Razor Generator 的执行过程。Razor Generator 仍然负责 Razor,Jazor 负责最终 C# 语义到 JavaScript 的 lowering。
二、为什么不模拟 Blazor 运行时
Jazor 从一开始就没有打算把完整 .NET 运行时塞进浏览器。StateHasChanged、ShouldRender 和 SetParametersAsync 这些 Blazor 运行时协议不属于 RazorVue 的主模型;响应式状态、组件更新和 props 传递由 Vue 接管。
因此 RazorVue 的定位不是“在 Vue 上复刻 Blazor”,而是“保留 Razor 的创作方式,按 Vue 的运行时语义生成代码”。能直接表达为 Vue render function 的内容进入输出;无法保持语义的 Blazor 专属运行时行为则明确位于支持边界之外。
三、生成的 C# 为什么适合作为输入
Razor Source Generator 已经把模板展开成普通 C#。组件元素、属性、事件和模板最终表现为 BuildRenderTree 中的调用,Roslyn 同时保留了类型绑定、重载决议、参数转换和源位置。
RazorVue 不需要重新猜测 Razor 的参数合法性:未知参数、必需参数和参数类型不匹配由 Razor SDK 在生成阶段检查。RazorVue 只消费已经绑定好的调用,并把其中属于 Vue artifact 的部分交给 Jazor.Compiler 翻译。这样,模板语义和 C# 语义各自只有一个权威来源。
四、组件输出与职责边界
当前产物是 Vue render-function .mjs,不是 .vue SFC。Jazor.RazorVue 负责生成 C# binding、识别组件、组织 artifact framing;Jazor.Compiler 负责 C# 表达式和方法语义的 lowering;Jazor.Emit 负责 catalog、物化、manifest、source map 和 bundle。
包的职责也已经分开:
Jazor提供编译器、分析器、生成器、Emit 和 MSBuild 集成。Jazor.Vue提供显式 opt-in 的 Razor hook 和 analyzer payload。Jazor.RazorVue负责 Razor 组件选择、binding 生成和 Vue artifact 组织。Jazor.Emit只负责输出物化与打包,不拥有 Razor hook 或 compiler lowering。
开发模式和生产模式也不是同一条开关:JazorMode=debug 物化 .mjs、source map 和 manifest;JazorMode=release 先物化中间产物,再由显式指定的 JazorTool=Deno 或 JazorTool=Netpack 生成 bundle。
五、当前已经打通的能力
当前主线覆盖了 Razor Source Generator 最终 Compilation 的组件选择、生成 BuildRenderTree 的语义遍历、属性和事件绑定、组件调用、插槽/模板传递,以及由编译器负责的表达式、闭包和异步 lowering。产物是可被 Vue 运行时消费的 render-function ESM 模块。
RazorVue 的生成测试持续覆盖这些契约,具体通过数量和快照内容以仓库当前测试为准。这里不再把某个历史测试数量或某组历史诊断 ID 当作产品定义;当前通用分析器诊断是 JAZOR001 到 JAZOR004,组件侧约束由 Razor、RazorVue hook 和 compiler 分层负责。
六、这条路线的价值
RazorVue 的难点不在于把标签字符串拼成 h() 调用,而在于把官方 Razor 生成的、已经完成 C# 绑定的语义,稳定地交给 Jazor 的通用 compiler lowering。这样可以复用确定性的符号绑定、白名单分派、import 收集、source origin 和 SourceMap,而不是再维护一套只服务 Razor 的 JavaScript 解释器。
两年半之后,答案不是“所有 Blazor 语义都被搬到了 Vue”,而是路线已经收敛:Razor 负责创作和绑定,Roslyn IOperation 负责事实,Jazor.Compiler 负责翻译,Vue 负责运行时,Emit 负责交付。这个边界比一组看起来更完整、实际却无法稳定维护的兼容层更有价值。

浙公网安备 33010602011771号