Hermes Parser JS 工具链演进全解析:从 WASM 解析器到 Flow/TS 生态七件套
2026/9/24 8:29:18 网站建设 项目流程
  • 语言运行时
  • 编译器
  • 移动开发

【免费下载链接】hermes

A JavaScript engine optimized for running React Native.

项目地址:https://gitcode.com/gh_mirrors/hermes/hermes
点击查看免费下载

导读

本篇文章围绕 tools/hermes-parser/js/CHANGELOG.md 记录的0.9.00.37.0版本演进,系统梳理 Hermes 引擎 JavaScript 工具链中七个 npm 包的定位、核心 API 与关键能力。文章既覆盖hermes-parser的完整解析选项与各包之间如何协同,也结合仓库源码与各包 README 说明其底层原理,帮助读者理解这套基于 C++ 编译器编译为 WebAssembly 的解析与转换体系,并能在 ESLint、Babel、Prettier 等真实工具链中直接落地使用。

一、包结构总览:一个引擎,七个 npm 包

Hermes 引擎本身是面向 React Native 优化的 JavaScript 引擎,其解析器由 C++ 编写。tools/hermes-parser/目录展示了这套体系的服务端构成:hermes-parser-wasm.cpp 负责将 C++ 解析器编译为 WASM,HermesParserJSSerializer.cpp 负责将解析结果序列化为 JS 对象,HermesParserDiagHandler.cpp 负责诊断信息收集。而tools/hermes-parser/js/下的 package.json 是一个 Yarn workspaces 管理的一体化 JS 仓库,由七个发布到 npm 的包组成:

