大多数人遇到"工具不支持"会绕路走。Brisa框架的作者选择直接改解析器源码——这背后是一套关于构建工具链的残酷成本计算。
从TypeScript编译器的泥潭里爬出来
![]()
维护过next-translate的开发者都懂那种痛。为了给Next.js页面自动注入国际化加载器,作者用了TypeScript编译器API。结果?每个页面文件都要调ts.createProgram(),完整类型检查器实例化,库解析全跑一遍。
最后只能靠noResolve: true和noLib: true硬压性能。解析器干了十倍于需求的活——他们只要AST,不要类型。
这种 overhead(额外开销)在大型项目里会指数级放大。作者算过账:Brisa需要解析每个源文件,分析导入、检测服务端/客户端组件、注入宏、转换JSX,全在AST层面完成。用TypeScript编译器等于给自己挖坑。
纯JavaScript解析器的速度暴力
Meriyah的卖点很直白:纯JavaScript实现,无原生绑定,无WASM加载,无编译步骤。调parseScript(code, { jsx: true, module: true, next: true }),微秒级返回ESTree(一种JavaScript语法树标准格式)AST。
Brisa的构建管线里,这个速度差是复利效应。每个源文件都过Meriyah,跑在AST().parseCodeToAST()里——先用Bun的转译器处理,再喂给Meriyah。输出是标准ESTree Program节点,用astring遍历、修改、再生代码。
这里有个细节:Bun的转译器+Meriyah的组合,相当于把"解析"和"类型无关的AST操作"解耦了。不需要的类型检查全部砍掉,只保留框架真正需要的语法分析能力。
renderOn="build"的实现陷阱
Brisa有个prerender(预渲染)功能,允许组件在构建时渲染。写法很直观:
AST转换检测到renderOn="build",把JSX替换成__prerender__macro()调用,并在文件顶部注入:
import { __prerender__macro } from 'brisa/macros' with { type: 'macro' };
那个with { type: 'macro' }是导入属性(import attribute),告诉Bun的打包器在编译期解析导入。组件在构建时渲染,结果注入为静态HTML。
用户写的是renderOn="build",框架底层却在手动构造ImportDeclaration和ImportAttribute AST节点,再再生代码。这套机制依赖Meriyah能正确解析和生成import attributes语法。
卡住的时刻:上游工具不支持新语法
问题来得直接:作者开始用Meriyah时,它还不支持import attributes。这不是配置能绕过去的——语法解析是硬门槛,不支持就是不支持。
选项很现实:等上游更新(时间不确定)、换解析器(迁移成本)、或者自己修。作者选了第三条路:给Meriyah提PR,亲手加上import attributes支持。
PR合并后,Brisa的整条预渲染管线才跑通。从"解析器不支持我的语法"到"我修解析器",这个跳跃的前提是深度理解AST工作机制——知道语法糖背后对应什么节点结构,知道怎么在不破坏现有功能的前提下扩展解析器。
小团队改底层工具链的隐性门槛
这件事的启示在于成本结构的重新计算。表面看,自己改解析器是"重投入";实际算总账,可能比绕路、等待、或换技术栈更便宜。
作者维护next-translate的经验说明:选错基础工具,后续的performance tuning(性能调优)是在还技术债。TypeScript编译器API功能完整,但为"类型检查"支付的 overhead 在只需要AST的场景里是纯浪费。
Meriyah的选型策略是精准裁剪:不要的功能坚决不要,用纯JavaScript实现换取部署简单性,用ESTree标准保证生态兼容。这种"刚好够用"的哲学,反而在特定场景下比全能型工具更高效。
但这也意味着要承担维护风险。当需要import attributes这种较新语法时,没有大公司背书的开源项目可能滞后。作者的解法是把"给上游提PR"纳入技术方案的可行选项——这要求团队有能力阅读、修改、测试解析器级别的代码。
AST操作正在成为框架开发的基础技能
作者提到AST Explorer是参考工具,自己也想为Kitmul建类似的东西。这个细节说明:现代JavaScript框架开发,AST操作已经从"高级技巧"变成"基础设施"。
编译时做代码转换、宏注入、服务端/客户端组件分离——这些功能都依赖解析→变换→再生这一流水线。框架作者必须能读懂AST结构,能在解析器不支持时定位问题甚至动手修复。
Brisa的案例展示了一条路径:当工具链的某个环节成为瓶颈,且该环节足够精简、边界清晰时,直接介入修改可能比等待或替换更可控。Meriyah的纯JavaScript实现降低了介入门槛——没有原生代码,没有复杂的构建系统,PR的review和合并周期相对可控。
但这条路也有边界。如果依赖的是V8级别的解析器,或者需要修改类型系统,小团队的介入成本会陡增。Meriyah的"简单性"既是性能优势,也是可hack性(可修改性)的来源。
当构建工具链的每个环节都可能成为瓶颈,框架作者需要的一套新能力是什么?是更深地扎进编译原理,还是在工具选型时就预留好"可替换"的接口设计?
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.