From 12840fdc718c1df86f5afbf2cfd5891b342abe49 Mon Sep 17 00:00:00 2001 From: Rob Hogan Date: Thu, 23 Jul 2026 05:40:17 -0700 Subject: [PATCH 1/2] Upstream `inlineModuleIdReferences`: serialise-time module-id inlining helper Summary: Upstream `inlineModuleIdReferences`, a pure string helper, from Metro-Buck to the OSS serialiser. This utility replaces `dependencyMapReservedName[i]` references in a module body with the resolved numeric module ID of dependency `i`, without any reparse or AST manipulation, with padding to preserve source map correctness. The safety of pure string replacement is guaranteed by `unstable_dependencyMapReservedName` (optional, enforces that that string cannot appear in user code) - this utility will throw if that's not set. In Metro-Buck, this powers an a runtime optimisation that replaces an array access with the literal. Immediately, this saves a bunch of array accesses during startup (especially if `inlineRequires` is disabled), and provides a modest bundle size reduction. On top of that, it unlocks `$SHBuiltin`-based optimisations (`unstable_enableStaticHermesOptimizedRequire`), which currently rely on matching a `require()`. The OSS serialiser itself is not yet wired to use the helper; that opt-in wiring lands in the next diff. Changelog: [Internal] Reviewed By: huntie Differential Revision: D112353888 --- .../Serializers/helpers/__tests__/js-test.js | 64 +++++++++++++++- .../DeltaBundler/Serializers/helpers/js.js | 76 +++++++++++++++++++ .../DeltaBundler/Serializers/helpers/js.d.ts | 33 +++++++- 3 files changed, 171 insertions(+), 2 deletions(-) diff --git a/packages/metro/src/DeltaBundler/Serializers/helpers/__tests__/js-test.js b/packages/metro/src/DeltaBundler/Serializers/helpers/__tests__/js-test.js index a010a9b53c..f770dd3097 100644 --- a/packages/metro/src/DeltaBundler/Serializers/helpers/__tests__/js-test.js +++ b/packages/metro/src/DeltaBundler/Serializers/helpers/__tests__/js-test.js @@ -12,7 +12,7 @@ import type {Dependency} from '../../../types'; import CountingSet from '../../../../lib/CountingSet'; -import {wrapModule} from '../js'; +import {inlineModuleIdReferences, wrapModule} from '../js'; import {wrap as raw} from 'jest-snapshot-serializer-raw'; import createModuleIdFactory from 'metro-config/private/defaults/createModuleIdFactory'; import nullthrows from 'nullthrows'; @@ -199,3 +199,65 @@ describe('wrapModule()', () => { ); }); }); + +describe('inlineModuleIdReferences()', () => { + const NAME = 'DEP_MAP_RESERVED_NAME'; + const ref = (i: number) => `${NAME}[${i}]`; + + test('returns code unchanged when there are no dependencies', () => { + const code = ref(0); + expect(inlineModuleIdReferences(code, NAME, [])).toBe(code); + }); + + test('replaces dependency-map references with resolved ids', () => { + const code = `require(${ref(0)}); require(${ref(1)});`; + const inlined = inlineModuleIdReferences(code, NAME, [7, 42]); + expect(inlined).toBe( + `require(${'7'.padEnd(ref(0).length)}); ` + + `require(${'42'.padEnd(ref(1).length)});`, + ); + expect(inlined.length).toBe(code.length); + }); + + test('right-pads ids to preserve byte offsets / source-map columns', () => { + const code = `x=${ref(0)};y=1;`; + const inlined = inlineModuleIdReferences(code, NAME, [3]); + expect(inlined.length).toBe(code.length); + expect(inlined).toBe(`x=${'3'.padEnd(ref(0).length)};y=1;`); + // Everything after the reference keeps its original column. + expect(inlined.indexOf('y=1;')).toBe(code.indexOf('y=1;')); + }); + + test('tolerates embedded tabs and spaces inside the reference', () => { + const code = `${NAME}\t[ 1 ]`; + const inlined = inlineModuleIdReferences(code, NAME, [0, 5]); + expect(inlined).toBe('5'.padEnd(code.length)); + expect(inlined.length).toBe(code.length); + }); + + test('throws when a resolved id is wider than the available space', () => { + // Short reserved name so the resolved id cannot fit in the reference width. + expect(() => inlineModuleIdReferences('D[0]', 'D', [12345])).toThrow( + "Module ID doesn't fit in available space; add 1 more characters to " + + "'dependencyMapReservedName'.", + ); + }); + + test('throws when the reserved name is absent but deps exist', () => { + expect(() => + inlineModuleIdReferences('require(someOtherName[0]);', NAME, [1]), + ).toThrow( + 'Module has dependencies but does not use the preconfigured dependency ' + + "map name 'DEP_MAP_RESERVED_NAME'", + ); + }); + + test('ignores a missing reserved name when told to', () => { + const code = 'require(someOtherName[0]);'; + expect( + inlineModuleIdReferences(code, NAME, [1], { + ignoreMissingDependencyMapReference: true, + }), + ).toBe(code); + }); +}); diff --git a/packages/metro/src/DeltaBundler/Serializers/helpers/js.js b/packages/metro/src/DeltaBundler/Serializers/helpers/js.js index 0853f49ac7..4b6b4e732e 100644 --- a/packages/metro/src/DeltaBundler/Serializers/helpers/js.js +++ b/packages/metro/src/DeltaBundler/Serializers/helpers/js.js @@ -117,6 +117,82 @@ export function getModuleParams( return params; } +/** + * Fast path for inlining module IDs as a cheap string operation, requiring + * neither parsing nor any adjustment to the source map. + * + * Assumptions: + * 1. `dependencyMapReservedName` is a globally reserved string; there are + * no false positives. + * 2. The longest module ID in the bundle does not exceed a length of + * `dependencyMapReservedName.length + 3`. (We assert this below.) + * 3. False negatives (failing to inline occasionally if an assumption + * isn't met) are rare to nonexistent, but safe if they do occur. + * + * Syntax definitions: + * 1. A dependency map reference is a member expression which, if parsed, + * would have the form: + * MemberExpression + * ├──object: Identifier (name = dependencyMapReservedName) + * ├──property: NumericLiteral (value = some integer) + * └──computed: true + * 2. The concrete form of a dependency map reference may contain embedded + * tabs or spaces, but no newlines (which would complicate source maps), + * parens (which would complicate detection) or comments (likewise). + * 3. The numeric literal in a dependency map reference is a base-10 + * integer printed as a simple sequence of digits. + */ +export function inlineModuleIdReferences( + code: string, + dependencyMapReservedName: string, + dependencyIds: ReadonlyArray, + { + ignoreMissingDependencyMapReference = false, + }: Readonly<{ignoreMissingDependencyMapReference?: boolean}> = {}, +): string { + if (!dependencyIds.length) { + // Nothing to inline in this module. + return code; + } + + if (!code.includes(dependencyMapReservedName)) { + if (ignoreMissingDependencyMapReference) { + return code; + } + + // If we're here, the module was probably generated by some code that + // doesn't make the dependency map name externally configurable, or a + // mock that needs to be updated. + throw new Error( + `Module has dependencies but does not use the preconfigured dependency map name '${dependencyMapReservedName}'\n` + + 'This is an internal error in Metro.', + ); + } + const WS = '[\t ]*'; + const depMapReferenceRegex = new RegExp( + escapeRegex(dependencyMapReservedName) + `${WS}\\[${WS}([0-9]+)${WS}\\]`, + 'g', + ); + const inlinedCode = code.replace(depMapReferenceRegex, (match, depIndex) => { + const idStr = dependencyIds[Number.parseInt(depIndex, 10)].toString(); + if (idStr.length > match.length) { + // Stop the build rather than silently emit an incorrect source map. + throw new Error( + `Module ID doesn't fit in available space; add ${ + idStr.length - match.length + } more characters to 'dependencyMapReservedName'.`, + ); + } + return idStr.padEnd(match.length); + }); + return inlinedCode; +} + +function escapeRegex(str: string): string { + // From http://stackoverflow.com/questions/14076210/ + return str.replace(/([.?*+^$[\]\\(){}|-])/g, '\\$1'); +} + export function getJsOutput( module: Readonly<{ output: ReadonlyArray, diff --git a/packages/metro/types/DeltaBundler/Serializers/helpers/js.d.ts b/packages/metro/types/DeltaBundler/Serializers/helpers/js.d.ts index b3ea436de3..3161b782b4 100644 --- a/packages/metro/types/DeltaBundler/Serializers/helpers/js.d.ts +++ b/packages/metro/types/DeltaBundler/Serializers/helpers/js.d.ts @@ -6,7 +6,7 @@ * * @noformat * @oncall react_native - * @generated SignedSource<> + * @generated SignedSource<<9cfb26ac2da104285365c1e527665ebe>> * * This file was translated from Flow by scripts/generateTypeScriptDefinitions.js * Original file: packages/metro/src/DeltaBundler/Serializers/helpers/js.js @@ -30,5 +30,36 @@ export type Options = Readonly<{ }>; export declare function wrapModule(module: Module, options: Options): string; export declare function getModuleParams(module: Module, options: Options): Array; +/** + * Fast path for inlining module IDs as a cheap string operation, requiring + * neither parsing nor any adjustment to the source map. + * + * Assumptions: + * 1. `dependencyMapReservedName` is a globally reserved string; there are + * no false positives. + * 2. The longest module ID in the bundle does not exceed a length of + * `dependencyMapReservedName.length + 3`. (We assert this below.) + * 3. False negatives (failing to inline occasionally if an assumption + * isn't met) are rare to nonexistent, but safe if they do occur. + * + * Syntax definitions: + * 1. A dependency map reference is a member expression which, if parsed, + * would have the form: + * MemberExpression + * ├──object: Identifier (name = dependencyMapReservedName) + * ├──property: NumericLiteral (value = some integer) + * └──computed: true + * 2. The concrete form of a dependency map reference may contain embedded + * tabs or spaces, but no newlines (which would complicate source maps), + * parens (which would complicate detection) or comments (likewise). + * 3. The numeric literal in a dependency map reference is a base-10 + * integer printed as a simple sequence of digits. + */ +export declare function inlineModuleIdReferences( + code: string, + dependencyMapReservedName: string, + dependencyIds: ReadonlyArray, + $$PARAM_3$$?: Readonly<{ignoreMissingDependencyMapReference?: boolean}>, +): string; export declare function getJsOutput(module: Readonly<{output: ReadonlyArray; path?: string}>): JsOutput; export declare function isJsModule(module: Module): boolean; From d1bc7f2983b3831c80a972772d0067ab6473c9db Mon Sep 17 00:00:00 2001 From: Rob Hogan Date: Thu, 23 Jul 2026 05:40:17 -0700 Subject: [PATCH 2/2] serializer.unstable_inlineDependencyMap: Add opt-in serialise-time module id inlining to the serialiser (#1786) Summary: Wires the `inlineModuleIdReferences` helper (previous diff) into the OSS serialiser behind a new opt-in `serializer.unstable_inlineDependencyMap`, porting this Metro-Buck optimisation to core. When `serializer.unstable_inlineDependencyMap` AND `transformer.unstable_dependencyMapReservedName` is set, each module body has its `[i]` references replaced with the resolved numeric module ID (right-padded to preserve source-map columns), and the dependency-map array argument is dropped from the `__d(...)` call (where it is empty AND the last argument). For dev bundles, a `null` keeps that slot occupied so the verbose-name argument stays in position. With the flag off, output is unchanged. Threading: - `SerializerConfigT` (+ default) gains `unstable_inlineDependencyMap`. - `SerializerOptions` gains optional `unstable_inlineDependencyMap` and `dependencyMapReservedName`. - `Server.js` populates both at all three serialiser-options construction sites from resolved config (the reserved name is already resolved at serialise time). - `baseJSBundle` -> `processModules` -> `wrapModule`/`getModuleParams` thread the options. Changelog: ``` - **[Experimental]**: Add `serializer.unstable_inlineDependencyMap` for an opt-in runtime optimisation. ``` Reviewed By: motiz88, huntie Differential Revision: D112353887 --- packages/metro-config/src/defaults/index.js | 1 + packages/metro-config/src/types.js | 1 + packages/metro-config/types/types.d.ts | 3 +- .../__tests__/baseJSBundle-test.js | 60 ++++++++++++ .../DeltaBundler/Serializers/baseJSBundle.js | 2 + .../Serializers/helpers/__tests__/js-test.js | 81 +++++++++++++++++ .../DeltaBundler/Serializers/helpers/js.js | 91 +++++++++++++++++-- .../Serializers/helpers/processModules.js | 6 ++ packages/metro/src/DeltaBundler/types.js | 2 + packages/metro/src/Server.js | 12 +++ .../DeltaBundler/Serializers/helpers/js.d.ts | 4 +- .../Serializers/helpers/processModules.d.ts | 4 +- packages/metro/types/DeltaBundler/types.d.ts | 4 +- 13 files changed, 258 insertions(+), 13 deletions(-) diff --git a/packages/metro-config/src/defaults/index.js b/packages/metro-config/src/defaults/index.js index 679d1e9498..4ea6563e32 100644 --- a/packages/metro-config/src/defaults/index.js +++ b/packages/metro-config/src/defaults/index.js @@ -69,6 +69,7 @@ const getDefaultValues = (projectRoot: ?string): ConfigT => ({ customSerializer: null, isThirdPartyModule: module => /(?:^|[/\\])node_modules[/\\]/.test(module.path), + unstable_inlineDependencyMap: false, }, server: { diff --git a/packages/metro-config/src/types.js b/packages/metro-config/src/types.js index 699afc7e6b..c7b98e0d3a 100644 --- a/packages/metro-config/src/types.js +++ b/packages/metro-config/src/types.js @@ -146,6 +146,7 @@ type SerializerConfigT = { polyfillModuleNames: ReadonlyArray, processModuleFilter: (modules: Module<>) => boolean, isThirdPartyModule: (module: Readonly<{path: string, ...}>) => boolean, + unstable_inlineDependencyMap: boolean, }; type TransformerConfigT = { diff --git a/packages/metro-config/types/types.d.ts b/packages/metro-config/types/types.d.ts index fda3ce1d02..0d1af02b3b 100644 --- a/packages/metro-config/types/types.d.ts +++ b/packages/metro-config/types/types.d.ts @@ -6,7 +6,7 @@ * * @noformat * @oncall react_native - * @generated SignedSource<<3f0c3f9093e9a6eadd3a8885218f8f45>> + * @generated SignedSource<<08960eb44a59d3d45155da2e2f9173b9>> * * This file was translated from Flow by scripts/generateTypeScriptDefinitions.js * Original file: packages/metro-config/src/types.js @@ -111,6 +111,7 @@ type SerializerConfigT = { polyfillModuleNames: ReadonlyArray; processModuleFilter: (modules: Module) => boolean; isThirdPartyModule: (module: Readonly<{path: string}>) => boolean; + unstable_inlineDependencyMap: boolean; }; type TransformerConfigT = Omit & { getTransformOptions: GetTransformOptions; diff --git a/packages/metro/src/DeltaBundler/Serializers/__tests__/baseJSBundle-test.js b/packages/metro/src/DeltaBundler/Serializers/__tests__/baseJSBundle-test.js index fcf45643f6..4a7d9a7ed4 100644 --- a/packages/metro/src/DeltaBundler/Serializers/__tests__/baseJSBundle-test.js +++ b/packages/metro/src/DeltaBundler/Serializers/__tests__/baseJSBundle-test.js @@ -549,3 +549,63 @@ test('does not add polyfills when `modulesOnly` is used', () => { } `); }); + +test('inlines module ids when unstable_inlineDependencyMap is set', () => { + const NAME = 'DEP_MAP_RESERVED'; + const ref = `${NAME}[0]`; + const fooWithRefs: Module<> = { + ...fooModule, + output: [ + { + type: 'js/module', + data: { + code: `__d(function(g,r,i,a,m,e,${NAME}){r(${ref})});`, + map: [], + lineCount: 1, + }, + }, + ], + }; + + const bundle = baseJSBundle( + '/root/foo', + [polyfill], + { + dependencies: new Map([ + ['/root/foo', fooWithRefs], + ['/root/bar', barModule], + ]), + entryPoints: new Set(['/root/foo']), + transformOptions, + }, + { + asyncRequireModulePath: '', + createModuleId: createModuleIdFactory(), + dev: false, + getRunModuleStatement, + globalPrefix: '', + includeAsyncPaths: false, + inlineSourceMap: false, + modulesOnly: false, + processModuleFilter: () => true, + projectRoot: '/root', + runBeforeMainModule: [], + runModule: true, + serverRoot: '/root', + shouldAddToIgnoreList: () => false, + sourceMapUrl: null, + sourceUrl: null, + getSourceUrl: null, + dependencyMapReservedName: NAME, + unstable_inlineDependencyMap: true, + }, + ); + + // baseJSBundle pre-assigns sequential ids in graph order: foo=0, bar=1. + // foo's DEP_MAP_RESERVED[0] resolves to its first dependency (bar => 1), + // inlined and right-padded; the dependency-map array is dropped. + expect(bundle.modules).toEqual([ + [0, `__d(function(g,r,i,a,m,e,${NAME}){r(${'1'.padEnd(ref.length)})},0);`], + [1, '__d(function() {/* code for bar */},1);'], + ]); +}); diff --git a/packages/metro/src/DeltaBundler/Serializers/baseJSBundle.js b/packages/metro/src/DeltaBundler/Serializers/baseJSBundle.js index dcfa8297dc..1eb091216c 100644 --- a/packages/metro/src/DeltaBundler/Serializers/baseJSBundle.js +++ b/packages/metro/src/DeltaBundler/Serializers/baseJSBundle.js @@ -38,6 +38,8 @@ export default function baseJSBundle( projectRoot: options.projectRoot, serverRoot: options.serverRoot, sourceUrl: options.sourceUrl, + dependencyMapReservedName: options.dependencyMapReservedName, + unstable_inlineDependencyMap: options.unstable_inlineDependencyMap, }; // Do not prepend polyfills or the require runtime when only modules are requested diff --git a/packages/metro/src/DeltaBundler/Serializers/helpers/__tests__/js-test.js b/packages/metro/src/DeltaBundler/Serializers/helpers/__tests__/js-test.js index f770dd3097..466e94f424 100644 --- a/packages/metro/src/DeltaBundler/Serializers/helpers/__tests__/js-test.js +++ b/packages/metro/src/DeltaBundler/Serializers/helpers/__tests__/js-test.js @@ -200,6 +200,87 @@ describe('wrapModule()', () => { }); }); +describe('wrapModule() with inlined module ids', () => { + const NAME = 'DEPENDENCY_MAP'; + const ref = (i: number) => `${NAME}[${i}]`; + const baseInlineOptions = { + dev: false, + includeAsyncPaths: false, + projectRoot: '/root', + serverRoot: '/root', + sourceUrl: null, + dependencyMapReservedName: NAME, + unstable_inlineDependencyMap: true, + }; + + beforeEach(() => { + // foo=0 (self), bar=1, baz=2 with a fresh sequential id factory. + myModule.output[0].data.code = `__d(function(g,r,i,a,m,e,${NAME}){r(${ref( + 0, + )});r(${ref(1)})});`; + }); + + test('inlines sync ids and drops the dependency-map array', () => { + expect( + wrapModule(myModule, { + ...baseInlineOptions, + createModuleId: createModuleIdFactory(), + }), + ).toBe( + `__d(function(g,r,i,a,m,e,${NAME}){r(${'1'.padEnd( + ref(0).length, + )});r(${'2'.padEnd(ref(1).length)})},0);`, + ); + }); + + test('keeps a placeholder slot before the verbose name in dev', () => { + expect( + wrapModule(myModule, { + ...baseInlineOptions, + dev: true, + createModuleId: createModuleIdFactory(), + }), + ).toBe( + `__d(function(g,r,i,a,m,e,${NAME}){r(${'1'.padEnd( + ref(0).length, + )});r(${'2'.padEnd(ref(1).length)})},0,null,"foo.js");`, + ); + }); + + test('passes a paths object (not the id array) for async dependencies', () => { + const dep = nullthrows(myModule.dependencies.get('bar')); + myModule.dependencies.set('bar', { + ...dep, + data: {...dep.data, data: {...dep.data.data, asyncType: 'async'}}, + }); + expect( + wrapModule(myModule, { + ...baseInlineOptions, + includeAsyncPaths: true, + sourceUrl: 'http://localhost/Main.bundle?param1=true', + createModuleId: createModuleIdFactory(), + }), + ).toBe( + `__d(function(g,r,i,a,m,e,${NAME}){r(${'1'.padEnd( + ref(0).length, + )});r(${'2'.padEnd(ref(1).length)})},0,` + + `{"paths":{"1":"/../bar.bundle?param1=true&modulesOnly=true&runModule=false"}});`, + ); + }); + + test('does not inline when the flag is off, even with a reserved name', () => { + expect( + wrapModule(myModule, { + ...baseInlineOptions, + unstable_inlineDependencyMap: false, + createModuleId: createModuleIdFactory(), + }), + ).toBe( + `__d(function(g,r,i,a,m,e,${NAME}){r(${ref(0)});r(${ref(1)})},0,[1,2]);`, + ); + }); +}); + describe('inlineModuleIdReferences()', () => { const NAME = 'DEP_MAP_RESERVED_NAME'; const ref = (i: number) => `${NAME}[${i}]`; diff --git a/packages/metro/src/DeltaBundler/Serializers/helpers/js.js b/packages/metro/src/DeltaBundler/Serializers/helpers/js.js index 4b6b4e732e..57547d1741 100644 --- a/packages/metro/src/DeltaBundler/Serializers/helpers/js.js +++ b/packages/metro/src/DeltaBundler/Serializers/helpers/js.js @@ -26,6 +26,11 @@ export type Options = Readonly<{ projectRoot: string, serverRoot: string, sourceUrl: ?string, + // When set (and `unstable_inlineDependencyMap` is true), resolved module IDs are + // inlined into each module body in place of `[i]` + // references, instead of being appended as a dependency-map array argument. + dependencyMapReservedName?: ?string, + unstable_inlineDependencyMap?: boolean, ... }>; @@ -36,14 +41,39 @@ export function wrapModule(module: Module<>, options: Options): string { return output.data.code; } + if ( + options.unstable_inlineDependencyMap === true && + options.dependencyMapReservedName != null + ) { + return wrapModuleWithInlinedDependencyIds( + module, + output.data.code, + options.dependencyMapReservedName, + options, + ); + } + const params = getModuleParams(module, options); return addParamsToDefineCall(output.data.code, ...params); } -export function getModuleParams( +function getModuleVerboseName(module: Module<>, options: Options): string { + // The relative path of the module, to make debugging easier. This is mapped + // to `module.verboseName` in `require.js`. + return normalizePathSeparatorsToPosix( + path.relative(options.projectRoot, module.path), + ); +} + +function getModuleDependencies( module: Module<>, options: Options, -): Array { +): { + moduleId: number | string, + dependencyMapArray: Array, + paths: {[moduleID: number | string]: unknown}, + hasPaths: boolean, +} { const moduleId = options.createModuleId(module.path); const paths: {[moduleID: number | string]: unknown} = {}; @@ -93,6 +123,18 @@ export function getModuleParams( }, ); + return {moduleId, dependencyMapArray, paths, hasPaths}; +} + +export function getModuleParams( + module: Module<>, + options: Options, +): Array { + const {moduleId, dependencyMapArray, paths, hasPaths} = getModuleDependencies( + module, + options, + ); + const params = [ moduleId, hasPaths @@ -105,18 +147,49 @@ export function getModuleParams( ]; if (options.dev) { - // Add the relative path of the module to make debugging easier. - // This is mapped to `module.verboseName` in `require.js`. - params.push( - normalizePathSeparatorsToPosix( - path.relative(options.projectRoot, module.path), - ), - ); + params.push(getModuleVerboseName(module, options)); } return params; } +// Wraps a module after inlining resolved module IDs into its body (via +// `inlineModuleIdReferences`). Because synchronous `[i]` +// references are replaced with literal IDs, the dependency-map array argument is +// redundant and dropped. Async requires still read `.paths`, so a +// `{paths}` object is passed in the dependency-map argument slot when needed. In +// dev, an empty array keeps that slot occupied so the verbose-name argument +// stays in position. +function wrapModuleWithInlinedDependencyIds( + module: Module<>, + code: string, + dependencyMapReservedName: string, + options: Options, +): string { + const {moduleId, dependencyMapArray, paths, hasPaths} = getModuleDependencies( + module, + options, + ); + + const inlinedCode = inlineModuleIdReferences( + code, + dependencyMapReservedName, + dependencyMapArray.map(id => (id == null ? 'null' : id)), + ); + + const params: Array = [moduleId]; + if (hasPaths) { + params.push({paths}); + } else if (options.dev) { + params.push(null); + } + if (options.dev) { + params.push(getModuleVerboseName(module, options)); + } + + return addParamsToDefineCall(inlinedCode, ...params); +} + /** * Fast path for inlining module IDs as a cheap string operation, requiring * neither parsing nor any adjustment to the source map. diff --git a/packages/metro/src/DeltaBundler/Serializers/helpers/processModules.js b/packages/metro/src/DeltaBundler/Serializers/helpers/processModules.js index be9bb5d3cc..3319700a88 100644 --- a/packages/metro/src/DeltaBundler/Serializers/helpers/processModules.js +++ b/packages/metro/src/DeltaBundler/Serializers/helpers/processModules.js @@ -23,6 +23,8 @@ export default function processModules( projectRoot, serverRoot, sourceUrl, + dependencyMapReservedName, + unstable_inlineDependencyMap, }: Readonly<{ filter?: (module: Module<>) => boolean, createModuleId: string => number, @@ -31,6 +33,8 @@ export default function processModules( projectRoot: string, serverRoot: string, sourceUrl: ?string, + dependencyMapReservedName?: ?string, + unstable_inlineDependencyMap?: boolean, }>, ): ReadonlyArray<[Module<>, string]> { return [...modules] @@ -45,6 +49,8 @@ export default function processModules( projectRoot, serverRoot, sourceUrl, + dependencyMapReservedName, + unstable_inlineDependencyMap, }), ]); } diff --git a/packages/metro/src/DeltaBundler/types.js b/packages/metro/src/DeltaBundler/types.js index c35a40016d..c2490adedc 100644 --- a/packages/metro/src/DeltaBundler/types.js +++ b/packages/metro/src/DeltaBundler/types.js @@ -168,6 +168,7 @@ export type DeltaResult = { export type SerializerOptions = Readonly<{ asyncRequireModulePath: string, createModuleId: string => number, + dependencyMapReservedName?: ?string, dev: boolean, getRunModuleStatement: ( moduleId: number | string, @@ -186,4 +187,5 @@ export type SerializerOptions = Readonly<{ sourceMapUrl: ?string, sourceUrl: ?string, getSourceUrl: ?(Module<>) => string, + unstable_inlineDependencyMap?: boolean, }>; diff --git a/packages/metro/src/Server.js b/packages/metro/src/Server.js index 29f5a88f3b..42c3cbebfc 100644 --- a/packages/metro/src/Server.js +++ b/packages/metro/src/Server.js @@ -266,6 +266,10 @@ export default class Server { this._shouldAddModuleToIgnoreList(module), getSourceUrl: (module: Module<>) => this._getModuleSourceUrl(module, serializerOptions.sourcePaths), + dependencyMapReservedName: + this._config.transformer.unstable_dependencyMapReservedName, + unstable_inlineDependencyMap: + this._config.serializer.unstable_inlineDependencyMap, }; let bundleCode = null; let bundleMap = null; @@ -412,6 +416,10 @@ export default class Server { this._shouldAddModuleToIgnoreList(module), getSourceUrl: (module: Module<>) => this._getModuleSourceUrl(module, serializerOptions.sourcePaths), + dependencyMapReservedName: + this._config.transformer.unstable_dependencyMapReservedName, + unstable_inlineDependencyMap: + this._config.serializer.unstable_inlineDependencyMap, }); } @@ -1158,6 +1166,10 @@ export default class Server { this._shouldAddModuleToIgnoreList(module), getSourceUrl: (module: Module<>) => this._getModuleSourceUrl(module, serializerOptions.sourcePaths), + dependencyMapReservedName: + this._config.transformer.unstable_dependencyMapReservedName, + unstable_inlineDependencyMap: + this._config.serializer.unstable_inlineDependencyMap, }, ); bundlePerfLogger.point('serializingBundle_end'); diff --git a/packages/metro/types/DeltaBundler/Serializers/helpers/js.d.ts b/packages/metro/types/DeltaBundler/Serializers/helpers/js.d.ts index 3161b782b4..167d5eaf1d 100644 --- a/packages/metro/types/DeltaBundler/Serializers/helpers/js.d.ts +++ b/packages/metro/types/DeltaBundler/Serializers/helpers/js.d.ts @@ -6,7 +6,7 @@ * * @noformat * @oncall react_native - * @generated SignedSource<<9cfb26ac2da104285365c1e527665ebe>> + * @generated SignedSource<> * * This file was translated from Flow by scripts/generateTypeScriptDefinitions.js * Original file: packages/metro/src/DeltaBundler/Serializers/helpers/js.js @@ -27,6 +27,8 @@ export type Options = Readonly<{ projectRoot: string; serverRoot: string; sourceUrl: null | undefined | string; + dependencyMapReservedName?: null | undefined | string; + unstable_inlineDependencyMap?: boolean; }>; export declare function wrapModule(module: Module, options: Options): string; export declare function getModuleParams(module: Module, options: Options): Array; diff --git a/packages/metro/types/DeltaBundler/Serializers/helpers/processModules.d.ts b/packages/metro/types/DeltaBundler/Serializers/helpers/processModules.d.ts index c6ac12639b..d22a42b174 100644 --- a/packages/metro/types/DeltaBundler/Serializers/helpers/processModules.d.ts +++ b/packages/metro/types/DeltaBundler/Serializers/helpers/processModules.d.ts @@ -6,7 +6,7 @@ * * @noformat * @oncall react_native - * @generated SignedSource<<1c5fe56fba9dbedcde1dbaeb5a486467>> + * @generated SignedSource<<9225c6d36e106c7936277e8158e90dc0>> * * This file was translated from Flow by scripts/generateTypeScriptDefinitions.js * Original file: packages/metro/src/DeltaBundler/Serializers/helpers/processModules.js @@ -27,6 +27,8 @@ declare function processModules( projectRoot: string; serverRoot: string; sourceUrl: null | undefined | string; + dependencyMapReservedName?: null | undefined | string; + unstable_inlineDependencyMap?: boolean; }>, ): ReadonlyArray<[Module, string]>; export default processModules; diff --git a/packages/metro/types/DeltaBundler/types.d.ts b/packages/metro/types/DeltaBundler/types.d.ts index ffd1307eed..379747808d 100644 --- a/packages/metro/types/DeltaBundler/types.d.ts +++ b/packages/metro/types/DeltaBundler/types.d.ts @@ -6,7 +6,7 @@ * * @noformat * @oncall react_native - * @generated SignedSource<<295faf3dbcdeffd6b15b9fa949b501cb>> + * @generated SignedSource<<1e7de4a3bc2a47dfb8f5031657e74bb6>> * * This file was translated from Flow by scripts/generateTypeScriptDefinitions.js * Original file: packages/metro/src/DeltaBundler/types.js @@ -126,6 +126,7 @@ export type DeltaResult = { export type SerializerOptions = Readonly<{ asyncRequireModulePath: string; createModuleId: ($$PARAM_0$$: string) => number; + dependencyMapReservedName?: null | undefined | string; dev: boolean; getRunModuleStatement: (moduleId: number | string, globalPrefix: string) => string; globalPrefix: string; @@ -141,4 +142,5 @@ export type SerializerOptions = Readonly<{ sourceMapUrl: null | undefined | string; sourceUrl: null | undefined | string; getSourceUrl: null | undefined | (($$PARAM_0$$: Module) => string); + unstable_inlineDependencyMap?: boolean; }>;