diff --git a/packages/metro/src/DeltaBundler/Serializers/baseJSBundle.js b/packages/metro/src/DeltaBundler/Serializers/baseJSBundle.js index f7946959db..07c616b4c5 100644 --- a/packages/metro/src/DeltaBundler/Serializers/baseJSBundle.js +++ b/packages/metro/src/DeltaBundler/Serializers/baseJSBundle.js @@ -39,6 +39,7 @@ function baseJSBundle( includeAsyncPaths: options.includeAsyncPaths, projectRoot: options.projectRoot, serverRoot: options.serverRoot, + sourceUrl: options.sourceUrl, }; // 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 48d2d909d0..c6cdd4c576 100644 --- a/packages/metro/src/DeltaBundler/Serializers/helpers/__tests__/js-test.js +++ b/packages/metro/src/DeltaBundler/Serializers/helpers/__tests__/js-test.js @@ -68,6 +68,7 @@ describe('wrapModule()', () => { includeAsyncPaths: false, projectRoot: '/root', serverRoot: '/root', + sourceUrl: null, }), ), ).toMatchInlineSnapshot(`__d(function() { console.log("foo") },0,[1,2]);`); @@ -82,6 +83,7 @@ describe('wrapModule()', () => { includeAsyncPaths: false, projectRoot: '/root', serverRoot: '/root', + sourceUrl: null, }), ), ).toMatchInlineSnapshot( @@ -100,6 +102,7 @@ describe('wrapModule()', () => { includeAsyncPaths: false, projectRoot: '/root', serverRoot: '/root', + sourceUrl: null, }), ), ).toMatchInlineSnapshot(`__d(function() { console.log("foo") });`); @@ -115,6 +118,7 @@ describe('wrapModule()', () => { includeAsyncPaths: false, projectRoot: '/root', serverRoot: '/root', + sourceUrl: null, }), ), ).toMatchInlineSnapshot( @@ -136,10 +140,11 @@ describe('wrapModule()', () => { includeAsyncPaths: true, projectRoot: '/root', serverRoot: '/root', + sourceUrl: 'http://localhost/Main.bundle?param1=true¶m2=1234', }), ), ).toMatchInlineSnapshot( - `__d(function() { console.log("foo") },0,{"0":1,"1":2,"paths":{"1":"../bar"}});`, + `__d(function() { console.log("foo") },0,{"0":1,"1":2,"paths":{"1":"/../bar.bundle?param1=true¶m2=1234&modulesOnly=true&runModule=false"}});`, ); }); @@ -157,10 +162,34 @@ describe('wrapModule()', () => { includeAsyncPaths: true, projectRoot: '/root', serverRoot: '/', + sourceUrl: 'http://localhost/Main.bundle?param1=true¶m2=1234', }), ), ).toMatchInlineSnapshot( - `__d(function() { console.log("foo") },0,{"0":1,"1":2,"paths":{"1":"bar"}});`, + `__d(function() { console.log("foo") },0,{"0":1,"1":2,"paths":{"1":"/bar.bundle?param1=true¶m2=1234&modulesOnly=true&runModule=false"}});`, + ); + }); + + it('async bundle paths override modulesOnly and runModule', () => { + const dep = nullthrows(myModule.dependencies.get('bar')); + myModule.dependencies.set('bar', { + ...dep, + data: {...dep.data, data: {...dep.data.data, asyncType: 'async'}}, + }); + expect( + raw( + wrapModule(myModule, { + createModuleId: createModuleIdFactory(), + dev: false, + includeAsyncPaths: true, + projectRoot: '/root', + serverRoot: '/root', + sourceUrl: + 'http://localhost/Main.bundle?modulesOnly=false&runModule=true', + }), + ), + ).toMatchInlineSnapshot( + `__d(function() { console.log("foo") },0,{"0":1,"1":2,"paths":{"1":"/../bar.bundle?modulesOnly=true&runModule=false"}});`, ); }); }); diff --git a/packages/metro/src/DeltaBundler/Serializers/helpers/js.js b/packages/metro/src/DeltaBundler/Serializers/helpers/js.js index a2aec82834..c358356046 100644 --- a/packages/metro/src/DeltaBundler/Serializers/helpers/js.js +++ b/packages/metro/src/DeltaBundler/Serializers/helpers/js.js @@ -24,6 +24,7 @@ export type Options = $ReadOnly<{ includeAsyncPaths: boolean, projectRoot: string, serverRoot: string, + sourceUrl: ?string, ... }>; @@ -48,16 +49,33 @@ function getModuleParams(module: Module<>, options: Options): Array { const id = options.createModuleId(dependency.absolutePath); if (options.includeAsyncPaths && dependency.data.data.asyncType != null) { hasPaths = true; + invariant( + options.sourceUrl != null, + 'sourceUrl is required when includeAsyncPaths is true', + ); + + // TODO: Only include path if the target is not in the bundle + + // Construct a server-relative URL for the split bundle, propagating + // most parameters from the main bundle's URL. + + const {searchParams} = new URL(options.sourceUrl); + searchParams.set('modulesOnly', 'true'); + searchParams.set('runModule', 'false'); + const bundlePath = path.relative( options.serverRoot, dependency.absolutePath, ); - // TODO: Eventually this slicing should be asyncRequire's responsibility - // Strip the file extension - paths[id] = path.join( - path.dirname(bundlePath), - path.basename(bundlePath, path.extname(bundlePath)), - ); + paths[id] = + '/' + + path.join( + path.dirname(bundlePath), + // Strip the file extension + path.basename(bundlePath, path.extname(bundlePath)), + ) + + '.bundle?' + + searchParams.toString(); } return id; }, diff --git a/packages/metro/src/DeltaBundler/Serializers/helpers/processModules.js b/packages/metro/src/DeltaBundler/Serializers/helpers/processModules.js index 52474df3f4..1318875ea6 100644 --- a/packages/metro/src/DeltaBundler/Serializers/helpers/processModules.js +++ b/packages/metro/src/DeltaBundler/Serializers/helpers/processModules.js @@ -24,6 +24,7 @@ function processModules( includeAsyncPaths, projectRoot, serverRoot, + sourceUrl, }: $ReadOnly<{ filter?: (module: Module<>) => boolean, createModuleId: string => number, @@ -31,6 +32,7 @@ function processModules( includeAsyncPaths: boolean, projectRoot: string, serverRoot: string, + sourceUrl: ?string, }>, ): $ReadOnlyArray<[Module<>, string]> { return [...modules] @@ -44,6 +46,7 @@ function processModules( includeAsyncPaths, projectRoot, serverRoot, + sourceUrl, }), ]); } diff --git a/packages/metro/src/DeltaBundler/Serializers/hmrJSBundle.js b/packages/metro/src/DeltaBundler/Serializers/hmrJSBundle.js index 5250170a7b..95e602f80a 100644 --- a/packages/metro/src/DeltaBundler/Serializers/hmrJSBundle.js +++ b/packages/metro/src/DeltaBundler/Serializers/hmrJSBundle.js @@ -77,6 +77,7 @@ function prepareModule( ): string { const code = wrapModule(module, { ...options, + sourceUrl: url.format(options.clientUrl), dev: true, }); diff --git a/packages/metro/src/shared/types.flow.js b/packages/metro/src/shared/types.flow.js index 0c901da846..0a9a410858 100644 --- a/packages/metro/src/shared/types.flow.js +++ b/packages/metro/src/shared/types.flow.js @@ -60,7 +60,6 @@ export type BundleOptions = { sourceUrl: ?string, createModuleIdFactory?: () => (path: string) => number, +unstable_transformProfile: TransformProfile, - ... }; export type ResolverInputOptions = $ReadOnly<{