Skip to content

Commit 104590a

Browse files
authored
Inline destructured requires (#2087)
`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`
1 parent 47976bc commit 104590a

3 files changed

Lines changed: 431 additions & 3 deletions

File tree

‎packages/metro-transform-plugins/src/__tests__/__snapshots__/inline-requires-plugin-test.js.snap‎

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,16 @@ var foo = require(\\"foo\\");
77
↓ ↓ ↓ ↓ ↓ ↓
88
99
10+
"
11+
`;
12+
13+
exports[`memoizeCalls=false: inline-requires deletes unused destructured requires: deletes unused destructured requires 1`] = `
14+
"
15+
const {a} = require(\\"foo\\");
16+
17+
↓ ↓ ↓ ↓ ↓ ↓
18+
19+
1020
"
1121
`;
1222

@@ -91,6 +101,25 @@ function test() {
91101
"
92102
`;
93103

104+
exports[`memoizeCalls=false: inline-requires ignores destructured properties that are re-assigned: ignores destructured properties that are re-assigned 1`] = `
105+
"
106+
var X = require(\\"X\\");
107+
const {a} = require(\\"X\\");
108+
X.a = function() {
109+
a();
110+
};
111+
112+
↓ ↓ ↓ ↓ ↓ ↓
113+
114+
const {
115+
a
116+
} = require(\\"X\\");
117+
require(\\"X\\").a = function () {
118+
a();
119+
};
120+
"
121+
`;
122+
94123
exports[`memoizeCalls=false: inline-requires ignores require properties (as identifiers) that are re-assigned: ignores require properties (as identifiers) that are re-assigned 1`] = `
95124
"
96125
var X = require(\\"X\\");
@@ -137,6 +166,46 @@ require(\\"foo\\").method();
137166
"
138167
`;
139168

169+
exports[`memoizeCalls=false: inline-requires inlines destructured requires referenced across scopes: inlines destructured requires referenced across scopes 1`] = `
170+
"
171+
const {a, b} = require(\\"foo\\");
172+
function f() {
173+
return a() + b();
174+
}
175+
function g() {
176+
if (b()) {
177+
a();
178+
}
179+
}
180+
181+
↓ ↓ ↓ ↓ ↓ ↓
182+
183+
function f() {
184+
return require(\\"foo\\").a() + require(\\"foo\\").b();
185+
}
186+
function g() {
187+
if (require(\\"foo\\").b()) {
188+
require(\\"foo\\").a();
189+
}
190+
}
191+
"
192+
`;
193+
194+
exports[`memoizeCalls=false: inline-requires inlines destructured requires: inlines destructured requires 1`] = `
195+
"
196+
const {a, b: c, \\"d-e\\": de} = require(\\"foo\\");
197+
a();
198+
c.x();
199+
de();
200+
201+
↓ ↓ ↓ ↓ ↓ ↓
202+
203+
require(\\"foo\\").a();
204+
require(\\"foo\\").b.x();
205+
require(\\"foo\\")[\\"d-e\\"]();
206+
"
207+
`;
208+
140209
exports[`memoizeCalls=false: inline-requires inlines functions provided via \`inlineableCalls\`: inlines functions provided via \`inlineableCalls\` 1`] = `
141210
"
142211
const inlinedCustom = customStuff(\\"foo\\");
@@ -244,6 +313,16 @@ var foo = require(\\"foo\\");
244313
↓ ↓ ↓ ↓ ↓ ↓
245314
246315
316+
"
317+
`;
318+
319+
exports[`memoizeCalls=true: inline-requires deletes unused destructured requires: deletes unused destructured requires 1`] = `
320+
"
321+
const {a} = require(\\"foo\\");
322+
323+
↓ ↓ ↓ ↓ ↓ ↓
324+
325+
247326
"
248327
`;
249328

@@ -331,6 +410,26 @@ function test() {
331410
"
332411
`;
333412

413+
exports[`memoizeCalls=true: inline-requires ignores destructured properties that are re-assigned: ignores destructured properties that are re-assigned 1`] = `
414+
"
415+
var X = require(\\"X\\");
416+
const {a} = require(\\"X\\");
417+
X.a = function() {
418+
a();
419+
};
420+
421+
↓ ↓ ↓ ↓ ↓ ↓
422+
423+
var X;
424+
const {
425+
a
426+
} = require(\\"X\\");
427+
(X || (X = require(\\"X\\"))).a = function () {
428+
a();
429+
};
430+
"
431+
`;
432+
334433
exports[`memoizeCalls=true: inline-requires ignores require properties (as identifiers) that are re-assigned: ignores require properties (as identifiers) that are re-assigned 1`] = `
335434
"
336435
var X = require(\\"X\\");
@@ -380,6 +479,48 @@ var baz = 4;
380479
"
381480
`;
382481

482+
exports[`memoizeCalls=true: inline-requires inlines destructured requires referenced across scopes: inlines destructured requires referenced across scopes 1`] = `
483+
"
484+
const {a, b} = require(\\"foo\\");
485+
function f() {
486+
return a() + b();
487+
}
488+
function g() {
489+
if (b()) {
490+
a();
491+
}
492+
}
493+
494+
↓ ↓ ↓ ↓ ↓ ↓
495+
496+
var _foo;
497+
function f() {
498+
return (_foo || (_foo = require(\\"foo\\"))).a() + _foo.b();
499+
}
500+
function g() {
501+
if ((_foo || (_foo = require(\\"foo\\"))).b()) {
502+
(_foo || (_foo = require(\\"foo\\"))).a();
503+
}
504+
}
505+
"
506+
`;
507+
508+
exports[`memoizeCalls=true: inline-requires inlines destructured requires: inlines destructured requires 1`] = `
509+
"
510+
const {a, b: c, \\"d-e\\": de} = require(\\"foo\\");
511+
a();
512+
c.x();
513+
de();
514+
515+
↓ ↓ ↓ ↓ ↓ ↓
516+
517+
var _foo;
518+
(_foo || (_foo = require(\\"foo\\"))).a();
519+
_foo.b.x();
520+
_foo[\\"d-e\\"]();
521+
"
522+
`;
523+
383524
exports[`memoizeCalls=true: inline-requires inlines functions provided via \`inlineableCalls\`: inlines functions provided via \`inlineableCalls\` 1`] = `
384525
"
385526
const inlinedCustom = customStuff(\\"foo\\");

‎packages/metro-transform-plugins/src/__tests__/inline-requires-plugin-test.js‎

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,97 @@ const TEST_CASES: TestCases = {
238238
code: ['const a = require("Foo", "Bar", 47);', '', 'a();'].join('\n'),
239239
snapshot: true,
240240
},
241+
242+
'inlines destructured requires': {
243+
code: [
244+
'const {a, b: c, "d-e": de} = require("foo");',
245+
'a();',
246+
'c.x();',
247+
'de();',
248+
].join('\n'),
249+
snapshot: true,
250+
},
251+
252+
'inlines destructured requires referenced across scopes': {
253+
code: [
254+
'const {a, b} = require("foo");',
255+
'function f() {',
256+
' return a() + b();',
257+
'}',
258+
'function g() {',
259+
' if (b()) {',
260+
' a();',
261+
' }',
262+
'}',
263+
].join('\n'),
264+
snapshot: true,
265+
},
266+
267+
'deletes unused destructured requires': {
268+
code: ['const {a} = require("foo");'].join('\n'),
269+
snapshot: true,
270+
},
271+
272+
'ignores destructured requires with defaults': {
273+
code: ['const {', ' a = 1', '} = require("foo");', 'a();'].join('\n'),
274+
snapshot: false,
275+
},
276+
277+
'ignores destructured requires with rest elements': {
278+
code: [
279+
'const {',
280+
' a,',
281+
' ...rest',
282+
'} = require("foo");',
283+
'a(rest);',
284+
].join('\n'),
285+
snapshot: false,
286+
},
287+
288+
'ignores nested destructured requires': {
289+
code: [
290+
'const {',
291+
' a: {',
292+
' b',
293+
' }',
294+
'} = require("foo");',
295+
'b();',
296+
].join('\n'),
297+
snapshot: false,
298+
},
299+
300+
'ignores destructured requires with computed keys': {
301+
code: ['const {', ' [key]: a', '} = require("foo");', 'a();'].join('\n'),
302+
snapshot: false,
303+
},
304+
305+
'ignores destructured requires that are re-assigned': {
306+
code: [
307+
'let {',
308+
' a,',
309+
' b',
310+
'} = require("foo");',
311+
'b = 1;',
312+
'a(b);',
313+
].join('\n'),
314+
snapshot: false,
315+
},
316+
317+
'ignores destructured properties that are re-assigned': {
318+
code: [
319+
'var X = require("X");',
320+
'const {a} = require("X");',
321+
'X.a = function() {',
322+
' a();',
323+
'};',
324+
].join('\n'),
325+
snapshot: true,
326+
},
327+
328+
'ignores destructured requires in `ignoredRequires`': {
329+
code: ['const {', ' a', '} = require("CommonFoo");', 'a();'].join('\n'),
330+
snapshot: false,
331+
},
241332
};
242333

243334
describe.each([true, false])('memoizeCalls=%s:', memoizeCalls => {

0 commit comments

Comments
 (0)