fix: parse with hermes-parser only when a file opts into Flow - #1452
Open
elirangoshen wants to merge 1 commit into
Open
fix: parse with hermes-parser only when a file opts into Flow#1452elirangoshen wants to merge 1 commit into
elirangoshen wants to merge 1 commit into
Conversation
babelLoader sent every non-TypeScript file through hermes-parser, unlike Metro, where the React Native preset's default parseLangTypes: 'flow' limits it to files carrying an @flow pragma. hermes-parser's Hermes-AST to Babel-AST conversion is quadratic in the number of sibling nodes, so one prebuilt minified dependency could add minutes to a build.
|
@elirangoshen is attempting to deploy a commit to the Callstack Team on Vercel. A member of the Team first needs to authorize it. |
🦋 Changeset detectedLatest commit: a434812 The changes in this PR will be included in the next version bump. This PR includes changesets to release 6 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
elirangoshen
marked this pull request as ready for review
September 4, 2026 09:06
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #1447
Summary
babelLoaderparsed every non-TypeScript file with hermes-parser. Metro does not do this:@react-native/babel-presetpassesparseLangTypes: 'flow'tobabel-plugin-syntax-hermes-parser, which skips hermes-parser for files without an@flowpragma and leaves them to@babel/parser.This change matches that behavior. Setting
hermesParserOverrides.flowto'all'opts every file back in.Why it matters
hermes-parser's Hermes-AST to Babel-AST conversion is quadratic in the number of sibling nodes, because each node replacement copies the whole sibling array. Prebuilt minified dependencies hit that path hard. In the Expensify app,
@lottiefiles/dotlottie-react/dist/browser/index.jstook 90.1s with hermes-parser and 0.1s with@babel/parser. The file is 502KB across 22 lines, has no@flowpragma, and contains oneArrayExpressionwith 128,834 elements. It runs as a single serial task, so it set a floor on the whole build no matter how many workers we gave it.Across that app's babel lane of 3,522 files, 2,779 carry no pragma. Those parse in 1.1s with
@babel/parseragainst 4.7s with hermes-parser, and hermes-parser fails on 2 of them.Swapping parsers wholesale does not work:
@babel/parsercannot read the Flow syntax in 241 react-native 0.86 files, which useascasts andcomponent(...)types. Gating on the pragma is what the preset already does.I reported the conversion cost upstream with a profile and a minimal repro in facebook/hermes#2158.
Change
shouldUseHermesParserlives inutils.tsand returnstruewhenflow === 'all'or the source matches/@flow/. hermes-parser now loads lazily, only when a file needs it, so builds that never touch a Flow file skip resolving it.Behavior change
Files containing Flow syntax without an
@flowpragma will now fail to parse, as they do under Metro. SettinghermesParserOverrides: { flow: 'all' }restores the old behavior. I marked the changeset as a patch, but tell me if you would rather it be minor given the shift in semantics.Tests
babelLoader.test.tsgets four cases for parser selection: no pragma skips hermes-parser, an@flowpragma uses it,flow: 'all'uses it regardless of pragma, and TypeScript sources skip it.I also fixed the existing
loadHermesParsermock, which threwConfiguration contains string/RegExp pattern, but no filename was passed to Babel. No test had exercised that path before, so the mock was never called.pnpm jestpasses 316 tests across 34 suites.pnpm --filter @callstack/repack typecheckandpnpm biome checkare clean.The perf repro is a large minified file, so it does not fit a unit test. facebook/hermes#2158 has a programmatic generator (build an
ArrayExpressionwith N elements, then convert) if you want it as a benchmark somewhere.