metro-bundler: remove hardcoded AssetRegistry path

Reviewed By: davidaurelio

Differential Revision: D5452553

fbshipit-source-id: e0a6f56d3bc03f4ba7f34fbee1ae418495dcc6cd
This commit is contained in:
Jean Lauliac 2017-07-24 17:04:38 -07:00 committed by Facebook Github Bot
parent 74e78ee43f
commit 5ba56250b5
10 changed files with 66 additions and 31 deletions

View File

@ -40,6 +40,7 @@ const {any, objectContaining} = expect;
var commonOptions = {
allowBundleUpdates: false,
assetExts: defaults.assetExts,
assetRegistryPath: '/AssetRegistry.js',
cacheVersion: 'smth',
enableBabelRCLookup: true,
extraNodeModules: {},

View File

@ -121,6 +121,7 @@ export type PostProcessBundleSourcemap = ({
type Options = {|
+allowBundleUpdates: boolean,
+assetExts: Array<string>,
+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,

View File

@ -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<string>,
dependencyOffsets: Array<number>,
|} {
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};
}

View File

@ -32,6 +32,7 @@ type ContainsTransformerOptions = {+transformer: JSTransformerOptions}
type Options = {|
+assetExts: Array<string>,
+assetRegistryPath: string,
+blacklistRE?: RegExp,
+extraNodeModules: ?{},
+getPolyfills: ({platform: ?string}) => $ReadOnlyArray<string>,
@ -71,7 +72,7 @@ class Resolver {
static async load(opts: Options): Promise<Resolver> {
const depGraphOpts = {
assetDependencies: ['react-native/Libraries/Image/AssetRegistry'],
assetDependencies: [opts.assetRegistryPath],
assetExts: opts.assetExts,
extraNodeModules: opts.extraNodeModules,
forceNodeFilesystemAPI: false,

View File

@ -68,6 +68,7 @@ function debounceAndBatch(fn, delay) {
type Options = {
assetExts?: Array<string>,
+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:

View File

@ -33,6 +33,7 @@ exports.createServer = createServer;
exports.Logger = Logger;
type Options = {|
+assetRegistryPath: string,
+sourceExts: ?Array<string>,
+transformCache: TransformCache,
+transformModulePath: string,

View File

@ -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);"
`;

View File

@ -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());
});
});

View File

@ -0,0 +1,6 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*/
'use strict';