From 5ba56250b5af7e25c30d8e1a2a744c89adc1c830 Mon Sep 17 00:00:00 2001 From: Jean Lauliac Date: Mon, 24 Jul 2017 17:04:38 -0700 Subject: [PATCH] metro-bundler: remove hardcoded AssetRegistry path Reviewed By: davidaurelio Differential Revision: D5452553 fbshipit-source-id: e0a6f56d3bc03f4ba7f34fbee1ae418495dcc6cd --- .../src/Bundler/__tests__/Bundler-test.js | 1 + packages/metro-bundler/src/Bundler/index.js | 5 +++- packages/metro-bundler/src/Bundler/util.js | 20 ++++++++----- packages/metro-bundler/src/Resolver/index.js | 3 +- packages/metro-bundler/src/Server/index.js | 2 ++ packages/metro-bundler/src/index.js | 1 + .../__snapshots__/basic_bundle-test.js.snap | 28 +++++++++-------- .../__tests__/basic_bundle-test.js | 30 ++++++++++++++----- .../basic_bundle/AssetRegistry.js | 6 ++++ .../Libraries/Image/AssetRegistry.js | 1 - 10 files changed, 66 insertions(+), 31 deletions(-) create mode 100644 packages/metro-bundler/src/integration_tests/basic_bundle/AssetRegistry.js delete mode 100644 packages/metro-bundler/src/integration_tests/basic_bundle/node_modules/react-native/Libraries/Image/AssetRegistry.js diff --git a/packages/metro-bundler/src/Bundler/__tests__/Bundler-test.js b/packages/metro-bundler/src/Bundler/__tests__/Bundler-test.js index 2f107604..bdfd3809 100644 --- a/packages/metro-bundler/src/Bundler/__tests__/Bundler-test.js +++ b/packages/metro-bundler/src/Bundler/__tests__/Bundler-test.js @@ -40,6 +40,7 @@ const {any, objectContaining} = expect; var commonOptions = { allowBundleUpdates: false, assetExts: defaults.assetExts, + assetRegistryPath: '/AssetRegistry.js', cacheVersion: 'smth', enableBabelRCLookup: true, extraNodeModules: {}, diff --git a/packages/metro-bundler/src/Bundler/index.js b/packages/metro-bundler/src/Bundler/index.js index 0109abe8..3a5db474 100644 --- a/packages/metro-bundler/src/Bundler/index.js +++ b/packages/metro-bundler/src/Bundler/index.js @@ -121,6 +121,7 @@ export type PostProcessBundleSourcemap = ({ type Options = {| +allowBundleUpdates: boolean, +assetExts: Array, + +assetRegistryPath: string, +assetServer: AssetServer, +blacklistRE?: RegExp, +cacheVersion: string, @@ -213,6 +214,7 @@ class Bundler { this._resolverPromise = Resolver.load({ assetExts: opts.assetExts, + assetRegistryPath: opts.assetRegistryPath, blacklistRE: opts.blacklistRE, extraNodeModules: opts.extraNodeModules, getPolyfills: opts.getPolyfills, @@ -740,7 +742,8 @@ class Bundler { return this._applyAssetPlugins(assetPlugins, asset); }).then(asset => { - const {code, dependencies, dependencyOffsets} = generateAssetTransformResult(asset); + const {code, dependencies, dependencyOffsets} = + generateAssetTransformResult(this._opts.assetRegistryPath, asset); return { asset, code, diff --git a/packages/metro-bundler/src/Bundler/util.js b/packages/metro-bundler/src/Bundler/util.js index f57b5501..c6c71ec6 100644 --- a/packages/metro-bundler/src/Bundler/util.js +++ b/packages/metro-bundler/src/Bundler/util.js @@ -29,15 +29,16 @@ const assetPropertyBlacklist = new Set([ 'path', ]); -const ASSET_REGISTRY_PATH = 'react-native/Libraries/Image/AssetRegistry'; - -function generateAssetCodeFileAst(assetDescriptor: AssetDescriptor): Object { +function generateAssetCodeFileAst( + assetRegistryPath: string, + assetDescriptor: AssetDescriptor, +): Object { const properDescriptor = filterObject(assetDescriptor, assetPropertyBlacklist); const descriptorAst = babylon.parseExpression(JSON.stringify(properDescriptor)); const t = babel.types; const moduleExports = t.memberExpression(t.identifier('module'), t.identifier('exports')); const requireCall = - t.callExpression(t.identifier('require'), [t.stringLiteral(ASSET_REGISTRY_PATH)]); + t.callExpression(t.identifier('require'), [t.stringLiteral(assetRegistryPath)]); const registerAssetFunction = t.memberExpression(requireCall, t.identifier('registerAsset')); const registerAssetCall = t.callExpression(registerAssetFunction, [descriptorAst]); return t.file(t.program([ @@ -45,17 +46,20 @@ function generateAssetCodeFileAst(assetDescriptor: AssetDescriptor): Object { ])); } -function generateAssetTransformResult(assetDescriptor: AssetDescriptor): {| +function generateAssetTransformResult( + assetRegistryPath: string, + assetDescriptor: AssetDescriptor, +): {| code: string, dependencies: Array, dependencyOffsets: Array, |} { const {code} = babelGenerate( - generateAssetCodeFileAst(assetDescriptor), + generateAssetCodeFileAst(assetRegistryPath, assetDescriptor), {comments: false, compact: true}, ); - const dependencies = [ASSET_REGISTRY_PATH]; - const dependencyOffsets = [code.indexOf(ASSET_REGISTRY_PATH) - 1]; + const dependencies = [assetRegistryPath]; + const dependencyOffsets = [code.indexOf(assetRegistryPath) - 1]; return {code, dependencies, dependencyOffsets}; } diff --git a/packages/metro-bundler/src/Resolver/index.js b/packages/metro-bundler/src/Resolver/index.js index 6626bdcc..d045ed87 100644 --- a/packages/metro-bundler/src/Resolver/index.js +++ b/packages/metro-bundler/src/Resolver/index.js @@ -32,6 +32,7 @@ type ContainsTransformerOptions = {+transformer: JSTransformerOptions} type Options = {| +assetExts: Array, + +assetRegistryPath: string, +blacklistRE?: RegExp, +extraNodeModules: ?{}, +getPolyfills: ({platform: ?string}) => $ReadOnlyArray, @@ -71,7 +72,7 @@ class Resolver { static async load(opts: Options): Promise { const depGraphOpts = { - assetDependencies: ['react-native/Libraries/Image/AssetRegistry'], + assetDependencies: [opts.assetRegistryPath], assetExts: opts.assetExts, extraNodeModules: opts.extraNodeModules, forceNodeFilesystemAPI: false, diff --git a/packages/metro-bundler/src/Server/index.js b/packages/metro-bundler/src/Server/index.js index afd3eb1a..55314e77 100644 --- a/packages/metro-bundler/src/Server/index.js +++ b/packages/metro-bundler/src/Server/index.js @@ -68,6 +68,7 @@ function debounceAndBatch(fn, delay) { type Options = { assetExts?: Array, + +assetRegistryPath: string, blacklistRE?: RegExp, cacheVersion?: string, enableBabelRCLookup?: boolean, @@ -176,6 +177,7 @@ class Server { const maxWorkers = getMaxWorkers(options.maxWorkers); this._opts = { assetExts: options.assetExts || defaults.assetExts, + assetRegistryPath: options.assetRegistryPath, blacklistRE: options.blacklistRE, cacheVersion: options.cacheVersion || '1.0', enableBabelRCLookup: diff --git a/packages/metro-bundler/src/index.js b/packages/metro-bundler/src/index.js index 829bcb12..01f726a1 100644 --- a/packages/metro-bundler/src/index.js +++ b/packages/metro-bundler/src/index.js @@ -33,6 +33,7 @@ exports.createServer = createServer; exports.Logger = Logger; type Options = {| + +assetRegistryPath: string, +sourceExts: ?Array, +transformCache: TransformCache, +transformModulePath: string, diff --git a/packages/metro-bundler/src/integration_tests/__tests__/__snapshots__/basic_bundle-test.js.snap b/packages/metro-bundler/src/integration_tests/__tests__/__snapshots__/basic_bundle-test.js.snap index 5bf88b9c..739b420e 100644 --- a/packages/metro-bundler/src/integration_tests/__tests__/__snapshots__/basic_bundle-test.js.snap +++ b/packages/metro-bundler/src/integration_tests/__tests__/__snapshots__/basic_bundle-test.js.snap @@ -237,8 +237,8 @@ __d(/* /TestBundle.js */function(global, require, module, exports) { 'use strict'; -var Bar = require(5 ); // 5 = ./Bar -var Foo = require(6 ); // 6 = ./Foo +var Bar = require(5); // 5 = ./Bar +var Foo = require(6); // 6 = ./Foo module.exports = { Foo: Foo, Bar: Bar }; }, 0); @@ -246,7 +246,7 @@ __d(/* /Bar.js */function(global, require, module, exports) { 'use strict'; -var Foo = require(6 ); // 6 = ./Foo +var Foo = require(6); // 6 = ./Foo module.exports = { type: 'bar', foo: Foo.type }; }, 5); @@ -254,13 +254,15 @@ __d(/* /Foo.js */function(global, require, module, exports) { 'use strict'; -var asset = require(7 ); // 7 = ./test.png +var asset = require(7); // 7 = ./test.png module.exports = { type: 'foo', asset: asset }; }, 6); -__d(/* /test.png */function(global, require, module, exports) {module.exports=require(8 ).registerAsset({\\"__packager_asset\\":true,\\"httpServerLocation\\":\\"/assets\\",\\"width\\":8,\\"height\\":8,\\"scales\\":[1],\\"hash\\":\\"77d45c1f7fa73c0f6c444a830dc42f67\\",\\"name\\":\\"test\\",\\"type\\":\\"png\\"}); // 8 = react-native/Libraries/Image/AssetRegistry +__d(/* /test.png */function(global, require, module, exports) {module.exports=require(8).registerAsset({\\"__packager_asset\\":true,\\"httpServerLocation\\":\\"/assets\\",\\"width\\":8,\\"height\\":8,\\"scales\\":[1],\\"hash\\":\\"77d45c1f7fa73c0f6c444a830dc42f67\\",\\"name\\":\\"test\\",\\"type\\":\\"png\\"}); // 8 = /AssetRegistry }, 7); -__d(/* /node_modules/react-native/Libraries/Image/AssetRegistry.js */function(global, require, module, exports) {'use strict'; +__d(/* /AssetRegistry.js */function(global, require, module, exports) { + +'use strict'; }, 8); ;require(0);" `; @@ -502,8 +504,8 @@ __d(/* /TestBundle.js */function(global, require, module, exports) { 'use strict'; -var Bar = require(5 ); // 5 = ./Bar -var Foo = require(6 ); // 6 = ./Foo +var Bar = require(5); // 5 = ./Bar +var Foo = require(6); // 6 = ./Foo module.exports = { Foo: Foo, Bar: Bar }; }, 0); @@ -511,7 +513,7 @@ __d(/* /Bar.js */function(global, require, module, exports) { 'use strict'; -var Foo = require(6 ); // 6 = ./Foo +var Foo = require(6); // 6 = ./Foo module.exports = { type: 'bar', foo: Foo.type }; }, 5); @@ -519,13 +521,15 @@ __d(/* /Foo.js */function(global, require, module, exports) { 'use strict'; -var asset = require(7 ); // 7 = ./test.png +var asset = require(7); // 7 = ./test.png module.exports = { type: 'foo', asset: asset }; }, 6); -__d(/* /test.png */function(global, require, module, exports) {module.exports=require(8 ).registerAsset({\\"__packager_asset\\":true,\\"httpServerLocation\\":\\"/assets\\",\\"width\\":8,\\"height\\":8,\\"scales\\":[1],\\"hash\\":\\"77d45c1f7fa73c0f6c444a830dc42f67\\",\\"name\\":\\"test\\",\\"type\\":\\"png\\"}); // 8 = react-native/Libraries/Image/AssetRegistry +__d(/* /test.png */function(global, require, module, exports) {module.exports=require(8).registerAsset({\\"__packager_asset\\":true,\\"httpServerLocation\\":\\"/assets\\",\\"width\\":8,\\"height\\":8,\\"scales\\":[1],\\"hash\\":\\"77d45c1f7fa73c0f6c444a830dc42f67\\",\\"name\\":\\"test\\",\\"type\\":\\"png\\"}); // 8 = /AssetRegistry }, 7); -__d(/* /node_modules/react-native/Libraries/Image/AssetRegistry.js */function(global, require, module, exports) {'use strict'; +__d(/* /AssetRegistry.js */function(global, require, module, exports) { + +'use strict'; }, 8); ;require(0);" `; diff --git a/packages/metro-bundler/src/integration_tests/__tests__/basic_bundle-test.js b/packages/metro-bundler/src/integration_tests/__tests__/basic_bundle-test.js index 13108e1c..43b0b6d8 100644 --- a/packages/metro-bundler/src/integration_tests/__tests__/basic_bundle-test.js +++ b/packages/metro-bundler/src/integration_tests/__tests__/basic_bundle-test.js @@ -20,6 +20,10 @@ jasmine.DEFAULT_TIMEOUT_INTERVAL = 30 * 1000; const INPUT_PATH = path.resolve(__dirname, '../basic_bundle'); const POLYFILLS_PATH = path.resolve(__dirname, '../../Resolver/polyfills'); +const ASSET_REGISTRY_PATH = path.resolve( + __dirname, + '../basic_bundle/AssetRegistry', +); describe('basic_bundle', () => { const absPathRe = new RegExp(INPUT_PATH, 'g'); @@ -74,9 +78,24 @@ describe('basic_bundle', () => { jest.resetModules(); }); + /** + * On different machines and local repos the absolute paths are different so + * we relativize them to the root of the test. We also trim the spacing inside + * ID-based `require()` calls because the way the bundle appears to do it is + * by replacing path strings directly by numbers in the code, not the AST. + */ + function verifyResultCode(code) { + expect( + code + .replace(absPathRe, '') + .replace(/require\(([0-9]*) *\)/g, 'require($1)'), + ).toMatchSnapshot(); + } + it('bundles package with polyfills as expected', async () => { const bundleWithPolyfills = await Packager.buildBundle( { + assetRegistryPath: ASSET_REGISTRY_PATH, getPolyfills: () => [polyfill1, polyfill2], projectRoots: [INPUT_PATH, POLYFILLS_PATH], transformCache: Packager.TransformCaching.none(), @@ -89,15 +108,13 @@ describe('basic_bundle', () => { platform: 'ios', }, ); - - expect( - bundleWithPolyfills.getSource().replace(absPathRe, ''), - ).toMatchSnapshot(); + verifyResultCode(bundleWithPolyfills.getSource()); }); it('bundles package without polyfills as expected', async () => { const bundleWithoutPolyfills = await Packager.buildBundle( { + assetRegistryPath: ASSET_REGISTRY_PATH, getPolyfills: () => [polyfill1, polyfill2], projectRoots: [INPUT_PATH, POLYFILLS_PATH], transformCache: Packager.TransformCaching.none(), @@ -110,9 +127,6 @@ describe('basic_bundle', () => { platform: 'ios', }, ); - - expect( - bundleWithoutPolyfills.getSource().replace(absPathRe, ''), - ).toMatchSnapshot(); + verifyResultCode(bundleWithoutPolyfills.getSource()); }); }); diff --git a/packages/metro-bundler/src/integration_tests/basic_bundle/AssetRegistry.js b/packages/metro-bundler/src/integration_tests/basic_bundle/AssetRegistry.js new file mode 100644 index 00000000..ff894007 --- /dev/null +++ b/packages/metro-bundler/src/integration_tests/basic_bundle/AssetRegistry.js @@ -0,0 +1,6 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + */ + +'use strict'; diff --git a/packages/metro-bundler/src/integration_tests/basic_bundle/node_modules/react-native/Libraries/Image/AssetRegistry.js b/packages/metro-bundler/src/integration_tests/basic_bundle/node_modules/react-native/Libraries/Image/AssetRegistry.js deleted file mode 100644 index ad9a93a7..00000000 --- a/packages/metro-bundler/src/integration_tests/basic_bundle/node_modules/react-native/Libraries/Image/AssetRegistry.js +++ /dev/null @@ -1 +0,0 @@ -'use strict';