Babel与esbuild如何共存:react-native-esbuild的babelPlugin搞定reanimated worklet语法
【免费下载链接】react-native-esbuildFast bundler and dev server for react-native using esbuild项目地址: https://gitcode.com/gh_mirrors/re/react-native-esbuild
react-native-esbuild 是基于 esbuild 的极速 React Native 打包器与开发服务器,打包速度比 Metro 快 10~50 倍。但 esbuild 再快,也认不出 reanimated 的 worklet 语法。本文带你搞懂项目里的 babelPlugin 与「语法感知加载器」如何让 Babel 和 esbuild 各干各的活,让 reanimated 动画在极速打包下正常运行。🚀
先搞清楚:为什么 esbuild 搞不定 worklet 语法
esbuild 用 Go 编写,快到飞起,但它的语法支持是"写死"的:只会处理 JS / TS / JSX。而 React Native 生态里有两类它处理不了的语法:
| 语法类型 | 谁来处理 | 不处理的后果 |
|---|---|---|
reanimated worklet(useAnimatedStyle、withSpring等) | Babel 插件react-native-reanimated/plugin | 动画不生效,甚至直接报错 |
Flow 类型标注(@flow) | Babel 的 strip-types 插件 | 构建时语法错误 |
reanimated v2 的 worklet 必须经过 Babel 重写后才能被搬运到 UI 线程执行。esbuild 没有等价能力,所以这类文件必须"绕道"Babel。react-native-esbuild 的解法很聪明:默认全交给 esbuild,只把真正需要的文件挑出来交给 Babel。
自动识别 worklet 文件:syntaxAwareLoaderPlugin 是怎么做的
核心逻辑在 syntax-aware-loader.js。它作为默认插件注册在 esbuild-config.js 中,匹配所有 JS/TS 文件,然后在加载每个文件时做两件事:
- 检测 reanimated 语法:
defaultHasReanimatedSyntax会在文件内容里查找一组特征关键字,例如useAnimatedStyle、useAnimatedProps、useDerivedValue、withSpring、withTiming、withRepeat,以及字面量"worklet"。命中任意一个,就判定该文件包含 worklet。 - 按需转换:
- 命中 worklet → 执行完整的 Babel 转换(加载你项目里的
babel.config.js,其中应包含react-native-reanimated/plugin),转换后以普通 JS 交给 esbuild; - 只含 Flow 语法 → 仅剥离类型,开销更小;
- 都没命中 → 原样返回,完全走 esbuild 原生速度。
- 命中 worklet → 执行完整的 Babel 转换(加载你项目里的
示例工程的 Babel 配置就是这样配合的(Example/babel.config.js):
module.exports = { presets: ['module:metro-react-native-babel-preset'], plugins: ['react-native-reanimated/plugin'], };也就是说:99% 的文件享受 esbuild 的极速,只有写动画的那几个文件多花一点 Babel 的时间。⚡
手动加料:用 babelPlugin 精准处理指定目录
如果你不只是 reanimated,还有自己依赖 Babel 插件的私有组件库,可以用项目导出的 babelPlugin。在react-native.config.js中通过createEsbuildCommands注入:
// react-native.config.js const { createEsbuildCommands, babelPlugin } = require('react-native-esbuild'); const commands = createEsbuildCommands((config) => ({ ...config, plugins: config.plugins.concat( babelPlugin({ filter: /src\/my-babel-components\/.+\.[tj]sx?$/ }) ), })); module.exports = { commands };几个常用参数,上手基本够用:
filter:正则过滤器,只有匹配的文件才走 Babel;config:自定义 Babel 选项,透传给@babel/core;cache:是否启用磁盘缓存,默认开启;loader:转换结果的 esbuild loader,默认'js'。
双重缓存:Babel 慢?缓存让它"只跑一次"
Babel 是出了名的慢,react-native-esbuild 给 Babel 转换加了双层缓存,让"慢"几乎不可感知:
- 内存缓存:以文件修改时间(mtime)为键存进 Map,开发过程中没改动的文件直接复用,源码见 babel.js 中的
transformCache; - 磁盘缓存:用
md5(Babel选项 + 文件内容)生成缓存键,结果写入系统临时目录下的react-native-esbuild文件夹(目录逻辑在 cache.js)。下次构建即使冷启动,也无需重新转换; - 开发模式下(
dev: true)自动开启缓存,--reset-cache参数可随时清空缓存目录。
三步上手:让 reanimated 跑在 esbuild 上
- 安装依赖:
yarn add react-native-esbuild esbuild - 注册命令:在项目根目录
react-native.config.js中导入commands并导出(没有该文件就新建); - 检查 Babel 配置:确认
babel.config.js的 plugins 里包含react-native-reanimated/plugin。
完成后,用react-native esbuild-start启动开发服务器、esbuild-bundle出生产包即可。若只想让部分文件走 Babel,再按上文用babelPlugin追加一个过滤规则就够了。
小结
react-native-esbuild 的巧妙之处在于"各取所长":esbuild 负责 90%+ 文件的极速打包,Babel 只被精准地派去处理 reanimated worklet 与 Flow 这类特殊语法,再用内存 + 磁盘双重缓存把 Babel 的开销压到最低。理解这套 babelPlugin 与语法感知加载器的协作方式,你也能给自己的项目定制同样的"快而不乱"的构建管线。✅
【免费下载链接】react-native-esbuildFast bundler and dev server for react-native using esbuild项目地址: https://gitcode.com/gh_mirrors/re/react-native-esbuild
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考