packager: Resolver: make the Resolver construction a Promise
Reviewed By: cpojer Differential Revision: D4681614 fbshipit-source-id: 5da558280edf300f67042e72c65b272e49351871
This commit is contained in:
parent
5177a55314
commit
1030aabbc4
|
@ -86,6 +86,7 @@ describe('Bundler', function() {
|
|||
getModuleSystemDependencies,
|
||||
};
|
||||
});
|
||||
Resolver.load = jest.fn().mockImplementation(opts => Promise.resolve(new Resolver(opts)));
|
||||
|
||||
fs.statSync.mockImplementation(function() {
|
||||
return {
|
||||
|
|
|
@ -108,7 +108,7 @@ class Bundler {
|
|||
_getModuleId: (opts: Module) => number;
|
||||
_cache: Cache;
|
||||
_transformer: Transformer;
|
||||
_resolver: Resolver;
|
||||
_resolverPromise: Promise<Resolver>;
|
||||
_projectRoots: Array<string>;
|
||||
_assetServer: AssetServer;
|
||||
_getTransformOptions: void | GetTransformOptions;
|
||||
|
@ -169,7 +169,7 @@ class Bundler {
|
|||
return transformCacheKey + getCacheKey(src, filename, options);
|
||||
};
|
||||
|
||||
this._resolver = new Resolver({
|
||||
this._resolverPromise = Resolver.load({
|
||||
assetExts: opts.assetExts,
|
||||
blacklistRE: opts.blacklistRE,
|
||||
cache: this._cache,
|
||||
|
@ -204,9 +204,9 @@ class Bundler {
|
|||
this._transformer.kill();
|
||||
return Promise.all([
|
||||
this._cache.end(),
|
||||
this.getResolver().getDependencyGraph().then(dependencyGraph => {
|
||||
dependencyGraph.getWatcher().end();
|
||||
}),
|
||||
this._resolverPromise.then(
|
||||
resolver => resolver.getDependencyGraph().getWatcher().end(),
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -215,15 +215,15 @@ class Bundler {
|
|||
minify: boolean,
|
||||
unbundle: boolean,
|
||||
sourceMapUrl: string,
|
||||
}) {
|
||||
}): Promise<Bundle> {
|
||||
const {dev, minify, unbundle} = options;
|
||||
const moduleSystemDeps =
|
||||
this._resolver.getModuleSystemDependencies({dev, unbundle});
|
||||
return this._bundle({
|
||||
return this._resolverPromise.then(
|
||||
resolver => resolver.getModuleSystemDependencies({dev, unbundle}),
|
||||
).then(moduleSystemDeps => this._bundle({
|
||||
...options,
|
||||
bundle: new Bundle({dev, minify, sourceMapUrl: options.sourceMapUrl}),
|
||||
moduleSystemDeps,
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
_sourceHMRURL(platform: ?string, hmrpath: string) {
|
||||
|
@ -338,11 +338,11 @@ class Bundler {
|
|||
response: ResolutionResponse,
|
||||
modulesByName: {[name: string]: Module},
|
||||
}) =>
|
||||
Promise.all(
|
||||
this._resolverPromise.then(resolver => Promise.all(
|
||||
transformedModules.map(({module, transformed}) =>
|
||||
finalBundle.addModule(this._resolver, response, module, transformed)
|
||||
finalBundle.addModule(resolver, response, module, transformed)
|
||||
)
|
||||
).then(() => {
|
||||
)).then(() => {
|
||||
const runBeforeMainModuleIds = Array.isArray(runBeforeMainModule)
|
||||
? runBeforeMainModule
|
||||
.map(name => modulesByName[name])
|
||||
|
@ -415,7 +415,9 @@ class Bundler {
|
|||
});
|
||||
}
|
||||
|
||||
return Promise.resolve(resolutionResponse).then(response => {
|
||||
return Promise.all(
|
||||
[this._resolverPromise, resolutionResponse],
|
||||
).then(([resolver, response]) => {
|
||||
bundle.setRamGroups(response.transformOptions.transform.ramGroups);
|
||||
|
||||
log(createActionEndEntry(transformingFilesLogEntry));
|
||||
|
@ -425,7 +427,7 @@ class Bundler {
|
|||
let entryFilePath;
|
||||
if (response.dependencies.length > 1) { // skip HMR requests
|
||||
const numModuleSystemDependencies =
|
||||
this._resolver.getModuleSystemDependencies({dev, unbundle}).length;
|
||||
resolver.getModuleSystemDependencies({dev, unbundle}).length;
|
||||
|
||||
const dependencyIndex =
|
||||
(response.numPrependedDependencies || 0) + numModuleSystemDependencies;
|
||||
|
@ -501,12 +503,14 @@ class Bundler {
|
|||
transform: transformSpecificOptions,
|
||||
};
|
||||
|
||||
return this._resolver.getShallowDependencies(entryFile, transformOptions);
|
||||
return this._resolverPromise.then(
|
||||
resolver => resolver.getShallowDependencies(entryFile, transformOptions),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
getModuleForPath(entryFile: string) {
|
||||
return this._resolver.getModuleForPath(entryFile);
|
||||
getModuleForPath(entryFile: string): Promise<Module> {
|
||||
return this._resolverPromise.then(resolver => resolver.getModuleForPath(entryFile));
|
||||
}
|
||||
|
||||
getDependencies({
|
||||
|
@ -547,13 +551,13 @@ class Bundler {
|
|||
transform: transformSpecificOptions,
|
||||
};
|
||||
|
||||
return this._resolver.getDependencies(
|
||||
return this._resolverPromise.then(resolver => resolver.getDependencies(
|
||||
entryFile,
|
||||
{dev, platform, recursive},
|
||||
transformOptions,
|
||||
onProgress,
|
||||
isolateModuleIDs ? createModuleIdFactory() : this._getModuleId,
|
||||
);
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -771,8 +775,8 @@ class Bundler {
|
|||
});
|
||||
}
|
||||
|
||||
getResolver() {
|
||||
return this._resolver;
|
||||
getResolver(): Promise<Resolver> {
|
||||
return this._resolverPromise;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -39,7 +39,9 @@ describe('Resolver', function() {
|
|||
return polyfill;
|
||||
});
|
||||
|
||||
DependencyGraph.load = jest.fn().mockImplementation(opts => Promise.resolve(new DependencyGraph(opts)));
|
||||
DependencyGraph.load = jest.fn().mockImplementation(
|
||||
opts => Promise.resolve(new DependencyGraph(opts)),
|
||||
);
|
||||
DependencyGraph.replacePatterns = require.requireActual('../../node-haste/lib/replacePatterns');
|
||||
DependencyGraph.prototype.createPolyfill = jest.fn();
|
||||
DependencyGraph.prototype.getDependencies = jest.fn();
|
||||
|
@ -101,8 +103,8 @@ describe('Resolver', function() {
|
|||
|
||||
DependencyGraph.prototype.getDependencies.mockImplementation(
|
||||
() => Promise.reject());
|
||||
return new Resolver({projectRoot: '/root'})
|
||||
.getDependencies(entry, {platform}, transformOptions)
|
||||
return Resolver.load({projectRoot: '/root'})
|
||||
.then(r => r.getDependencies(entry, {platform}, transformOptions))
|
||||
.catch(() => {
|
||||
expect(DependencyGraph.prototype.getDependencies).toBeCalledWith({
|
||||
entryPath: entry,
|
||||
|
@ -114,19 +116,23 @@ describe('Resolver', function() {
|
|||
});
|
||||
|
||||
it('passes custom platforms to the dependency graph', function() {
|
||||
new Resolver({ // eslint-disable-line no-new
|
||||
expect.assertions(1);
|
||||
return Resolver.load({ // eslint-disable-line no-new
|
||||
projectRoot: '/root',
|
||||
platforms: ['ios', 'windows', 'vr'],
|
||||
}).then(() => {
|
||||
const platforms = DependencyGraph.mock.calls[0][0].platforms;
|
||||
expect(Array.from(platforms)).toEqual(['ios', 'windows', 'vr']);
|
||||
});
|
||||
const platforms = DependencyGraph.mock.calls[0][0].platforms;
|
||||
expect(Array.from(platforms)).toEqual(['ios', 'windows', 'vr']);
|
||||
});
|
||||
|
||||
it('should get dependencies with polyfills', function() {
|
||||
expect.assertions(5);
|
||||
|
||||
var module = createModule('index');
|
||||
var deps = [module];
|
||||
|
||||
var depResolver = new Resolver({
|
||||
var depResolverPromise = Resolver.load({
|
||||
projectRoot: '/root',
|
||||
});
|
||||
|
||||
|
@ -144,14 +150,14 @@ describe('Resolver', function() {
|
|||
};
|
||||
DependencyGraph.prototype.createPolyfill.mockReturnValueOnce(polyfill);
|
||||
|
||||
return depResolver
|
||||
.getDependencies(
|
||||
return depResolverPromise
|
||||
.then(r => r.getDependencies(
|
||||
'/root/index.js',
|
||||
{dev: false},
|
||||
undefined,
|
||||
undefined,
|
||||
createGetModuleId()
|
||||
).then(function(result) {
|
||||
)).then(function(result) {
|
||||
expect(result.mainModuleId).toEqual('index');
|
||||
expect(result.dependencies[result.dependencies.length - 1]).toBe(module);
|
||||
|
||||
|
@ -256,10 +262,12 @@ describe('Resolver', function() {
|
|||
});
|
||||
|
||||
it('should pass in more polyfills', function() {
|
||||
expect.assertions(2);
|
||||
|
||||
var module = createModule('index');
|
||||
var deps = [module];
|
||||
|
||||
var depResolver = new Resolver({
|
||||
var depResolverPromise = Resolver.load({
|
||||
projectRoot: '/root',
|
||||
polyfillModuleNames: ['some module'],
|
||||
});
|
||||
|
@ -271,14 +279,14 @@ describe('Resolver', function() {
|
|||
}));
|
||||
});
|
||||
|
||||
return depResolver
|
||||
.getDependencies(
|
||||
return depResolverPromise
|
||||
.then(r => r.getDependencies(
|
||||
'/root/index.js',
|
||||
{dev: false},
|
||||
undefined,
|
||||
undefined,
|
||||
createGetModuleId()
|
||||
).then(result => {
|
||||
)).then(result => {
|
||||
expect(result.mainModuleId).toEqual('index');
|
||||
const calls =
|
||||
DependencyGraph.prototype.createPolyfill.mock.calls[result.dependencies.length - 2];
|
||||
|
@ -305,13 +313,14 @@ describe('Resolver', function() {
|
|||
describe('wrapModule', function() {
|
||||
let depResolver;
|
||||
beforeEach(() => {
|
||||
depResolver = new Resolver({
|
||||
depResolver,
|
||||
return Resolver.load({
|
||||
projectRoot: '/root',
|
||||
});
|
||||
}).then(r => { depResolver = r; });
|
||||
});
|
||||
|
||||
it('should resolve modules', function() {
|
||||
expect.assertions(1);
|
||||
|
||||
/*eslint-disable */
|
||||
var code = [
|
||||
// require
|
||||
|
@ -378,6 +387,8 @@ describe('Resolver', function() {
|
|||
});
|
||||
|
||||
it('should add module transport names as fourth argument to `__d`', () => {
|
||||
expect.assertions(1);
|
||||
|
||||
const module = createModule('test module');
|
||||
const code = 'arbitrary(code)'
|
||||
const resolutionResponse = new ResolutionResponseMock({
|
||||
|
@ -400,6 +411,7 @@ describe('Resolver', function() {
|
|||
});
|
||||
|
||||
it('should pass through passed-in source maps', () => {
|
||||
expect.assertions(1);
|
||||
const module = createModule('test module');
|
||||
const resolutionResponse = new ResolutionResponseMock({
|
||||
dependencies: [module],
|
||||
|
@ -416,23 +428,25 @@ describe('Resolver', function() {
|
|||
});
|
||||
|
||||
it('should resolve polyfills', function () {
|
||||
const depResolver = new Resolver({
|
||||
expect.assertions(1);
|
||||
return Resolver.load({
|
||||
projectRoot: '/root',
|
||||
});
|
||||
const polyfill = createPolyfill('test polyfill', []);
|
||||
const code = [
|
||||
'global.fetch = () => 1;',
|
||||
].join('');
|
||||
return depResolver.wrapModule({
|
||||
module: polyfill,
|
||||
code
|
||||
}).then(({code: processedCode}) => {
|
||||
expect(processedCode).toEqual([
|
||||
'(function(global) {',
|
||||
}).then(depResolver => {;
|
||||
const polyfill = createPolyfill('test polyfill', []);
|
||||
const code = [
|
||||
'global.fetch = () => 1;',
|
||||
'\n})' +
|
||||
"(typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : this);",
|
||||
].join(''));
|
||||
].join('');
|
||||
return depResolver.wrapModule({
|
||||
module: polyfill,
|
||||
code
|
||||
}).then(({code: processedCode}) => {
|
||||
expect(processedCode).toEqual([
|
||||
'(function(global) {',
|
||||
'global.fetch = () => 1;',
|
||||
'\n})' +
|
||||
"(typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : this);",
|
||||
].join(''));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -442,15 +456,18 @@ describe('Resolver', function() {
|
|||
let depResolver, module, resolutionResponse;
|
||||
|
||||
beforeEach(() => {
|
||||
depResolver = new Resolver({projectRoot: '/root'});
|
||||
module = createJsonModule(id);
|
||||
resolutionResponse = new ResolutionResponseMock({
|
||||
dependencies: [module],
|
||||
mainModuleId: id,
|
||||
return Resolver.load({projectRoot: '/root'}).then(r => {
|
||||
depResolver = r;
|
||||
module = createJsonModule(id);
|
||||
resolutionResponse = new ResolutionResponseMock({
|
||||
dependencies: [module],
|
||||
mainModuleId: id,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should prefix JSON files with `module.exports=`', () => {
|
||||
expect.assertions(1);
|
||||
return depResolver
|
||||
.wrapModule({resolutionResponse, module, name: id, code, dev: false})
|
||||
.then(({code: processedCode}) =>
|
||||
|
@ -469,10 +486,6 @@ describe('Resolver', function() {
|
|||
beforeEach(() => {
|
||||
minifyCode = jest.fn((filename, code, map) =>
|
||||
Promise.resolve({code, map}));
|
||||
depResolver = new Resolver({
|
||||
projectRoot: '/root',
|
||||
minifyCode,
|
||||
});
|
||||
module = createModule(id);
|
||||
module.path = '/arbitrary/path.js';
|
||||
resolutionResponse = new ResolutionResponseMock({
|
||||
|
@ -480,9 +493,14 @@ describe('Resolver', function() {
|
|||
mainModuleId: id,
|
||||
});
|
||||
sourceMap = {version: 3, sources: ['input'], mappings: 'whatever'};
|
||||
return Resolver.load({
|
||||
projectRoot: '/root',
|
||||
minifyCode,
|
||||
}).then(r => { depResolver = r; });
|
||||
});
|
||||
|
||||
it('should invoke the minifier with the wrapped code', () => {
|
||||
expect.assertions(1);
|
||||
const wrappedCode =
|
||||
`__d(/* ${id} */function(global, require, module, exports) {${
|
||||
code}\n}, ${resolutionResponse.getModuleId(module)});`
|
||||
|
@ -501,6 +519,7 @@ describe('Resolver', function() {
|
|||
});
|
||||
|
||||
it('should use minified code', () => {
|
||||
expect.assertions(2);
|
||||
const minifiedCode = 'minified(code)';
|
||||
const minifiedMap = {version: 3, file: ['minified']};
|
||||
minifyCode.mockReturnValue(Promise.resolve({code: minifiedCode, map: minifiedMap}));
|
||||
|
|
|
@ -50,13 +50,18 @@ type Options = {
|
|||
|
||||
class Resolver {
|
||||
|
||||
_depGraphPromise: Promise<DependencyGraph>;
|
||||
_depGraph: DependencyGraph;
|
||||
_minifyCode: MinifyCode;
|
||||
_polyfillModuleNames: Array<string>;
|
||||
|
||||
constructor(opts: Options) {
|
||||
this._depGraphPromise = DependencyGraph.load({
|
||||
constructor(opts: Options, depGraph: DependencyGraph) {
|
||||
this._minifyCode = opts.minifyCode;
|
||||
this._polyfillModuleNames = opts.polyfillModuleNames || [];
|
||||
this._depGraph = depGraph;
|
||||
}
|
||||
|
||||
static async load(opts: Options): Promise<Resolver> {
|
||||
const depGraph = await DependencyGraph.load({
|
||||
assetDependencies: ['react-native/Libraries/Image/AssetRegistry'],
|
||||
assetExts: opts.assetExts,
|
||||
cache: opts.cache,
|
||||
|
@ -86,19 +91,7 @@ class Resolver {
|
|||
useWatchman: true,
|
||||
watch: opts.watch || false,
|
||||
});
|
||||
|
||||
this._minifyCode = opts.minifyCode;
|
||||
this._polyfillModuleNames = opts.polyfillModuleNames || [];
|
||||
|
||||
this._depGraphPromise.then(
|
||||
depGraph => { this._depGraph = depGraph; },
|
||||
err => {
|
||||
console.error(err.message + '\n' + err.stack);
|
||||
// FIXME(jeanlauliac): we shall never exit the process by ourselves,
|
||||
// packager may be used in a server application or the like.
|
||||
process.exit(1);
|
||||
},
|
||||
);
|
||||
return new Resolver(opts, depGraph);
|
||||
}
|
||||
|
||||
getShallowDependencies(
|
||||
|
@ -120,13 +113,13 @@ class Resolver {
|
|||
getModuleId: mixed,
|
||||
): Promise<ResolutionResponse> {
|
||||
const {platform, recursive = true} = options;
|
||||
return this._depGraphPromise.then(depGraph => depGraph.getDependencies({
|
||||
return this._depGraph.getDependencies({
|
||||
entryPath,
|
||||
platform,
|
||||
transformOptions,
|
||||
recursive,
|
||||
onProgress,
|
||||
})).then(resolutionResponse => {
|
||||
}).then(resolutionResponse => {
|
||||
this._getPolyfillDependencies().reverse().forEach(
|
||||
polyfill => resolutionResponse.prependDependency(polyfill)
|
||||
);
|
||||
|
@ -252,8 +245,8 @@ class Resolver {
|
|||
return this._minifyCode(path, code, map);
|
||||
}
|
||||
|
||||
getDependencyGraph(): Promise<DependencyGraph> {
|
||||
return this._depGraphPromise;
|
||||
getDependencyGraph(): DependencyGraph {
|
||||
return this._depGraph;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -79,12 +79,12 @@ describe('processRequest', () => {
|
|||
|
||||
Bundler.prototype.invalidateFile = invalidatorFunc;
|
||||
Bundler.prototype.getResolver =
|
||||
jest.fn().mockReturnValue({
|
||||
getDependencyGraph: jest.fn().mockReturnValue(Promise.resolve({
|
||||
jest.fn().mockReturnValue(Promise.resolve({
|
||||
getDependencyGraph: jest.fn().mockReturnValue({
|
||||
getHasteMap: jest.fn().mockReturnValue({on: jest.fn()}),
|
||||
load: jest.fn(() => Promise.resolve()),
|
||||
})),
|
||||
});
|
||||
}),
|
||||
}));
|
||||
|
||||
server = new Server(options);
|
||||
requestHandler = server.processRequest.bind(server);
|
||||
|
|
|
@ -251,8 +251,8 @@ class Server {
|
|||
this._bundler = new Bundler(bundlerOpts);
|
||||
|
||||
// changes to the haste map can affect resolution of files in the bundle
|
||||
this._bundler.getResolver().getDependencyGraph().then(dependencyGraph => {
|
||||
dependencyGraph.getWatcher().on(
|
||||
this._bundler.getResolver().then(resolver => {
|
||||
resolver.getDependencyGraph().getWatcher().on(
|
||||
'change',
|
||||
({eventsQueue}) => eventsQueue.forEach(processFileChange),
|
||||
);
|
||||
|
@ -306,7 +306,7 @@ class Server {
|
|||
entryFile: string,
|
||||
platform?: string,
|
||||
}): Promise<Bundle> {
|
||||
return this._bundler.getResolver().getDependencyGraph().then(() => {
|
||||
return this._bundler.getResolver().then(() => {
|
||||
if (!options.platform) {
|
||||
options.platform = getPlatformExtension(options.entryFile);
|
||||
}
|
||||
|
@ -319,13 +319,14 @@ class Server {
|
|||
bundleDeps.set(bundle, {
|
||||
files: new Map(
|
||||
nonVirtual
|
||||
.map(({sourcePath, meta = {dependencies: []}}) =>
|
||||
[sourcePath, meta.dependencies])
|
||||
.map(({sourcePath, meta}) =>
|
||||
[sourcePath, meta != null ? meta.dependencies : []])
|
||||
),
|
||||
idToIndex: new Map(modules.map(({id}, i) => [id, i])),
|
||||
dependencyPairs: new Map(
|
||||
nonVirtual
|
||||
.filter(({meta}) => meta && meta.dependencyPairs)
|
||||
/* $FlowFixMe: the filter above ensures `dependencyPairs` is not null. */
|
||||
.map(m => [m.sourcePath, m.meta.dependencyPairs])
|
||||
),
|
||||
outdated: new Set(),
|
||||
|
@ -361,7 +362,7 @@ class Server {
|
|||
});
|
||||
}
|
||||
|
||||
getModuleForPath(entryFile: string): Module {
|
||||
getModuleForPath(entryFile: string): Promise<Module> {
|
||||
return this._bundler.getModuleForPath(entryFile);
|
||||
}
|
||||
|
||||
|
@ -602,8 +603,6 @@ class Server {
|
|||
|
||||
debug('Attempt to update existing bundle');
|
||||
|
||||
const changedModules =
|
||||
Array.from(outdated, this.getModuleForPath, this);
|
||||
// $FlowFixMe(>=0.37.0)
|
||||
deps.outdated = new Set();
|
||||
|
||||
|
@ -615,11 +614,14 @@ class Server {
|
|||
// specific response we can compute a non recursive one which
|
||||
// is the least we need and improve performance.
|
||||
const bundlePromise = this._bundles[optionsJson] =
|
||||
this.getDependencies({
|
||||
platform, dev, hot, minify,
|
||||
entryFile: options.entryFile,
|
||||
recursive: false,
|
||||
}).then(response => {
|
||||
Promise.all([
|
||||
this.getDependencies({
|
||||
platform, dev, hot, minify,
|
||||
entryFile: options.entryFile,
|
||||
recursive: false,
|
||||
}),
|
||||
Promise.all(Array.from(outdated, this.getModuleForPath, this)),
|
||||
]).then(([response, changedModules]) => {
|
||||
debug('Update bundle: rebuild shallow bundle');
|
||||
|
||||
changedModules.forEach(m => {
|
||||
|
@ -969,7 +971,7 @@ class Server {
|
|||
}
|
||||
}
|
||||
|
||||
function contentsEqual(array: Array<mixed>, set: Set<mixed>): boolean {
|
||||
function contentsEqual<T>(array: Array<T>, set: Set<T>): boolean {
|
||||
return array.length === set.size && array.every(set.has, set);
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ import type {MixedSourceMap} from './SourceMap';
|
|||
type SourceMapOrMappings = MixedSourceMap | Array<RawMapping>;
|
||||
|
||||
type Metadata = {
|
||||
dependencies?: ?Array<string>,
|
||||
dependencyPairs?: Array<[mixed, {path: string}]>,
|
||||
preloaded?: boolean,
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue