mirror of https://github.com/status-im/metro.git
metro: collectDependencies: do not hardwire dependency on asyncRequire
Reviewed By: rafeca Differential Revision: D6773002 fbshipit-source-id: a55b63f6bf20f467496ffe1d18c663b87f5d7ba6
This commit is contained in:
parent
47519ec56b
commit
4b7371d732
|
@ -81,6 +81,7 @@ export type PostProcessBundleSourcemap = ({
|
|||
export type Options = {|
|
||||
+assetExts: Array<string>,
|
||||
+assetRegistryPath: string,
|
||||
+asyncRequireModulePath: string,
|
||||
+blacklistRE?: RegExp,
|
||||
+cacheVersion: string,
|
||||
+dynamicDepsInPackages: DynamicRequiresBehavior,
|
||||
|
@ -120,6 +121,7 @@ class Bundler {
|
|||
opts.projectRoots.forEach(verifyRootExists);
|
||||
|
||||
this._transformer = new Transformer({
|
||||
asyncRequireModulePath: opts.asyncRequireModulePath,
|
||||
maxWorkers: opts.maxWorkers,
|
||||
reporters: {
|
||||
stdoutChunk: chunk =>
|
||||
|
@ -139,6 +141,7 @@ class Bundler {
|
|||
extraNodeModules: opts.extraNodeModules,
|
||||
getPolyfills: opts.getPolyfills,
|
||||
getTransformCacheKey: getTransformCacheKeyFn({
|
||||
asyncRequireModulePath: opts.asyncRequireModulePath,
|
||||
cacheVersion: opts.cacheVersion,
|
||||
dynamicDepsInPackages: opts.dynamicDepsInPackages,
|
||||
projectRoots: opts.projectRoots,
|
||||
|
|
|
@ -27,6 +27,7 @@ describe('Transformer', function() {
|
|||
const transformModulePath = __filename;
|
||||
|
||||
const opts = {
|
||||
asyncRequireModulePath: 'asyncRequire',
|
||||
maxWorkers: 4,
|
||||
reporters: {},
|
||||
transformModulePath,
|
||||
|
@ -82,6 +83,7 @@ describe('Transformer', function() {
|
|||
transformOptions,
|
||||
[],
|
||||
'',
|
||||
'asyncRequire',
|
||||
'reject',
|
||||
);
|
||||
});
|
||||
|
|
|
@ -38,16 +38,19 @@ type Reporters = {
|
|||
module.exports = class Transformer {
|
||||
_worker: WorkerInterface;
|
||||
_transformModulePath: string;
|
||||
_asyncRequireModulePath: string;
|
||||
_dynamicDepsInPackages: DynamicRequiresBehavior;
|
||||
|
||||
constructor(options: {|
|
||||
+maxWorkers: number,
|
||||
+reporters: Reporters,
|
||||
+transformModulePath: string,
|
||||
+asyncRequireModulePath: string,
|
||||
+dynamicDepsInPackages: DynamicRequiresBehavior,
|
||||
+workerPath: ?string,
|
||||
|}) {
|
||||
this._transformModulePath = options.transformModulePath;
|
||||
this._asyncRequireModulePath = options.asyncRequireModulePath;
|
||||
this._dynamicDepsInPackages = options.dynamicDepsInPackages;
|
||||
const {workerPath = require.resolve('./worker')} = options;
|
||||
|
||||
|
@ -108,6 +111,7 @@ module.exports = class Transformer {
|
|||
options,
|
||||
assetExts,
|
||||
assetRegistryPath,
|
||||
this._asyncRequireModulePath,
|
||||
this._dynamicDepsInPackages,
|
||||
);
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@ describe('code transformation worker:', () => {
|
|||
},
|
||||
[],
|
||||
'',
|
||||
'asyncRequire',
|
||||
'reject',
|
||||
);
|
||||
|
||||
|
@ -61,6 +62,7 @@ describe('code transformation worker:', () => {
|
|||
},
|
||||
[],
|
||||
'',
|
||||
'asyncRequire',
|
||||
'reject',
|
||||
);
|
||||
|
||||
|
@ -93,6 +95,7 @@ describe('code transformation worker:', () => {
|
|||
},
|
||||
[],
|
||||
'',
|
||||
'asyncRequire',
|
||||
'reject',
|
||||
);
|
||||
|
||||
|
@ -133,6 +136,7 @@ describe('code transformation worker:', () => {
|
|||
},
|
||||
[],
|
||||
'',
|
||||
'asyncRequire',
|
||||
'reject',
|
||||
);
|
||||
throw new Error('should not reach this');
|
||||
|
@ -157,6 +161,7 @@ describe('code transformation worker:', () => {
|
|||
},
|
||||
[],
|
||||
'',
|
||||
'asyncRequire',
|
||||
'throwAtRuntime',
|
||||
);
|
||||
});
|
||||
|
|
|
@ -98,6 +98,7 @@ function postTransform(
|
|||
isScript: boolean,
|
||||
options: Options,
|
||||
transformFileStartLogEntry: LogEntry,
|
||||
asyncRequireModulePath: string,
|
||||
dynamicDepsInPackages: DynamicRequiresBehavior,
|
||||
receivedAst: ?Ast,
|
||||
): Data {
|
||||
|
@ -128,6 +129,7 @@ function postTransform(
|
|||
let dependencyMapName;
|
||||
try {
|
||||
const opts = {
|
||||
asyncRequireModulePath,
|
||||
dynamicRequires: getDynamicDepsBehavior(
|
||||
dynamicDepsInPackages,
|
||||
filename,
|
||||
|
@ -197,6 +199,7 @@ function transformCode(
|
|||
options: Options,
|
||||
assetExts: $ReadOnlyArray<string>,
|
||||
assetRegistryPath: string,
|
||||
asyncRequireModulePath: string,
|
||||
dynamicDepsInPackages: DynamicRequiresBehavior,
|
||||
): Data | Promise<Data> {
|
||||
const isJson = filename.endsWith('.json');
|
||||
|
@ -243,6 +246,7 @@ function transformCode(
|
|||
isScript,
|
||||
options,
|
||||
transformFileStartLogEntry,
|
||||
asyncRequireModulePath,
|
||||
dynamicDepsInPackages,
|
||||
];
|
||||
|
||||
|
|
|
@ -21,7 +21,10 @@ const {codeFromAst, comparableCode} = require('../../test-helpers');
|
|||
const {any} = expect;
|
||||
|
||||
const {InvalidRequireCallError} = collectDependencies;
|
||||
const opts = {dynamicRequires: 'reject'};
|
||||
const opts = {
|
||||
asyncRequireModulePath: 'asyncRequire',
|
||||
dynamicRequires: 'reject',
|
||||
};
|
||||
|
||||
it('collects unique dependency identifiers and transforms the AST', () => {
|
||||
const ast = astFromCode(`
|
||||
|
@ -193,7 +196,10 @@ describe('Evaluating static arguments', () => {
|
|||
|
||||
it('throws at runtime when requiring non-strings with special option', () => {
|
||||
const ast = astFromCode('require(1)');
|
||||
const opts = {dynamicRequires: 'throwAtRuntime'};
|
||||
const opts = {
|
||||
asyncRequireModulePath: 'asyncRequire',
|
||||
dynamicRequires: 'throwAtRuntime',
|
||||
};
|
||||
const {dependencies} = collectDependencies(ast, opts);
|
||||
expect(dependencies).toEqual([]);
|
||||
expect(codeFromAst(ast)).toEqual(
|
||||
|
|
|
@ -27,6 +27,7 @@ const {objectContaining} = jasmine;
|
|||
describe('optimizing JS modules', () => {
|
||||
const filename = 'arbitrary/file.js';
|
||||
const sourceExts = new Set(['js', 'json']);
|
||||
const asyncRequireModulePath = 'asyncRequire';
|
||||
const optimizationOptions = {
|
||||
dev: false,
|
||||
platform: 'android',
|
||||
|
@ -43,7 +44,7 @@ describe('optimizing JS modules', () => {
|
|||
|
||||
let transformResult;
|
||||
beforeAll(() => {
|
||||
const trOpts = {filename, sourceExts, transformer};
|
||||
const trOpts = {asyncRequireModulePath, filename, sourceExts, transformer};
|
||||
const result = transformModule(originalCode, trOpts);
|
||||
invariant(result.type === 'code', 'result must be code');
|
||||
transformResult = new Buffer(
|
||||
|
|
|
@ -33,6 +33,7 @@ jest.mock('image-size', () => buffer => {
|
|||
describe('transforming JS modules:', () => {
|
||||
const filename = 'arbitrary.js';
|
||||
const sourceExts = new Set(['js', 'json']);
|
||||
const asyncRequireModulePath = 'asyncRequire';
|
||||
|
||||
let transformer;
|
||||
|
||||
|
@ -47,6 +48,7 @@ describe('transforming JS modules:', () => {
|
|||
const {bodyAst, sourceCode, transformedCode} = createTestData();
|
||||
|
||||
const options = (variants?: TransformVariants) => ({
|
||||
asyncRequireModulePath,
|
||||
filename,
|
||||
sourceExts,
|
||||
transformer,
|
||||
|
|
|
@ -21,12 +21,16 @@ const prettyPrint = require('babel-generator').default;
|
|||
import type {TransformResultDependency} from '../types.flow';
|
||||
|
||||
export type DynamicRequiresBehavior = 'throwAtRuntime' | 'reject';
|
||||
type Options = {|+dynamicRequires: DynamicRequiresBehavior|};
|
||||
type Options = {|
|
||||
+dynamicRequires: DynamicRequiresBehavior,
|
||||
+asyncRequireModulePath: string,
|
||||
|};
|
||||
|
||||
type Context = {
|
||||
nameToIndex: Map<string, number>,
|
||||
dependencies: Array<{|+name: string, isAsync: boolean|}>,
|
||||
+asyncRequireModulePath: string,
|
||||
+dynamicRequires: DynamicRequiresBehavior,
|
||||
dependencies: Array<{|+name: string, isAsync: boolean|}>,
|
||||
nameToIndex: Map<string, number>,
|
||||
};
|
||||
|
||||
type CollectedDependencies = {|
|
||||
|
@ -47,8 +51,13 @@ function collectDependencies(
|
|||
options: Options,
|
||||
): CollectedDependencies {
|
||||
const visited = new WeakSet();
|
||||
const {dynamicRequires} = options;
|
||||
const context = {nameToIndex: new Map(), dependencies: [], dynamicRequires};
|
||||
const {asyncRequireModulePath, dynamicRequires} = options;
|
||||
const context = {
|
||||
asyncRequireModulePath,
|
||||
dynamicRequires,
|
||||
dependencies: [],
|
||||
nameToIndex: new Map(),
|
||||
};
|
||||
const visitor = {
|
||||
Program(path, state) {
|
||||
state.dependencyMapIdentifier = path.scope.generateUidIdentifier(
|
||||
|
@ -90,9 +99,10 @@ function processImportCall(context, path, node, depMapIdent) {
|
|||
}
|
||||
const index = assignDependencyIndex(context, name, 'import');
|
||||
const mapLookup = createDepMapLookup(depMapIdent, index);
|
||||
const {asyncRequireModulePath} = context;
|
||||
const newImport = makeAsyncRequire({
|
||||
MODULE_ID: mapLookup,
|
||||
ASYNC_REQUIRE_PATH: {type: 'StringLiteral', value: 'asyncRequire'},
|
||||
ASYNC_REQUIRE_PATH: {type: 'StringLiteral', value: asyncRequireModulePath},
|
||||
});
|
||||
path.replaceWith(newImport);
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@ import type {
|
|||
import type {Ast} from 'babel-core';
|
||||
|
||||
export type TransformOptions<ExtraOptions> = {|
|
||||
+asyncRequireModulePath: string,
|
||||
filename: string,
|
||||
hasteImpl?: HasteImpl,
|
||||
polyfill?: boolean,
|
||||
|
@ -76,7 +77,7 @@ function transformModule(
|
|||
return {type: 'unknown'};
|
||||
}
|
||||
|
||||
const code = content.toString('utf8');
|
||||
const sourceCode = content.toString('utf8');
|
||||
const {filename, transformer, polyfill, variants = defaultVariants} = options;
|
||||
const transformed: {[key: string]: TransformResult} = {};
|
||||
|
||||
|
@ -85,15 +86,22 @@ function transformModule(
|
|||
filename,
|
||||
localPath: filename,
|
||||
options: {...defaultTransformOptions, ...variants[variantName]},
|
||||
src: code,
|
||||
src: sourceCode,
|
||||
});
|
||||
invariant(ast != null, 'ast required from the transform results');
|
||||
transformed[variantName] = makeResult(ast, filename, code, polyfill);
|
||||
const {asyncRequireModulePath} = options;
|
||||
transformed[variantName] = makeResult({
|
||||
ast,
|
||||
asyncRequireModulePath,
|
||||
filename,
|
||||
isPolyfill: polyfill || false,
|
||||
sourceCode,
|
||||
});
|
||||
}
|
||||
|
||||
let hasteID = null;
|
||||
if (filename.indexOf(NODE_MODULES) === -1 && !polyfill) {
|
||||
hasteID = docblock.parse(docblock.extract(code)).providesModule;
|
||||
hasteID = docblock.parse(docblock.extract(sourceCode)).providesModule;
|
||||
if (options.hasteImpl) {
|
||||
if (options.hasteImpl.enforceHasteNameMatches) {
|
||||
options.hasteImpl.enforceHasteNameMatches(filename, hasteID);
|
||||
|
@ -182,17 +190,25 @@ function getAssetSize(
|
|||
return {width, height};
|
||||
}
|
||||
|
||||
function makeResult(ast: Ast, filename, sourceCode, isPolyfill = false) {
|
||||
function makeResult(options: {|
|
||||
+ast: Ast,
|
||||
+asyncRequireModulePath: string,
|
||||
+filename: string,
|
||||
+isPolyfill: boolean,
|
||||
+sourceCode: string,
|
||||
|}) {
|
||||
let dependencies, dependencyMapName, file;
|
||||
if (isPolyfill) {
|
||||
const {ast} = options;
|
||||
if (options.isPolyfill) {
|
||||
dependencies = [];
|
||||
file = JsFileWrapping.wrapPolyfill(ast);
|
||||
} else {
|
||||
const opts = {dynamicRequires: 'reject'};
|
||||
const {asyncRequireModulePath} = options;
|
||||
const opts = {asyncRequireModulePath, dynamicRequires: 'reject'};
|
||||
({dependencies, dependencyMapName} = collectDependencies(ast, opts));
|
||||
file = JsFileWrapping.wrapModule(ast, dependencyMapName);
|
||||
}
|
||||
|
||||
const {filename, sourceCode} = options;
|
||||
const gen = generate(file, filename, sourceCode, false);
|
||||
return {
|
||||
code: gen.code,
|
||||
|
|
|
@ -168,6 +168,9 @@ class Server {
|
|||
bundlerOpts.globalTransformCache = options.globalTransformCache;
|
||||
bundlerOpts.watch = this._opts.watch;
|
||||
bundlerOpts.reporter = reporter;
|
||||
bundlerOpts.asyncRequireModulePath =
|
||||
options.asyncRequireModulePath ||
|
||||
'metro/src/lib/bundle-modules/asyncRequire';
|
||||
this._bundler = new Bundler(bundlerOpts);
|
||||
|
||||
// changes to the haste map can affect resolution of files in the bundle
|
||||
|
|
|
@ -169,6 +169,7 @@ function toServerOptions(options: Options): ServerOptions {
|
|||
assetTransforms: options.assetTransforms,
|
||||
assetExts: options.assetExts,
|
||||
assetRegistryPath: options.assetRegistryPath,
|
||||
asyncRequireModulePath: options.asyncRequireModulePath,
|
||||
blacklistRE: options.blacklistRE,
|
||||
cacheVersion: options.cacheVersion,
|
||||
dynamicDepsInPackages: options.dynamicDepsInPackages,
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`getTransformCacheKeyFn Should return always the same key for the same params 1`] = `"c4732dae08f17ef9c571cb8bcc24d249166862c6"`;
|
||||
exports[`getTransformCacheKeyFn Should return always the same key for the same params 1`] = `"1b825aa92d266cc01c946596e777463bd7e68c82"`;
|
||||
|
|
|
@ -20,6 +20,7 @@ describe('getTransformCacheKeyFn', () => {
|
|||
it('Should return always the same key for the same params', async () => {
|
||||
expect(
|
||||
getTransformCacheKeyFn({
|
||||
asyncRequireModulePath: 'beep',
|
||||
cacheVersion: '1.0',
|
||||
dynamicDepsInPackages: 'arbitrary',
|
||||
projectRoots: [__dirname],
|
||||
|
@ -33,6 +34,7 @@ describe('getTransformCacheKeyFn', () => {
|
|||
|
||||
it('Should return a different key when the params change', async () => {
|
||||
const baseParams = {
|
||||
asyncRequireModulePath: 'beep',
|
||||
cacheVersion: '1.0',
|
||||
dynamicDepsInPackages: 'arbitrary',
|
||||
projectRoots: [__dirname],
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
/**
|
||||
* Copyright (c) 2016-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @format
|
||||
* @flow
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
// eslint-disable-next-line flow-no-fixme
|
||||
const dynamicRequire = (require: $FlowFixMe);
|
||||
module.exports = function(moduleID: mixed): Promise<mixed> {
|
||||
return Promise.resolve(dynamicRequire(moduleID));
|
||||
};
|
|
@ -23,6 +23,7 @@ const VERSION = require('../../package.json').version;
|
|||
* passed transform options.
|
||||
*/
|
||||
function getTransformCacheKeyFn(opts: {|
|
||||
+asyncRequireModulePath: string,
|
||||
+cacheVersion: string,
|
||||
+dynamicDepsInPackages: string,
|
||||
+projectRoots: $ReadOnlyArray<string>,
|
||||
|
@ -46,6 +47,7 @@ function getTransformCacheKeyFn(opts: {|
|
|||
.split(path.sep)
|
||||
.join('-'),
|
||||
transformModuleHash,
|
||||
opts.asyncRequireModulePath,
|
||||
opts.dynamicDepsInPackages,
|
||||
];
|
||||
|
||||
|
|
|
@ -71,6 +71,7 @@ export type Options = {|
|
|||
// TODO: Remove this option below (T23793920)
|
||||
assetTransforms?: boolean,
|
||||
assetExts?: Array<string>,
|
||||
+asyncRequireModulePath?: string,
|
||||
+assetRegistryPath: string,
|
||||
blacklistRE?: RegExp,
|
||||
cacheVersion?: string,
|
||||
|
|
Loading…
Reference in New Issue