- 语言运行时
- 编译器
- 移动开发
【免费下载链接】hermes
A JavaScript engine optimized for running React Native.
导读
本文以 Hermes 仓库内 tools/hermes-parser/js/prettier-plugin-hermes-parser/CHANGELOG.md 为主线,系统讲解prettier-plugin-hermes-parser(当前仓库版本 0.37.0)的设计定位、安装配置、底层打印原理,以及它随版本迭代逐步支持 React 组件/ Hook 声明、Flow 新型 variance、keyof、match 模式、Records、opaque type 上下界等前沿语法的完整过程。读完本文,你将掌握该插件的接入方式、版本选择依据,并能从源码与测试层面理解它如何让 Prettier 持续兼容 Hermes 解析器产出的最新 ESTree 结构。
一、插件定位:让 Prettier 认识 Hermes 的 AST
prettier-plugin-hermes-parser是 Hermes 生态中连接「解析」与「格式化」的桥梁。Hermes 的 JavaScript 解析器由 C++ 实现并编译为 WASM,能完整解析 Flow、JSX 以及大量尚未进入 Prettier 官方插件的实验性语法。Prettier 官方自带 Babel 等解析器插件,但无法第一时间覆盖 Hermes 解析器支持的这些「超集」语法节点;该插件的职责就是把 Hermes 解析器产出的 AST(以estree-hermes格式标识)接入 Prettier 的打印管线,从而让这些新语法也能获得一致的格式化输出。
需要特别说明定位:仓库 README.md 明确写道——「Unless you want to be on the bleeding edge, you should use the official@prettier/plugin-hermesinstead」。也就是说,追求稳定环境的普通用户应使用官方发布的@prettier/plugin-hermes,而本插件是 Hermes 仓库内维护的「前沿(bleeding edge)」版本,用于更快跟进 Hermes 解析器新增的语法;在 0.31.1 版本中,插件正是在@prettier/plugin-hermes基础上重建("Rebuild based on@prettier/plugin-hermes. There should be no formatting differences, but it will be less buggy"),由此继承了其打印逻辑,同时以独立版本线继续演进。
从 package.json 的元数据(package.json)可以看到:
- 包名
prettier-plugin-hermes-parser,版本 0.37.0,MIT 许可; - 入口通过
exports字段暴露./index.mjs(ESM 模块); peerDependencies声明prettier: ^3.0.0——插件仅支持 Prettier v3,这与 0.31.0 版本移除 Prettier v2 支持的决策一致(见 tools/hermes-parser/js/CHANGELOG.md 0.31.0 条目)。
二、安装与配置:将 hermes 设为解析器
2.1 基础配置
插件的使用方式非常直接:安装插件后,在 Prettier 配置中把它加入plugins列表,并对需要走 Hermes 解析器的文件通过overrides指定parser: "hermes"。仓库 README 给出了完整的 .prettierrc 示例:
{ "plugins": ["prettier-plugin-hermes-parser"], "overrides": [ { "files": ["*.js", "*.jsx", "*.flow"], "options": { "parser": "hermes" } } ] }其中overrides的files可扩展至你项目中所有使用 Flow/JSX 的文件类型;parser: "hermes"是插件向 Prettier 注册的解析器名。之所以用overrides而非全局parser,是为了让.js/.jsx/.flow之外的文件继续走 Prettier 默认解析器。
2.2 在测试中的实际调用方式
仓库的单元测试展示了编程式调用方式,可视为配置的「代码形态」。以 prettier-plugin-hermes-parser-test.js 为例:
function getOptions() { return { ...prettierConfig, parser: 'hermes', requirePragma: false, plugins: [require.resolve('../index.mjs')], }; } const output = await prettier.format(code, getOptions());要点包括:parser: 'hermes'与 CLI/配置文件中的写法完全一致;plugins直接引用本地index.mjs的解析路径;requirePragma: false表示不需要@prettier类 pragma 注释也会格式化。测试还额外验证了格式化的稳定性(idempotency)——对输出结果二次格式化必须与首次结果逐字节一致,这是 Prettier 插件质量的关键指标。
三、入口实现:index.mjs 与 avoidAstMutation
理解插件能力边界,最好的切入点是它的入口文件 index.mjs。整个文件非常精简:
import hermesPlugin from './index.generated.mjs'; const HERMES_AST_FORMAT = 'estree-hermes'; const hermesPrinter = hermesPlugin.printers[HERMES_AST_FORMAT]; const printers = { ...hermesPlugin.printers, [HERMES_AST_FORMAT]: { ...hermesPrinter, experimentalFeatures: { ...hermesPrinter.experimentalFeatures, avoidAstMutation: true, }, features: { ...hermesPrinter.features, experimental_avoidAstMutation: true, }, }, }; export const languages = hermesPlugin.languages; export const options = hermesPlugin.options; export const parsers = hermesPlugin.parsers; export {printers};从源码结构可以提炼出三点实现事实:
- 核心实现来自生成文件:真正的解析器与打印器逻辑位于
index.generated.mjs(由scripts/build-prettier.sh从 Prettier fork 构建产出,见下文「贡献与构建」一节),入口文件只是在其上做轻量包装。 estree-hermes打印格式:插件注册的 AST 格式标识为estree-hermes,Prettier 根据该标识找到对应的 printer 来序列化 Hermes 解析器输出的节点。avoidAstMutation(避免 AST 变异):这是本插件相对 Prettier 默认行为的重要差异——它显式开启了实验性特性experimental_avoidAstMutation,即打印过程中不修改传入的 AST。这对hermes-transform、flow-api-translator等依赖 AST 多次复用的工具链尤为关键:保证打印不会破坏原始节点结构(相关背景见 tools/hermes-parser/js/CHANGELOG.md 0.15.0 中print缓存键唯一性的修复,以及 0.13.0 中「Printer 始终使用本插件以支持最新 Flow 语法」的决策)。
四、版本演进全景:0.31.1 → 0.37.0 的功能时间线
CHANGELOG 将 0.31.1 之前的历史指向 tools/hermes-parser/js/CHANGELOG.md(hermes-parser 系列的主 changelog),因此本文聚焦 0.31.1 之后独立维护的条目。以下按功能类别梳理:
4.1 对 Prettier 版本的兼容与同步(选型必读)
- 0.37.0:修复与 Prettier 3.7+ 的兼容性问题(Fix compatibility with Prettier 3.7+)。这是当前最新版本,如果你的工程升级到了 Prettier 3.7 及以上,应使用该版本。
- 0.33.2:将内置基础 Prettier 版本回退到 3.6.2,但保留其他变更(Reverts base Prettier version back to 3.6.2, but keeps other changes)。这提醒我们:插件内部「基于某个 Prettier 版本 fork」与「对宿主 Prettier 版本的兼容」是两条独立的维度,基础版本的升降不影响插件在宿主环境中的工作。
- 0.33.1:包含直至 Prettier 3.7.4 的变更(Includes changes up to Prettier 3.7.4)。
- 0.31.1:基于
@prettier/plugin-hermes重建,格式输出不变但更少 bug。
这些条目的实践含义是:插件版本与宿主 Prettier 版本需要匹配。若宿主 Prettier 较新(≥3.7),应优先使用 0.37.0;若被 0.37.0 的兼容修复影响,可结合 0.33.x 的兼容策略评估回退路径。
4.2 新语法格式化支持(核心能力)
这是插件的核心竞争力——让 Prettier 能够打印 Hermes 解析器支持的各类 Flow 实验语法:
- React 组件与 Hook 声明(0.36.1):支持
async component和async hook声明的格式化。对应解析器侧在 hermes-parser 0.34.0 就加入了async hook/async component语法支持,0.36.1 修复了async component函数体内await不被识别的问题,随后插件跟进打印支持。 - Flow variance 新语法(0.36.0、0.35.0):支持新的 Flow variance 语法;并将
readonly作为等价于+(协变/只读)的 variance 注解加以支持,可作用于对象类型属性、索引器、类属性乃至元组标记元素。hermes-estree 侧在 0.36.0 为 variance 类型新增了writeonly、in、out,0.35.0 新增readonly,插件随之同步。 keyof运算符(0.34.0):支持 Flow 新的keyof运算符(用于替代$Keys)。- match 实例模式与 Flow Records(0.33.1):支持 Flow match 实例模式(
match语句/表达式)与 Records(记录字面量{}语法)。 - opaque type 上下界(0.32.0):支持同时带下界与上界的 opaque type,即
super与extends语法(对应解析器 0.30.0 的解析能力)。
上述每一项都有对应的专项测试文件佐证,例如 component-declaration-test.js(组件声明)、readonly-variance-test.js(readonly variance)、keyof-test.js(keyof)、match-test.js、record-test.js、opaque-type-test.js,以及 const 类型参数(const-type-param-test.js)与declare component/declare hook(declare-component-test.js、declare-hook-test.js)等。
4.3 Bug 修复(稳定性保障)
- 0.34.1:修复自动格式化器意外删除空格、导致 Prettier 补出多余空行的问题("a white space was accidentally removed by autoformatter causing prettier to add unnecessary new lines")。这一条说明插件同时维护自己的生成代码风格,生成过程中的空白处理也是质量保障的一部分。
4.4 其他语法细节
- 0.36.0:支持
DeclareVariable声明的数组形式("SupportDeclareVariabledeclarations array"),对应 Flow 中declare var声明数组的打印。
五、格式化效果示例:从测试快照看插件行为
专项测试中的 inline snapshot 直接展示了插件的真实输出,是理解其格式化行为的最佳素材。以下从 component-declaration-test.js 选取典型场景:
组件声明(含导出、泛型约束、可选参数、默认值):
component MyComponent() {} component MyComponent() renders SomeComponent {} export component MyComponent() {} component MyComponent<T>() {} component MyComponent(bar: string) {} component MyComponent(bar?: string) {} component MyComponent(bar: string = '') {}超长泛型约束与长参数列表自动换行(体现 Prettier 折行策略与 Flow 尾逗号约定):
component MyComponent< T: Fooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo, >() {} component MyComponent( bar: string, baz: $ReadOnly<{k: string}>, realllllllllllllllllllyLong: string, ) {}rest 参数、注释保留(块注释、行尾注释、前置注释均被稳定保留并正确对齐):
component MyComponent(...restProps: $ReadOnly<{k: string}>) {} component MyComponent( /** * Commet block */ bar: string, // Trailing comment // preceding comment 'data-baz' as baz: $ReadOnly<{k: string}>, ) {}JSX 稳定性(prettier-plugin-hermes-parser-test.js):测试验证了 JSX 变量声明「一次格式化后再次格式化结果完全一致」,并确保嵌套 JSX 中不会在开标签后/闭标签前出现多余空行:
function Foo() { return ( <View style={styles.root}> <View style={styles.content}> <Text>Hello</Text> <Button onClick={handleClick} /> </View> <Separator /> </View> ); }内嵌标签模板(graphql / css)与 prettier-ignore 注释也在同一测试中验证可正常工作,说明插件保留了 Prettier 的完整嵌入式格式化能力:
const styles = { content: css` column-gap: 8px; display: grid; grid-template-columns: 1fr 3fr; `, };六、在 Hermes 工具链中的位置:为 transform 与 translator 提供打印能力
本插件并不仅服务于命令行格式化,它还是 Hermes 代码变换工具链的「打印后端」。从 tools/hermes-parser/js/CHANGELOG.md 可以还原这条依赖链:
- 0.13.0:
hermes-transform与flow-api-translator的 Printer「始终使用prettier-plugin-hermes-parser以确保支持最新 Flow 语法」——即 AST 变换/翻译后的代码统一交给本插件序列化; - 0.15.0:
hermes-transform增加对本插件的peerDependency,并保证print缓存键在存在多实例时唯一; - 0.32.0:
hermes-transform在安装了本插件时,使用它来打印变换后的代码; - 0.37.0(最新):
hermes-transform改为使用 Prettier 内置的 Flow 与 TypeScript 插件打印,不再条件加载本插件——这是对当前主 changelog 中该工具链策略的一次重要调整,说明本插件的职责正逐步回归「面向使用者的独立格式化插件」角色。
因此,如果你在研究hermes-transform(AST 变换后重写源码)或flow-api-translator(Flow 转 TypeScript 定义),本插件的历史版本行为与之深度耦合,理解这份 CHANGELOG 有助于判断打印行为差异的来源。
七、贡献与构建:基于 Prettier fork 的二次开发
仓库内 CONTRIBUTION.md 描述了插件(本质上是一份「修改版 Prettier v3」)的构建流程,对想深入贡献的开发者很有价值:
- 在
hermes-parser/js下运行./scripts/build-prettier.sh执行 yarn 构建脚本; - 对位于
hermes-parser/js/prettier-hermes-flow-fork的 Prettier fork 仓库做修改; - 修改完成后运行
yarn build-prettier重新构建; - 完成后在 fork 仓库内提交,并可将相关改动向上游提交 PR。
手动流程则是:检出 Prettier 的 flow fork,执行yarn build --package=@prettier/plugin-hermes,将构建产物dist/plugin-hermes及全部 JS 文件拷贝到本目录。这也解释了入口文件为何是index.mjs引用index.generated.mjs——后者即构建生成的、体积较大的完整插件实现。
八、总结与版本选择建议
prettier-plugin-hermes-parser的演进史是 Hermes 解析器语法扩展的缩影:每当 hermes-parser 新增语法解析能力,插件在下一版本即跟进打印支持,同时持续同步 Prettier 上游并修复空白、换行等细节问题。选择建议如下:
- 稳定场景:优先使用官方
@prettier/plugin-hermes(见 README.md); - 前沿场景:需要格式化
component/hook声明、Flow 新 variance、keyof、match 模式、Records、opaque type 上下界等实验语法时,使用本插件; - 版本匹配:宿主 Prettier ≥ 3.7 时使用 0.37.0;更早版本可参考 0.33.x 的兼容与回退策略;peerDependency 约束为 Prettier ^3.0.0,不支持 v2;
- 验证手段:所有格式化行为均可通过仓库内tests目录下的专项测试(含稳定性与快照断言)复核,便于在接入前评估对自身代码库的影响。
- 语言运行时
- 编译器
- 移动开发
【免费下载链接】hermes
A JavaScript engine optimized for running React Native.
相关推荐
Vector NATS Sink 详解:配置、认证策略与 JetStream 发布实战
Vector NATS Sink 详解:配置、认证策略与 JetStream 发布实战 Vector 的 nats sink 用于将观测数据(日志事件)发布到
语言运行时编译器移动开发使用 @prettier/plugin-hermes 为 Prettier 接入 Hermes 解析器
使用 @prettier/plugin hermes 为 Prettier 接入 Hermes 解析器 本篇技术指南围绕 Prettier 官方仓库中的 @pr
开发工具格式化CLITypeSpec Prettier 插件:`@typespec/prettier-plugin-typespec` 的架构、使用与版本演进全解析
TypeSpec Prettier 插件: @typespec/prettier plugin typespec 的架构、使用与版本演进全解析 导读 @type
编程语言编译器后端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考