WebSharper F#源码生成器新特性:编译前自动生成代码与输出自动合并
【免费下载链接】coreWebSharper - Full-stack, functional, reactive web apps and microservices in F# and C#项目地址: https://gitcode.com/gh_mirrors/core113/core
WebSharper F# 源码生成器是 WebSharper 10 新增的元编程特性:它在 F# 编译启动之前自动运行你的代码生成逻辑,把生成的.fs源文件加入编译;再配合changeTracking输出自动合并机制,你手动修改过的 JavaScript 输出在重新编译时也能被安全合并,而不是被覆盖。两大特性组合起来,让“手写 + 自动生成”的混合工作流真正可用。
为什么需要“编译前”源码生成?
传统做法里,代码生成往往发生在编译之后或依赖 MSBuild 自定义任务,时机晚、集成复杂。WebSharper 的 F# 源码生成器(F# source generators)直接把生成步骤嵌入编译管线:
- 🧩时机早:在 F# 编译器(FCS)开始编译前完成源文件生成,生成的代码享受完整的类型检查与重构支持
- 🔌按扩展名路由:项目中的非标准源文件(如自定义
.abc、.ws等扩展名)会被自动交给对应生成器处理 - ⚡可增量:生成器能拿到上一次的输出文件列表(
PreviousOutputFiles),从而只在新文件出现时生成,实现增量构建
该特性在 WebSharper 10.0.0 中随版本 10.0.0.651 发布,发布说明见 10.0.0.md。
一键启用:如何注册一个 F# 源码生成器
使用方式非常轻量:只需实现WebSharper.ISourceGenerator接口,并在程序集级别用WebSharper.FSharpSourceGenerator特性声明“扩展名 → 生成器类型”的映射。官方测试项目里的示例可以照抄:
- 特性声明:
[<assembly: WebSharper.FSharpSourceGenerator("ext", typeof<ExtGenerator>)] - 生成器实现
Generate input:根据输入路径生成输出文件,返回生成的文件数组
完整示例(仅 19 行)位于 FSharpSourceGeneratorTest.fs,其中还演示了通过input.Print把生成日志输出到编译日志中,方便排查问题。
编译器侧的发现与加载逻辑在 Compile.fs 中实现:它会扫描项目引用的程序集,找到声明了对应扩展名的FSharpSourceGeneratorAttribute,通过反射实例化生成器并校验其实现了 Interfaces.fs 中定义的ISourceGenerator接口。
增量生成:PreviousOutputFiles 让重复构建更快
生成器输入GenerateInput中的PreviousOutputFiles字段是关键增量信号:
- 首次构建:该字段为
None,生成器执行完整生成(如把源文件复制/转换为新扩展名文件) - 后续构建:字段携带上次生成的文件列表,生成器直接返回
None,跳过重复工作
在上面的示例中,这一模式让重复构建几乎零开销。生成文件的跟踪信息记录在 MSBuild props 文件中(包含<DependentUpon>关联关系),由编译器读取后还原“上次输出”,详见 Compile.fs 中对 props 文件的解析逻辑。
输出自动合并:手写修改不再被覆盖
这是最容易让新手“踩坑”的场景:WebSharper 会把你的 F#/C# 代码编译为 JavaScript bundle。如果你为了调试或打补丁直接改了输出的.js文件,下次构建就会被覆盖。
WebSharper 10 新增changeTracking设置 + 输出合并(output merging),解决方式很直观:
- ✅ 开启 changeTracking 后,编译器会追踪输出文件的历史版本
- ✅ 重新构建时,如果你的手动修改能自动合并进新输出,就保留修改;合并冲突时才提示
- ✅ 底层文件操作采用“备份 → 执行 → 失败回滚”的可撤销事务模式,任何一步失败都会自动还原,保证输出目录不会被写坏
这套安全合并逻辑实现在 Merging.fs 中,其中的UnrollableIOActions事务执行器确保目录替换、备份清理等操作原子化完成。
上手路径与延伸阅读
| 步骤 | 说明 | 参考位置 |
|---|---|---|
| 1️⃣ 定义生成器 | 实现ISourceGenerator,处理Generate | FSharpSourceGeneratorTest.fs |
| 2️⃣ 注册映射 | 程序集级FSharpSourceGenerator特性 | 同上 |
| 3️⃣ 理解管线 | 编译器如何发现并调用生成器 | Compile.fs |
| 4️⃣ 保护手写输出 | 启用 changeTracking 输出合并 | Merging.fs |
一句话总结:F# 源码生成器把“代码生成”提前到了编译前,输出合并则保护了你的手工修改——两者都是 WebSharper 10 元编程体系的实用组件,建议配合发布说明 10.0.0.md 中 #1476 与 #1513 两条特性说明一起阅读。
【免费下载链接】coreWebSharper - Full-stack, functional, reactive web apps and microservices in F# and C#项目地址: https://gitcode.com/gh_mirrors/core113/core
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考