From cf6e12274d055502c3e983b27bfb05b839850c2a Mon Sep 17 00:00:00 2001 From: Durvesh Pilankar Date: Mon, 29 Jun 2026 21:51:55 -0700 Subject: [PATCH] Fix RAM bundle passing the deps function (not its result) to getTransformOptions getRamBundleInfo gives custom getTransformOptions a callback to look up a module's transitive dependencies, but it called `Array.from(getDependencies)` on the function itself instead of `Array.from(getDependencies(x))`. Since the closure has arity 1, Array.from treated it as array-like and returned [undefined], so any getTransformOptions relying on this callback received garbage regardless of the file queried. Invoke getDependencies(x). Existing tests never exercised the callback, which masked this. Adds a regression test that calls the callback and asserts the real transitive deps (fails before / passes after). --- .../__tests__/getRamBundleInfo-test.js | 41 +++++++++++++++++++ .../Serializers/getRamBundleInfo.js | 2 +- 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/packages/metro/src/DeltaBundler/Serializers/__tests__/getRamBundleInfo-test.js b/packages/metro/src/DeltaBundler/Serializers/__tests__/getRamBundleInfo-test.js index c988afebe4..6fc33a61d2 100644 --- a/packages/metro/src/DeltaBundler/Serializers/__tests__/getRamBundleInfo-test.js +++ b/packages/metro/src/DeltaBundler/Serializers/__tests__/getRamBundleInfo-test.js @@ -112,6 +112,47 @@ test('should return the RAM bundle info', async () => { ).toMatchSnapshot(); }); +test('passes a working transitive-dependency lookup to getTransformOptions', async () => { + let resolvedDeps; + await getRamBundleInfo( + '/root/entry.js', + pre, + {...graph, entryPoints: new Set(['/root/entry.js'])}, + { + asyncRequireModulePath: '', + // $FlowFixMe[incompatible-type] createModuleId assumes numeric IDs - is this too strict? + createModuleId: path => path, + dev: true, + excludeSource: false, + getRunModuleStatement, + getTransformOptions: async (entryPoints, opts, getDependenciesOf) => { + resolvedDeps = await getDependenciesOf('/root/foo.js'); + return {preloadedModules: {}, ramGroups: []}; + }, + globalPrefix: '', + includeAsyncPaths: false, + inlineSourceMap: false, + modulesOnly: false, + platform: null, + processModuleFilter: module => true, + projectRoot: '/root', + runBeforeMainModule: [], + runModule: true, + serverRoot: '/root', + shouldAddToIgnoreList: () => false, + sourceMapUrl: 'http://localhost/bundle.map', + sourceUrl: null, + getSourceUrl: null, + }, + ); + // foo depends on bar, baz, qux — the callback must return those, not [undefined]. + expect([...resolvedDeps].sort()).toEqual([ + '/root/bar.js', + '/root/baz.js', + '/root/qux.js', + ]); +}); + test('emits x_google_ignoreList based on shouldAddToIgnoreList', async () => { expect( await getRamBundleInfo( diff --git a/packages/metro/src/DeltaBundler/Serializers/getRamBundleInfo.js b/packages/metro/src/DeltaBundler/Serializers/getRamBundleInfo.js index 9b8047ec08..997f6561cc 100644 --- a/packages/metro/src/DeltaBundler/Serializers/getRamBundleInfo.js +++ b/packages/metro/src/DeltaBundler/Serializers/getRamBundleInfo.js @@ -160,7 +160,7 @@ async function _getRamOptions( /* $FlowFixMe[incompatible-type](>=0.99.0 site=react_native_fb) This comment suppresses an * error found when Flow v0.99 was deployed. To see the error, delete this * comment and run Flow. */ - async (x: string) => Array.from(getDependencies), + async (x: string) => Array.from(getDependencies(x)), ); return {