包名职责定位
hermes-parser核心解析器,暴露parse(code, options)API,可解析 ES6、Flow、JSX
hermes-estreeHermes 解析器产出的 Flow-ESTree 规范的 Flow 类型定义
hermes-transformAST 遍历与变换工具,可配合 Prettier 打印源码
hermes-eslintESLint 自定义解析器,Flow 代码 lint 的推荐选择
flow-api-translator将 Flow 代码翻译为 Flow 定义(.flow)或 TypeScript 定义(.d.ts
prettier-plugin-hermes-parserPrettier 插件,让 Prettier 使用 Hermes 解析器打印代码
babel-plugin-syntax-hermes-parserBabel 插件,让 Babel 用hermes-parser替代@babel/parser

Changelog 中每个版本均按这些包的维度组织条目,因此理解这七者的分工,是读懂后续所有版本演进的前提。

二、hermes-parser:WASM 化的核心解析器

2.1 单个parse函数与完整配置项

hermes-parser的对外 API 只有parse(code, options)一个函数,其完整参数说明见 tools/hermes-parser/js/hermes-parser/README.md:

  • babelboolean,默认false。为true时输出符合 Babel AST 格式的 AST,否则输出符合 ESTree 格式的 AST。
  • allowReturnOutsideFunctionboolean,默认false。为true时不报"函数外出现 return 语句"的错误。
  • flow"all""detect",默认"detect"。设为"detect"时,仅在文件存在@flowpragma 的情况下,将歧义语法解析为 Flow 语法;设为"all"则无论是否存在 pragma 都按 Flow 语法解析。例如foo<T>(x)在无@flow注释且为"detect"时会被解析为两次比较运算,而设为"all"或带 pragma 时会被解析为带类型参数调用。
  • sourceFilenamestring,默认null。非空时该文件名会被写入 AST 中所有源码位置信息。
  • sourceType"module""script""unambiguous"(默认)。"unambiguous"模式下,若代码中出现 ES6 import/export 则自动判定为"module",否则为"script"
  • tokensboolean,默认false。为true时将所有 token 追加到根节点的tokens属性上。
  • transformOptionsobject,供相关 transform 使用。目前包含TransformEnumSyntax
    • enableboolean,是否启用 Flow Enums 语法变换,默认false
    • getRuntime(可选):() => Expression,返回指向 Flow Enums 运行时的表达式,默认require('flow-enums-runtime')

2.2 为什么快:C++ 编译为 WASM

babel-plugin-syntax-hermes-parser的 README 明确说明:"Hermes parser uses C++ compiled to WASM it is significantly faster and provides full syntax support for Flow"。也就是说解析核心不是 JS 实现的递归下降解析器,而是 Hermes 引擎自带的高性能 C++ 解析器通过 Emscripten 编译为 WASM 后在浏览器/Node 环境中运行。Changelog 0.16.0 中"Upgrade to latestemscripten(3.1.44 from 3.1.3)"这一条也印证了 WASM 工具链的持续升级;0.12.0 中"Fixprocess.exitCodebeing overridden when initializing WASM"则说明 WASM 初始化阶段对宿主环境的侵入也被仔细处理过。

2.3 语法能力随版本持续扩张

从 changelog 可以清晰看到解析器对语法支持不断追平 Flow 与 ECMAScript 前沿特性的过程:

  • Flow 类型系统(0.11.0):支持keyof、条件类型ConditionalTypeAnnotationInferTypeAnnotation、映射对象类型属性ObjectTypeMappedTypeProperty、类型谓词TypePredicateDeclareEnum
  • 类型节点独立化(0.33.0):unknownneverundefined类型解析为独立节点(UnknownTypeAnnotationNeverTypeAnnotationUndefinedTypeAnnotation);
  • 协变/逆变注解(0.35.0/0.36.0):支持readonly以及writeonlyin Tout T长格式类型参数变型;
  • 记录与模式匹配(0.33.0/0.26.0/0.28.0):解析 record 声明与表达式、match实例模式,以及持续迭代的实验性 Flow 模式匹配支持;
  • 声明语法(0.11.0):DeclareVariable新增kind属性(var/let/const),DeclareEnum支持解析;
  • JSX 增强(0.11.0/0.31.2):支持 JSX 元素中的类型参数、含-的 JSX 标识符;
  • TC39 新语法(0.34.0):解析 decorators,import ... with取代import ... assert,新增async hookasync component语法;0.21.0 起支持as const、不精确元组[...]、bigint 成员的 Flow Enums、单边类型守卫implies x is T

同时 AST 结构也在向 ESTree/Flow 规范对齐,例如 0.29.0 将ImportExpressionattributes字段重命名为options,0.33.0 将TupleTypeAnnotation.types重命名为elementTypessuperTypeParameters重命名为superTypeArguments——这类破坏性重命名正是为了与 Flow parser 及 ESTree 规范保持一致。

三、hermes-estree:类型层的"地基"

hermes-estree提供"Flow types for the Flow-ESTree spec produced by the hermes parser"(见 tools/hermes-parser/js/hermes-estree/README.md),即对解析器产出的 AST 节点的 Flow 类型定义。

changelog 中该包的改进反映了类型精度的持续打磨:

  • 谓词与判断函数(0.10.0):新增isExpressionisStatement谓词函数;0.23.0 采纳单边类型守卫implies x is T
  • 父节点强类型(0.9.0):为小规模父节点集合的节点提供显式类型化的parent
  • 可选链字段(0.11.0):修正MemberExpression在 Flow 中正确暴露optional属性;
  • 精确联合类型(0.16.0):改进DestructuringObjectPropertyWithShorthandStaticNameExportNamedDeclarationWithSpecifiersObjectTypeAnnotationBigIntLiteral等节点的类型;
  • 变型字段扩展(0.35.0/0.36.0):先新增readonly,再新增writeonlyinout到 variance kind 类型中。

由于hermes-eslinthermes-transform等都依赖这套类型定义做作用域分析与变换,hermes-estree的类型正确性是整个工具链安全的基石。

四、hermes-transform:可预测的 AST 变换

4.1 设计理念:遍历可读、变换可控

hermes-transform是"traversing and transforming a hermes AST"的包,其 README 表明它借鉴了@babel/traverse、eslint、prettier 三者的实现思路。与直接允许遍历中原地改 AST 的SimpleTransform不同,hermes-transform只在遍历结束后统一应用变更,changelog 0.10.0 明确指出这种"end-only"模式"much easier to reason about but limits what can be achieved"。

4.2 核心 API 演进

  • transform 主 API(0.10.0):新增parseprint两个导出。parse在调用hermes-parser之后额外执行注释挂接与 docblock 属性设置;print则通过 Prettier 由 AST 生成源码,并完成 docblock 重新挂回为普通注释等准备动作。
  • 控制遍历(0.10.0):stopTraversal中止整个遍历;skipTraversal跳过当前节点的子树但继续遍历;0.9.0 还提供modifyNodeInPlace直接修改节点(内部隐式 clone)。
  • 克隆语义(0.9.0):大部分 API 会自动对传入节点做浅克隆,使显式克隆基本不再必要;同时导出MaybeDetachedNode类型与asDetachedNode函数。
  • 注释工具(0.11.0):导出makeCommentOwnLine,让新增注释打印时独占一行;0.17.1 修复了可选链节点注释保留问题。
  • Program 级修改(0.23.0):context.modifyInPlace允许直接修改 Program 节点本身(此前依赖replaceNode,无法修改 Program)。
  • 节点构造器(0.10.0):提供t.Program({...})这样的节点生成器,可自底向上构造完整 AST。

docblock 的处理细节值得注意:0.10.0 起 docblock 不再挂接到第一个语句,而只通过 Program 节点的docblock属性访问,避免首语句被移动时注释被复制;0.23.1 修复了空body+ docblock 注释打印时报错的问题。

五、hermes-eslint:Flow 代码 lint 的推荐解析器

hermes-eslint是 ESLint 的自定义解析器,官方 README 称其为"the recommended parser for use for linting with Flow code",并给出两种配置方式(见 tools/hermes-parser/js/hermes-eslint/README.md):

  • Flat configeslint.config.js):将require('hermes-eslint')设为languageOptions.parser,解析选项通过languageOptions.parserOptions传入;
  • Legacy config.eslintrc):将"hermes-eslint"设为"parser"parserOptions直接写在配置对象中。

ParserOptions类型定义包含:

  • jsxPragma:JSX 元素创建(转译后)所用的标识符,须为根标识符而非成员表达式(用"React"而非"React.createElement"),显式设为null可启用新的全局 JSX transform,默认"React"
  • jsxFragmentName:JSX fragment 标识符,默认null(假定用jsxFactory的成员如React.Fragment);
  • sourceType'script' | 'module',默认"module"
  • fbt:忽略<fbt />JSX 元素对模块级React变量的引用计数(FBT 会转译为非 JSX,引用方式不同)。

changelog 中该包的重点集中在作用域分析的完善:0.18.0 将 JSX 闭合元素纳入作用域/绑定引用;0.19.1 支持DeclareNamespace节点的作用域分析;0.20.1 支持带类型参数的typeof节点;0.22.0 修复映射类型的作用域分析;0.9.0 处理 FBT 的fbs标签与函数类型this参数;0.17.1 确保AsExpression中的类型转换被视为已引用。作用域分析的正确性直接决定no-unused-vars等规则在 Flow 代码上的可信度。

六、flow-api-translator:Flow 到 TS 定义的双向翻译

flow-api-translator诞生于 0.10.0,其定位是"translating Flow code into either Flow definitions or TS definitions along with generating the non typed runtime code",目的是帮助 Flow 库作者同时支持 TS 与 Flow 代码库的使用。需注意:该包的后续开发已迁移至 facebook/flow 仓库(见 tools/hermes-parser/js/flow-api-translator/README.md)。

changelog 中该包的演进有几个清晰的脉络:

  • React 类型体系:从 0.11.0 开始逐步支持React.ElementConfigReact.KeyReact.RefReact.ComponentReact.ElementTypeReact.ChildrenArray,并改进React.ComponentTypeReact.AbstractComponent(0.21.1 支持三参数形式);0.25.0 支持React.RefSetter并移除错误的React.Ref翻译;0.28.0 翻译到ComponentRef替代废弃的ElementRef;0.27.0 改用React.JSX命名空间。
  • Flow 工具类型翻译:0.19.0 让$ReadOnlyMap/$ReadOnlySet与 Flow API 对齐为两个类型参数;0.15.0 移除已删除的$Shape$Partial;0.23.0 将StringPrefix<foo>译为foo${string}StringPrefix<foo, T>译为foo${T};0.28.0 支持$ArrayBufferView
  • 错误恢复策略(0.11.0):对不支持的 Flow 语法不再整体退出,而是将大多数错误以注释形式输出到生成的 TS 代码中并给出合适的类型回退。
  • 通用类型结构:0.16.0 支持条件类型、类型守卫、infer、映射对象类型;0.15.0 支持元组带标签与 spread 元素、ExportAllDeclaration;0.18.1 输出类型守卫代替%checks
  • 与 Prettier 的绑定:0.13.0 起切换为始终使用prettier-plugin-hermes-parser打印以支持最新 Flow 语法;0.30.0 修复 Prettier v3 支持;0.37.0 要求 Prettier v3 并输出TSImportType.source(为$Exports而生)。

七、prettier-plugin-hermes-parser:让打印追上解析

该插件的用途是让 Prettier 以 Hermes 解析器解析 Flow 代码并打印,从而支持 Prettier 官方插件尚未跟上的最新 Flow 语法。README 中的配置方式(见 tools/hermes-parser/js/prettier-plugin-hermes-parser/README.md):

// .prettierrc { "plugins": ["prettier-plugin-hermes-parser"], "overrides": [ { "files": ["*.js", "*.jsx", "*.flow"], "options": { "parser": "hermes" } } ] }

