Repository navigation
Inline destructured requires - #2087
Merged
Merged
Conversation
`inlineRequires` only inlined requires assigned to an identifier, so `const {foo} = require('foo')` stayed eager at module scope unless a Babel preset had lowered the destructuring first. `@react-native/babel-preset` stopped lowering destructuring for Hermes profiles in react/react-native#58965.
This inlines top-level object patterns with plain, renamed or string keys directly: each reference becomes `require('foo').foo`, matching the lowered form. With `memoizeCalls`, a module's properties share one memoized module. Defaults, rest elements, nesting and computed keys are left alone, as are reassigned bindings and properties assigned on the module.
Changelog: [Performance] Inline destructured CommonJS requires (`const {foo} = require('foo')`) under `inlineRequires`
vzaidman
approved these changes
Oct 23, 2026
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.
Summary
Inline requires only inlines requires assigned to an identifier, ie
const foo = require('foo')orconst foo = require('foo').foo. Despite what the plugin's doc comment says,const {foo, bar} = require('foo')has never been inlined - it only appeared to work because Babel presets used to lower destructuring into the identifier form first.react/react-native#58965 stopped
@react-native/babel-presetlowering destructuring for Hermes profiles, so since then destructured CommonJS requires are evaluated eagerly at module init. ESM imports aren't affected.This adds direct support for top-level object patterns with plain, renamed or string keys. Each reference becomes
require('foo').bar, exactly what the lowered form produced. WithmemoizeCalls, a module's properties share one memoised module, so each scope requires it at most once:Defaults, rest elements, nested patterns and computed keys are left alone, as are reassigned bindings and properties assigned on the module elsewhere - the same constraints as the existing identifier forms.
Changelog: [Performance] Inline destructured CommonJS requires (
const {foo} = require('foo')) underinlineRequiresTest plan
New cases cover renamed and string keys, references across scopes and branches, unused requires and each unsupported pattern, with and without
memoizeCalls.End to end, I swapped this build into React Native's own Jest transform, which runs inline requires, on react/react-native#59303 (which preserves destructuring in that config). The 17 suites that relied on inline requires to load modules after their
jest.mockcalls pass in their original form, before react/react-native#59307 and react/react-native#59352 fixed them: 292 tests and 70 snapshots, against 110 failures without this change. RN's full suite passes too (6,289 tests).