mirror of https://github.com/status-im/metro.git
Remove ModuleTransport/ResolutionResponse modules and lots of logic from Resolver/ResolutionRequest
Reviewed By: davidaurelio Differential Revision: D6284728 fbshipit-source-id: 53d27cd65b8c96ed6d6872eb16a9b5d1e14db85e
This commit is contained in:
parent
860dcc4867
commit
e1b5fe79fa
|
@ -18,7 +18,6 @@ const debug = require('debug')('Metro:Bundler');
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const Transformer = require('../JSTransformer');
|
const Transformer = require('../JSTransformer');
|
||||||
const Resolver = require('../Resolver');
|
const Resolver = require('../Resolver');
|
||||||
const ModuleTransport = require('../lib/ModuleTransport');
|
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const defaults = require('../defaults');
|
const defaults = require('../defaults');
|
||||||
const createModuleIdFactory = require('../lib/createModuleIdFactory');
|
const createModuleIdFactory = require('../lib/createModuleIdFactory');
|
||||||
|
@ -240,12 +239,6 @@ class Bundler {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
getModuleForPath(entryFile: string): Promise<Module> {
|
|
||||||
return this._resolverPromise.then(resolver =>
|
|
||||||
resolver.getModuleForPath(entryFile),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
async generateAssetObjAndCode(
|
async generateAssetObjAndCode(
|
||||||
module: Module,
|
module: Module,
|
||||||
assetPlugins: Array<string>,
|
assetPlugins: Array<string>,
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
const Generator = require('./Generator');
|
const Generator = require('./Generator');
|
||||||
const SourceMap = require('source-map');
|
const SourceMap = require('source-map');
|
||||||
|
|
||||||
import type ModuleTransport from '../../lib/ModuleTransport';
|
|
||||||
import type {MappingsMap, RawMappings} from '../../lib/SourceMap';
|
import type {MappingsMap, RawMappings} from '../../lib/SourceMap';
|
||||||
import type {RawMapping as BabelRawMapping} from 'babel-generator';
|
import type {RawMapping as BabelRawMapping} from 'babel-generator';
|
||||||
|
|
||||||
|
|
|
@ -322,20 +322,22 @@ class DeltaTransformer extends EventEmitter {
|
||||||
}
|
}
|
||||||
|
|
||||||
async _getAppend(dependencyEdges: DependencyEdges): Promise<DeltaEntries> {
|
async _getAppend(dependencyEdges: DependencyEdges): Promise<DeltaEntries> {
|
||||||
|
const dependencyGraph = this._resolver.getDependencyGraph();
|
||||||
|
|
||||||
// Get the absolute path of the entry file, in order to be able to get the
|
// Get the absolute path of the entry file, in order to be able to get the
|
||||||
// actual correspondant module (and its moduleId) to be able to add the
|
// actual correspondant module (and its moduleId) to be able to add the
|
||||||
// correct require(); call at the very end of the bundle.
|
// correct require(); call at the very end of the bundle.
|
||||||
const absPath = this._resolver
|
const absPath = dependencyGraph.getAbsolutePath(
|
||||||
.getDependencyGraph()
|
this._bundleOptions.entryFile,
|
||||||
.getAbsolutePath(this._bundleOptions.entryFile);
|
);
|
||||||
const entryPointModule = this._resolver.getModuleForPath(absPath);
|
const entryPointModule = dependencyGraph.getModuleForPath(absPath);
|
||||||
|
|
||||||
// First, get the modules correspondant to all the module names defined in
|
// First, get the modules correspondant to all the module names defined in
|
||||||
// the `runBeforeMainModule` config variable. Then, append the entry point
|
// the `runBeforeMainModule` config variable. Then, append the entry point
|
||||||
// module so the last thing that gets required is the entry point.
|
// module so the last thing that gets required is the entry point.
|
||||||
const append = new Map(
|
const append = new Map(
|
||||||
this._bundleOptions.runBeforeMainModule
|
this._bundleOptions.runBeforeMainModule
|
||||||
.map(path => this._resolver.getModuleForPath(path))
|
.map(path => dependencyGraph.getModuleForPath(path))
|
||||||
.concat(entryPointModule)
|
.concat(entryPointModule)
|
||||||
.filter(module => dependencyEdges.has(module.path))
|
.filter(module => dependencyEdges.has(module.path))
|
||||||
.map(this._getModuleId)
|
.map(this._getModuleId)
|
||||||
|
|
|
@ -96,94 +96,6 @@ describe('Resolver', function() {
|
||||||
return polyfill;
|
return polyfill;
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('getDependencies', function() {
|
|
||||||
it('forwards transform options to the dependency graph', function() {
|
|
||||||
expect.assertions(1);
|
|
||||||
const transformOptions = {arbitrary: 'options'};
|
|
||||||
const platform = 'ios';
|
|
||||||
const entry = '/root/index.js';
|
|
||||||
|
|
||||||
DependencyGraph.prototype.getDependencies.mockImplementation(() =>
|
|
||||||
Promise.reject(),
|
|
||||||
);
|
|
||||||
return Resolver.load({projectRoot: '/root'})
|
|
||||||
.then(r => r.getDependencies(entry, {platform}, transformOptions))
|
|
||||||
.catch(() => {
|
|
||||||
expect(DependencyGraph.prototype.getDependencies).toBeCalledWith({
|
|
||||||
entryPath: entry,
|
|
||||||
platform,
|
|
||||||
options: transformOptions,
|
|
||||||
recursive: true,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('passes custom platforms to the dependency graph', function() {
|
|
||||||
expect.assertions(1);
|
|
||||||
return Resolver.load({
|
|
||||||
projectRoot: '/root',
|
|
||||||
platforms: ['ios', 'windows', 'vr'],
|
|
||||||
}).then(() => {
|
|
||||||
const platforms = DependencyGraph.mock.calls[0][0].platforms;
|
|
||||||
expect(Array.from(platforms)).toEqual(['ios', 'windows', 'vr']);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should pass in more polyfills when prependPolyfills is true', function() {
|
|
||||||
expect.assertions(3);
|
|
||||||
|
|
||||||
var module = createModule('index');
|
|
||||||
var deps = [module];
|
|
||||||
|
|
||||||
var depResolverPromise = Resolver.load({
|
|
||||||
getPolyfills: () => ['custom-polyfill-1', 'custom-polyfill-2'],
|
|
||||||
projectRoot: '/root',
|
|
||||||
});
|
|
||||||
|
|
||||||
DependencyGraph.prototype.getDependencies.mockImplementation(function() {
|
|
||||||
return Promise.resolve(
|
|
||||||
new ResolutionResponseMock({
|
|
||||||
dependencies: deps,
|
|
||||||
mainModuleId: 'index',
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
return depResolverPromise
|
|
||||||
.then(r =>
|
|
||||||
r.getDependencies(
|
|
||||||
'/root/index.js',
|
|
||||||
{dev: false, prependPolyfills: true},
|
|
||||||
undefined,
|
|
||||||
undefined,
|
|
||||||
createGetModuleId(),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.then(result => {
|
|
||||||
expect(result.mainModuleId).toEqual('index');
|
|
||||||
const calls = DependencyGraph.prototype.createPolyfill.mock.calls;
|
|
||||||
const callPolyfill1 = calls[result.dependencies.length - 3];
|
|
||||||
const callPolyfill2 = calls[result.dependencies.length - 2];
|
|
||||||
|
|
||||||
expect(callPolyfill1).toEqual([
|
|
||||||
{
|
|
||||||
file: 'custom-polyfill-1',
|
|
||||||
id: 'custom-polyfill-1',
|
|
||||||
dependencies: [],
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
|
|
||||||
expect(callPolyfill2).toEqual([
|
|
||||||
{
|
|
||||||
file: 'custom-polyfill-2',
|
|
||||||
id: 'custom-polyfill-2',
|
|
||||||
dependencies: ['custom-polyfill-1'],
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('wrapModule', function() {
|
describe('wrapModule', function() {
|
||||||
let depResolver;
|
let depResolver;
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
|
|
@ -23,7 +23,6 @@ const {
|
||||||
} = require('../Bundler/source-map');
|
} = require('../Bundler/source-map');
|
||||||
const pathJoin = require('path').join;
|
const pathJoin = require('path').join;
|
||||||
|
|
||||||
import type ResolutionResponse from '../node-haste/DependencyGraph/ResolutionResponse';
|
|
||||||
import type Module, {HasteImpl, TransformCode} from '../node-haste/Module';
|
import type Module, {HasteImpl, TransformCode} from '../node-haste/Module';
|
||||||
import type {MappingsMap, CompactRawMappings} from '../lib/SourceMap';
|
import type {MappingsMap, CompactRawMappings} from '../lib/SourceMap';
|
||||||
import type {PostMinifyProcess} from '../Bundler';
|
import type {PostMinifyProcess} from '../Bundler';
|
||||||
|
@ -107,52 +106,6 @@ class Resolver {
|
||||||
return new Resolver(opts, depGraph);
|
return new Resolver(opts, depGraph);
|
||||||
}
|
}
|
||||||
|
|
||||||
getShallowDependencies(
|
|
||||||
entryFile: string,
|
|
||||||
transformOptions: JSTransformerOptions,
|
|
||||||
): Promise<Array<string>> {
|
|
||||||
return this._depGraph.getShallowDependencies(entryFile, transformOptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
getModuleForPath(entryFile: string): Module {
|
|
||||||
return this._depGraph.getModuleForPath(entryFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
async getDependencies<T: ContainsTransformerOptions>(
|
|
||||||
entryPath: string,
|
|
||||||
options: {
|
|
||||||
platform: ?string,
|
|
||||||
recursive?: boolean,
|
|
||||||
prependPolyfills: boolean,
|
|
||||||
},
|
|
||||||
bundlingOptions: T,
|
|
||||||
onProgress?: ?(finishedModules: number, totalModules: number) => mixed,
|
|
||||||
getModuleId: mixed,
|
|
||||||
): Promise<ResolutionResponse<Module, T>> {
|
|
||||||
const {platform, recursive = true, prependPolyfills} = options;
|
|
||||||
|
|
||||||
const resolutionResponse: ResolutionResponse<
|
|
||||||
Module,
|
|
||||||
T,
|
|
||||||
> = await this._depGraph.getDependencies({
|
|
||||||
entryPath,
|
|
||||||
platform,
|
|
||||||
options: bundlingOptions,
|
|
||||||
recursive,
|
|
||||||
onProgress,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (prependPolyfills) {
|
|
||||||
this._getPolyfillDependencies(platform)
|
|
||||||
.reverse()
|
|
||||||
.forEach(polyfill => resolutionResponse.prependDependency(polyfill));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* $FlowFixMe: monkey patching */
|
|
||||||
resolutionResponse.getModuleId = getModuleId;
|
|
||||||
return resolutionResponse.finalize();
|
|
||||||
}
|
|
||||||
|
|
||||||
getModuleSystemDependencies({dev = true}: {dev?: boolean}): Array<Module> {
|
getModuleSystemDependencies({dev = true}: {dev?: boolean}): Array<Module> {
|
||||||
const prelude = dev
|
const prelude = dev
|
||||||
? pathJoin(__dirname, 'polyfills/prelude_dev.js')
|
? pathJoin(__dirname, 'polyfills/prelude_dev.js')
|
||||||
|
@ -169,20 +122,6 @@ class Resolver {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
_getPolyfillDependencies(platform: ?string): Array<Module> {
|
|
||||||
const polyfillModuleNames = this._getPolyfills({platform}).concat(
|
|
||||||
this._polyfillModuleNames,
|
|
||||||
);
|
|
||||||
|
|
||||||
return polyfillModuleNames.map((polyfillModuleName, idx) =>
|
|
||||||
this._depGraph.createPolyfill({
|
|
||||||
file: polyfillModuleName,
|
|
||||||
id: polyfillModuleName,
|
|
||||||
dependencies: polyfillModuleNames.slice(0, idx),
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
resolveRequires(
|
resolveRequires(
|
||||||
module: Module,
|
module: Module,
|
||||||
getModuleId: ({path: string}) => number,
|
getModuleId: ({path: string}) => number,
|
||||||
|
|
|
@ -1,79 +0,0 @@
|
||||||
/**
|
|
||||||
* Copyright (c) 2015-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.
|
|
||||||
*
|
|
||||||
* @flow
|
|
||||||
* @format
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
import type {RawMapping} from '../Bundler/source-map';
|
|
||||||
import type Module from '../node-haste/Module';
|
|
||||||
import type {SourceMap} from './SourceMap';
|
|
||||||
|
|
||||||
export type SourceMapOrMappings = SourceMap | Array<RawMapping>;
|
|
||||||
|
|
||||||
type Metadata = {
|
|
||||||
dependencies?: ?Array<string>,
|
|
||||||
dependencyPairs?: Array<[string, Module]>,
|
|
||||||
preloaded: ?boolean,
|
|
||||||
dependencyOffsets?: ?Array<number>,
|
|
||||||
};
|
|
||||||
|
|
||||||
class ModuleTransport {
|
|
||||||
name: string;
|
|
||||||
id: number;
|
|
||||||
code: string;
|
|
||||||
sourceCode: string;
|
|
||||||
sourcePath: string;
|
|
||||||
virtual: boolean;
|
|
||||||
meta: ?Metadata;
|
|
||||||
polyfill: boolean;
|
|
||||||
map: ?SourceMapOrMappings;
|
|
||||||
|
|
||||||
constructor(data: {
|
|
||||||
name: string,
|
|
||||||
id: number,
|
|
||||||
code: string,
|
|
||||||
sourceCode: string,
|
|
||||||
sourcePath: string,
|
|
||||||
virtual?: boolean,
|
|
||||||
meta?: ?Metadata,
|
|
||||||
polyfill?: boolean,
|
|
||||||
map?: ?SourceMapOrMappings,
|
|
||||||
}) {
|
|
||||||
this.name = data.name;
|
|
||||||
|
|
||||||
assertExists(data, 'id');
|
|
||||||
this.id = data.id;
|
|
||||||
|
|
||||||
assertExists(data, 'code');
|
|
||||||
this.code = data.code;
|
|
||||||
|
|
||||||
assertExists(data, 'sourceCode');
|
|
||||||
this.sourceCode = data.sourceCode;
|
|
||||||
|
|
||||||
assertExists(data, 'sourcePath');
|
|
||||||
this.sourcePath = data.sourcePath;
|
|
||||||
|
|
||||||
this.virtual = !!data.virtual;
|
|
||||||
this.meta = data.meta;
|
|
||||||
this.polyfill = !!data.polyfill;
|
|
||||||
this.map = data.map;
|
|
||||||
|
|
||||||
Object.freeze(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = ModuleTransport;
|
|
||||||
|
|
||||||
function assertExists(obj, field) {
|
|
||||||
if (obj[field] == null) {
|
|
||||||
throw new Error('Modules must have `' + field + '`');
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -19,7 +19,6 @@ const JestHasteMap = require('jest-haste-map');
|
||||||
const Module = require('./Module');
|
const Module = require('./Module');
|
||||||
const ModuleCache = require('./ModuleCache');
|
const ModuleCache = require('./ModuleCache');
|
||||||
const ResolutionRequest = require('./DependencyGraph/ResolutionRequest');
|
const ResolutionRequest = require('./DependencyGraph/ResolutionRequest');
|
||||||
const ResolutionResponse = require('./DependencyGraph/ResolutionResponse');
|
|
||||||
|
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const isAbsolutePath = require('absolute-path');
|
const isAbsolutePath = require('absolute-path');
|
||||||
|
@ -233,10 +232,6 @@ class DependencyGraph extends EventEmitter {
|
||||||
return this._moduleCache.getModule(entryFile);
|
return this._moduleCache.getModule(entryFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
getAllModules() {
|
|
||||||
return Promise.resolve(this._moduleCache.getAllModules());
|
|
||||||
}
|
|
||||||
|
|
||||||
resolveDependency(
|
resolveDependency(
|
||||||
fromModule: Module,
|
fromModule: Module,
|
||||||
toModuleName: string,
|
toModuleName: string,
|
||||||
|
@ -253,45 +248,6 @@ class DependencyGraph extends EventEmitter {
|
||||||
return req.resolveDependency(fromModule, toModuleName);
|
return req.resolveDependency(fromModule, toModuleName);
|
||||||
}
|
}
|
||||||
|
|
||||||
getDependencies<T: {+transformer: JSTransformerOptions}>({
|
|
||||||
entryPath,
|
|
||||||
options,
|
|
||||||
platform,
|
|
||||||
onProgress,
|
|
||||||
recursive = true,
|
|
||||||
}: {
|
|
||||||
entryPath: string,
|
|
||||||
options: T,
|
|
||||||
platform: ?string,
|
|
||||||
onProgress?: ?(finishedModules: number, totalModules: number) => mixed,
|
|
||||||
recursive: boolean,
|
|
||||||
}): Promise<ResolutionResponse<Module, T>> {
|
|
||||||
platform = this._getRequestPlatform(entryPath, platform);
|
|
||||||
const absPath = this.getAbsolutePath(entryPath);
|
|
||||||
const req = new ResolutionRequest({
|
|
||||||
moduleResolver: this._moduleResolver,
|
|
||||||
entryPath: absPath,
|
|
||||||
helpers: this._helpers,
|
|
||||||
platform: platform != null ? platform : null,
|
|
||||||
moduleCache: this._moduleCache,
|
|
||||||
});
|
|
||||||
|
|
||||||
const response = new ResolutionResponse(options);
|
|
||||||
|
|
||||||
return req
|
|
||||||
.getOrderedDependencies({
|
|
||||||
response,
|
|
||||||
transformOptions: options.transformer,
|
|
||||||
onProgress,
|
|
||||||
recursive,
|
|
||||||
})
|
|
||||||
.then(() => response);
|
|
||||||
}
|
|
||||||
|
|
||||||
matchFilesByPattern(pattern: RegExp) {
|
|
||||||
return Promise.resolve(this._hasteFS.matchFiles(pattern));
|
|
||||||
}
|
|
||||||
|
|
||||||
_doesFileExist = (filePath: string): boolean => {
|
_doesFileExist = (filePath: string): boolean => {
|
||||||
return this._hasteFS.exists(filePath);
|
return this._hasteFS.exists(filePath);
|
||||||
};
|
};
|
||||||
|
|
|
@ -12,23 +12,19 @@
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const AsyncTaskGroup = require('../lib/AsyncTaskGroup');
|
|
||||||
const MapWithDefaults = require('../lib/MapWithDefaults');
|
|
||||||
const ModuleResolution = require('./ModuleResolution');
|
const ModuleResolution = require('./ModuleResolution');
|
||||||
|
|
||||||
const debug = require('debug')('Metro:DependencyGraph');
|
|
||||||
const isAbsolutePath = require('absolute-path');
|
const isAbsolutePath = require('absolute-path');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
|
||||||
const {DuplicateHasteCandidatesError} = require('jest-haste-map').ModuleMap;
|
const {DuplicateHasteCandidatesError} = require('jest-haste-map').ModuleMap;
|
||||||
|
|
||||||
import type DependencyGraphHelpers from './DependencyGraphHelpers';
|
import type DependencyGraphHelpers from './DependencyGraphHelpers';
|
||||||
import type ResolutionResponse from './ResolutionResponse';
|
|
||||||
import type {Options as TransformWorkerOptions} from '../../JSTransformer/worker';
|
import type {Options as TransformWorkerOptions} from '../../JSTransformer/worker';
|
||||||
import type {ReadResult, CachedReadResult} from '../Module';
|
import type {ReadResult, CachedReadResult} from '../Module';
|
||||||
import type {ModuleResolver} from './ModuleResolution';
|
import type {ModuleResolver} from './ModuleResolution';
|
||||||
|
|
||||||
const {UnableToResolveError, isRelativeImport} = ModuleResolution;
|
const {isRelativeImport} = ModuleResolution;
|
||||||
|
|
||||||
export type Packageish = {
|
export type Packageish = {
|
||||||
isHaste(): boolean,
|
isHaste(): boolean,
|
||||||
|
@ -126,239 +122,6 @@ class ResolutionRequest<TModule: Moduleish, TPackage: Packageish> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
resolveModuleDependencies(
|
|
||||||
module: TModule,
|
|
||||||
dependencyNames: $ReadOnlyArray<string>,
|
|
||||||
): [$ReadOnlyArray<string>, $ReadOnlyArray<TModule>] {
|
|
||||||
const dependencies = dependencyNames.map(name =>
|
|
||||||
this.resolveDependency(module, name),
|
|
||||||
);
|
|
||||||
return [dependencyNames, dependencies];
|
|
||||||
}
|
|
||||||
|
|
||||||
getOrderedDependencies<T>({
|
|
||||||
response,
|
|
||||||
transformOptions,
|
|
||||||
onProgress,
|
|
||||||
recursive = true,
|
|
||||||
}: {
|
|
||||||
response: ResolutionResponse<TModule, T>,
|
|
||||||
transformOptions: TransformWorkerOptions,
|
|
||||||
onProgress?: ?(finishedModules: number, totalModules: number) => mixed,
|
|
||||||
recursive: boolean,
|
|
||||||
}): Promise<void> {
|
|
||||||
const entry = this._options.moduleCache.getModule(this._options.entryPath);
|
|
||||||
|
|
||||||
response.pushDependency(entry);
|
|
||||||
let totalModules = 1;
|
|
||||||
let finishedModules = 0;
|
|
||||||
|
|
||||||
let preprocessedModuleCount = 1;
|
|
||||||
if (recursive) {
|
|
||||||
this._preprocessPotentialDependencies(transformOptions, entry, count => {
|
|
||||||
if (count + 1 <= preprocessedModuleCount) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
preprocessedModuleCount = count + 1;
|
|
||||||
if (onProgress != null) {
|
|
||||||
onProgress(finishedModules, preprocessedModuleCount);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const resolveDependencies = (module: TModule) =>
|
|
||||||
Promise.resolve().then(() => {
|
|
||||||
const cached = module.readCached(transformOptions);
|
|
||||||
if (cached.result != null) {
|
|
||||||
return this.resolveModuleDependencies(
|
|
||||||
module,
|
|
||||||
cached.result.dependencies,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return module
|
|
||||||
.readFresh(transformOptions)
|
|
||||||
.then(({dependencies}) =>
|
|
||||||
this.resolveModuleDependencies(module, dependencies),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
const collectedDependencies: MapWithDefaults<
|
|
||||||
TModule,
|
|
||||||
Promise<Array<TModule>>,
|
|
||||||
> = new MapWithDefaults(module => collect(module));
|
|
||||||
const crawlDependencies = (mod, [depNames, dependencies]) => {
|
|
||||||
const filteredPairs = [];
|
|
||||||
|
|
||||||
dependencies.forEach((modDep, i) => {
|
|
||||||
const name = depNames[i];
|
|
||||||
if (modDep == null) {
|
|
||||||
debug(
|
|
||||||
'WARNING: Cannot find required module `%s` from module `%s`',
|
|
||||||
name,
|
|
||||||
mod.path,
|
|
||||||
);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return filteredPairs.push([name, modDep]);
|
|
||||||
});
|
|
||||||
|
|
||||||
response.setResolvedDependencyPairs(mod, filteredPairs);
|
|
||||||
|
|
||||||
const dependencyModules = filteredPairs.map(([, m]) => m);
|
|
||||||
const newDependencies = dependencyModules.filter(
|
|
||||||
m => !collectedDependencies.has(m),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (onProgress) {
|
|
||||||
finishedModules += 1;
|
|
||||||
totalModules += newDependencies.length;
|
|
||||||
onProgress(
|
|
||||||
finishedModules,
|
|
||||||
Math.max(totalModules, preprocessedModuleCount),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (recursive) {
|
|
||||||
// doesn't block the return of this function invocation, but defers
|
|
||||||
// the resulution of collectionsInProgress.done.then(...)
|
|
||||||
dependencyModules.forEach(dependency =>
|
|
||||||
collectedDependencies.get(dependency),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return dependencyModules;
|
|
||||||
};
|
|
||||||
|
|
||||||
const collectionsInProgress = new AsyncTaskGroup();
|
|
||||||
function collect(module) {
|
|
||||||
collectionsInProgress.start(module);
|
|
||||||
const result = resolveDependencies(module).then(deps =>
|
|
||||||
crawlDependencies(module, deps),
|
|
||||||
);
|
|
||||||
const end = () => collectionsInProgress.end(module);
|
|
||||||
result.then(end, end);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
function resolveKeyWithPromise(
|
|
||||||
[key: TModule, promise: Promise<Array<TModule>>],
|
|
||||||
): Promise<[TModule, Array<TModule>]> {
|
|
||||||
return promise.then(value => [key, value]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Promise.all([
|
|
||||||
// kicks off recursive dependency discovery, but doesn't block until it's
|
|
||||||
// done
|
|
||||||
collectedDependencies.get(entry),
|
|
||||||
|
|
||||||
// resolves when there are no more modules resolving dependencies
|
|
||||||
collectionsInProgress.done,
|
|
||||||
])
|
|
||||||
.then(([rootDependencies]) => {
|
|
||||||
return Promise.all(
|
|
||||||
Array.from(collectedDependencies, resolveKeyWithPromise),
|
|
||||||
).then(moduleToDependenciesPairs => [
|
|
||||||
rootDependencies,
|
|
||||||
new MapWithDefaults(() => [], moduleToDependenciesPairs),
|
|
||||||
]);
|
|
||||||
})
|
|
||||||
.then(([rootDependencies, moduleDependencies]) => {
|
|
||||||
// serialize dependencies, and make sure that every single one is only
|
|
||||||
// included once
|
|
||||||
const seen = new Set([entry]);
|
|
||||||
function traverse(dependencies) {
|
|
||||||
dependencies.forEach(dependency => {
|
|
||||||
if (seen.has(dependency)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
seen.add(dependency);
|
|
||||||
response.pushDependency(dependency);
|
|
||||||
traverse(moduleDependencies.get(dependency));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
traverse(rootDependencies);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This synchronously look at all the specified modules and recursively kicks
|
|
||||||
* off global cache fetching or transforming (via `readFresh`). This is a hack
|
|
||||||
* that workaround the current structure, because we could do better. First
|
|
||||||
* off, the algorithm that resolves dependencies recursively should be
|
|
||||||
* synchronous itself until it cannot progress anymore (and needs to call
|
|
||||||
* `readFresh`), so that this algo would be integrated into it.
|
|
||||||
*/
|
|
||||||
_preprocessPotentialDependencies(
|
|
||||||
transformOptions: TransformWorkerOptions,
|
|
||||||
module: TModule,
|
|
||||||
onProgress: (moduleCount: number) => mixed,
|
|
||||||
): void {
|
|
||||||
const visitedModulePaths = new Set();
|
|
||||||
const pendingBatches = [
|
|
||||||
this.preprocessModule(transformOptions, module, visitedModulePaths),
|
|
||||||
];
|
|
||||||
onProgress(visitedModulePaths.size);
|
|
||||||
while (pendingBatches.length > 0) {
|
|
||||||
const dependencyModules = pendingBatches.pop();
|
|
||||||
while (dependencyModules.length > 0) {
|
|
||||||
const dependencyModule = dependencyModules.pop();
|
|
||||||
const deps = this.preprocessModule(
|
|
||||||
transformOptions,
|
|
||||||
dependencyModule,
|
|
||||||
visitedModulePaths,
|
|
||||||
);
|
|
||||||
pendingBatches.push(deps);
|
|
||||||
onProgress(visitedModulePaths.size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
preprocessModule(
|
|
||||||
transformOptions: TransformWorkerOptions,
|
|
||||||
module: TModule,
|
|
||||||
visitedModulePaths: Set<string>,
|
|
||||||
): Array<TModule> {
|
|
||||||
const cached = module.readCached(transformOptions);
|
|
||||||
if (cached.result == null) {
|
|
||||||
module.readFresh(transformOptions).catch(error => {
|
|
||||||
/* ignore errors, they'll be handled later if the dependency is actually
|
|
||||||
* not obsolete, and required from somewhere */
|
|
||||||
});
|
|
||||||
}
|
|
||||||
const dependencies =
|
|
||||||
cached.result != null
|
|
||||||
? cached.result.dependencies
|
|
||||||
: cached.outdatedDependencies;
|
|
||||||
return this.tryResolveModuleDependencies(
|
|
||||||
module,
|
|
||||||
dependencies,
|
|
||||||
visitedModulePaths,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
tryResolveModuleDependencies(
|
|
||||||
module: TModule,
|
|
||||||
dependencyNames: $ReadOnlyArray<string>,
|
|
||||||
visitedModulePaths: Set<string>,
|
|
||||||
): Array<TModule> {
|
|
||||||
const result = [];
|
|
||||||
for (let i = 0; i < dependencyNames.length; ++i) {
|
|
||||||
try {
|
|
||||||
const depModule = this.resolveDependency(module, dependencyNames[i]);
|
|
||||||
if (!visitedModulePaths.has(depModule.path)) {
|
|
||||||
visitedModulePaths.add(depModule.path);
|
|
||||||
result.push(depModule);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
if (!(error instanceof UnableToResolveError)) {
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
_resetResolutionCache() {
|
_resetResolutionCache() {
|
||||||
this._immediateResolutionCache = Object.create(null);
|
this._immediateResolutionCache = Object.create(null);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,126 +0,0 @@
|
||||||
/**
|
|
||||||
* Copyright (c) 2015-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.
|
|
||||||
*
|
|
||||||
* @flow
|
|
||||||
* @format
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
const NO_OPTIONS = {};
|
|
||||||
|
|
||||||
class ResolutionResponse<TModule: {hash(): string}, TOptions> {
|
|
||||||
dependencies: Array<TModule>;
|
|
||||||
mainModuleId: ?(number | string);
|
|
||||||
mocks: mixed;
|
|
||||||
numPrependedDependencies: number;
|
|
||||||
options: TOptions;
|
|
||||||
|
|
||||||
// This is monkey-patched from Resolver.
|
|
||||||
getModuleId: ?() => number;
|
|
||||||
|
|
||||||
_mappings: {[hash: string]: Array<[string, TModule]>, __proto__: null};
|
|
||||||
_finalized: boolean;
|
|
||||||
_mainModule: ?TModule;
|
|
||||||
|
|
||||||
constructor(options: TOptions) {
|
|
||||||
this.dependencies = [];
|
|
||||||
this.mainModuleId = null;
|
|
||||||
this.mocks = null;
|
|
||||||
this.numPrependedDependencies = 0;
|
|
||||||
this.options = options;
|
|
||||||
this._mappings = Object.create(null);
|
|
||||||
this._finalized = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
copy(properties: {
|
|
||||||
dependencies?: Array<TModule>,
|
|
||||||
mainModuleId?: number,
|
|
||||||
mocks?: mixed,
|
|
||||||
}): ResolutionResponse<TModule, TOptions> {
|
|
||||||
const {
|
|
||||||
dependencies = this.dependencies,
|
|
||||||
mainModuleId = this.mainModuleId,
|
|
||||||
mocks = this.mocks,
|
|
||||||
} = properties;
|
|
||||||
|
|
||||||
const numPrependedDependencies =
|
|
||||||
dependencies === this.dependencies ? this.numPrependedDependencies : 0;
|
|
||||||
|
|
||||||
/* $FlowFixMe: Flow doesn't like Object.assign on class-made objects. */
|
|
||||||
return Object.assign(new this.constructor(this.options), this, {
|
|
||||||
dependencies,
|
|
||||||
mainModuleId,
|
|
||||||
mocks,
|
|
||||||
numPrependedDependencies,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
_assertNotFinalized() {
|
|
||||||
if (this._finalized) {
|
|
||||||
throw new Error('Attempted to mutate finalized response.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_assertFinalized() {
|
|
||||||
if (!this._finalized) {
|
|
||||||
throw new Error('Attempted to access unfinalized response.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
finalize(): Promise<this> {
|
|
||||||
return Promise.resolve().then(() => {
|
|
||||||
/* $FlowFixMe: _mainModule is not initialized in the constructor. */
|
|
||||||
this.mainModuleId = this._mainModule.getName();
|
|
||||||
this._finalized = true;
|
|
||||||
return this;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
pushDependency(module: TModule) {
|
|
||||||
this._assertNotFinalized();
|
|
||||||
if (this.dependencies.length === 0) {
|
|
||||||
this._mainModule = module;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.dependencies.push(module);
|
|
||||||
}
|
|
||||||
|
|
||||||
prependDependency(module: TModule) {
|
|
||||||
this._assertNotFinalized();
|
|
||||||
this.dependencies.unshift(module);
|
|
||||||
this.numPrependedDependencies += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
setResolvedDependencyPairs(
|
|
||||||
module: TModule,
|
|
||||||
pairs: Array<[string, TModule]>,
|
|
||||||
options: {ignoreFinalized?: boolean} = NO_OPTIONS,
|
|
||||||
) {
|
|
||||||
if (!options.ignoreFinalized) {
|
|
||||||
this._assertNotFinalized();
|
|
||||||
}
|
|
||||||
const hash = module.hash();
|
|
||||||
if (this._mappings[hash] == null) {
|
|
||||||
this._mappings[hash] = pairs;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setMocks(mocks: mixed) {
|
|
||||||
this.mocks = mocks;
|
|
||||||
}
|
|
||||||
|
|
||||||
getResolvedDependencyPairs(
|
|
||||||
module: TModule,
|
|
||||||
): $ReadOnlyArray<[string, TModule]> {
|
|
||||||
this._assertFinalized();
|
|
||||||
return this._mappings[module.hash()] || [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = ResolutionResponse;
|
|
|
@ -1,37 +0,0 @@
|
||||||
/**
|
|
||||||
* 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.
|
|
||||||
*
|
|
||||||
* @flow
|
|
||||||
* @format
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
module.exports = class AsyncTaskGroup<TTaskHandle> {
|
|
||||||
_runningTasks: Set<TTaskHandle>;
|
|
||||||
_resolve: ?() => void;
|
|
||||||
done: Promise<void>;
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
this._runningTasks = new Set();
|
|
||||||
this._resolve = null;
|
|
||||||
this.done = new Promise(resolve => (this._resolve = resolve));
|
|
||||||
}
|
|
||||||
|
|
||||||
start(taskHandle: TTaskHandle) {
|
|
||||||
this._runningTasks.add(taskHandle);
|
|
||||||
}
|
|
||||||
|
|
||||||
end(taskHandle: TTaskHandle) {
|
|
||||||
const runningTasks = this._runningTasks;
|
|
||||||
if (runningTasks.delete(taskHandle) && runningTasks.size === 0) {
|
|
||||||
/* $FlowFixMe: could be null */
|
|
||||||
this._resolve();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -10,7 +10,11 @@
|
||||||
* @format
|
* @format
|
||||||
*/
|
*/
|
||||||
'use strict';
|
'use strict';
|
||||||
import type {SourceMapOrMappings} from '../lib/ModuleTransport';
|
|
||||||
|
import type {RawMapping} from '../Bundler/source-map';
|
||||||
|
import type {SourceMap} from '../lib/SourceMap';
|
||||||
|
|
||||||
|
type SourceMapOrMappings = SourceMap | Array<RawMapping>;
|
||||||
|
|
||||||
export type ModuleGroups = {|
|
export type ModuleGroups = {|
|
||||||
groups: Map<number, Set<number>>,
|
groups: Map<number, Set<number>>,
|
||||||
|
|
Loading…
Reference in New Issue