关键版本节点:

  • 0.12.0 创建:同时支持 Prettier v3 与 v2,但打印逻辑始终走最新的 Prettier v3,以完整支持 Hermes parser 的全部特性;
  • 0.12.1 性能优化:插件懒加载,未使用时零性能影响;从内置 Prettier v3 bundle 中剥离 Flow parser,缩短插件初始化时间;
  • 0.13.0 修复上游缺陷:修补 Prettier 打印hermes-transform产出的数组时无限递归的问题;
  • 0.31.0 移除 Prettier v2:与hermes-transform同步放弃 v2;
  • 0.37.0 新方向hermes-transform改为直接用 Prettier 内置的 Flow 与 TypeScript 插件打印,仅在需要时按需加载prettier-plugin-hermes-parser

八、babel-plugin-syntax-hermes-parser:接管 Babel 的解析阶段

该包创建于 0.13.0,将 Babel 的解析器从@babel/parser替换为hermes-parser,从而获得更快的解析速度与完整的 Flow 语法支持(C++ 编译为 WASM)。用法见 tools/hermes-parser/js/babel-plugin-syntax-hermes-parser/README.md:

npm install --save-dev babel-plugin-syntax-hermes-parser # 或 yarn add babel-plugin-syntax-hermes-parser --dev
// babel.config.json { "plugins": ["babel-plugin-syntax-hermes-parser"] }

需要向解析器传参时使用parserOpts

// babel.config.json { "plugins": ["babel-plugin-syntax-hermes-parser"], "parserOpts": { "allowReturnOutsideFunction": true } }

该插件值得注意的边界处理:0.18.1 起不对 TS 文件启用插件,0.25.1 新增parseLangTypes选项跳过非 Flow 文件,0.20.1 支持 Babel 8 beta。

九、贯穿版本的工程质量与破坏性变更

从 changelog 可总结出几条贯穿始终的工程主线:

  1. 破坏性重命名均为对齐生态attributesoptionstypeselementTypessuperTypeParameterssuperTypeArguments,以及falseTYpefalseType(0.11.0 修正 TS 节点拼写错误),都是为了与 ESTree/Flow parser 规范保持一致。
  2. babel 模式输出持续对齐:0.16.0 对 babel 支持基础设施做了重大重构,使 transform 更安全容易且输出更贴近@babel/parser;0.15.0 将MethodDefinition正确转为ClassPrivateMethod;0.13.0 剥离PropertyDefinition节点上 TS 专用的tsModifiers
  3. 依赖治理严苛:0.10.1 移除对hermes-eslint的未声明依赖以避免模块找不到错误;0.15.0 为hermes-transform增加prettier-plugin-hermes-parser的 peer dependency;0.11.1 修复依赖版本。
  4. 配置默认值的安全设计:0.33.2 将 Flow Enums transform 改为默认关闭,需显式传入transformOptions: {TransformEnumSyntax: {enable: true}};0.23.0 为hermes-parser新增reactRuntimeTarget配置(默认'18'),设为'19'时不再为函数组件添加forwardRef包装,因为 React 19 将 ref 视为普通 prop。

十、如何在当前仓库中深入验证

  • 解析选项:完整阅读 tools/hermes-parser/js/hermes-parser/README.md 中的参数表;
  • WASM 构建链路:查看 tools/hermes-parser/CMakeLists.txt、hermes-parser-wasm.cpp 与 HermesParserJSSerializer.cpp,了解 C++ 解析器如何序列化给 JS 消费;
  • 测试用例:tools/hermes-parser/js/tests/ 与各包内__tests__目录中的快照测试,是理解各类 Flow 语法在 AST 中具体形态的最佳入口;
  • 作用域分析实现:tools/hermes-parser/js/hermes-eslint/src/scope-manager/README.md 说明 ESLint 作用域分析的内部结构;
  • monorepo 构建与测试:tools/hermes-parser/js/package.json 中的build./scripts/build.sh)、lintflowtest脚本展示了整套工具的工程化流程。

结语

从 0.9.0 到 0.37.0,Hermes parser 的 JS 工具链完成了一次"解析能力追平语法、打印能力追平解析"的螺旋式演进:以 WASM 化的hermes-parser为核心,hermes-estree提供类型地基,hermes-eslintbabel-plugin-syntax-hermes-parser将解析能力注入主流工具链,hermes-transformprettier-plugin-hermes-parser支撑代码变换与格式化,flow-api-translator打通 Flow 与 TypeScript 之间的类型翻译。理解这七件套的分工与版本脉络,无论是排查解析问题、接入 ESLint/Babel/Prettier,还是实现自己的 AST 变换,都能做到有据可依。

  • 语言运行时
  • 编译器
  • 移动开发

【免费下载链接】hermes

A JavaScript engine optimized for running React Native.

项目地址:https://gitcode.com/gh_mirrors/hermes/hermes
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询