mirror of https://github.com/status-im/metro.git
packager: sync Module#read()
Reviewed By: davidaurelio Differential Revision: D4802783 fbshipit-source-id: c6309bcae6ad48bea2350de04353f694be6eea2f
This commit is contained in:
parent
b9bfe3b85d
commit
87c7e781a2
|
@ -37,14 +37,14 @@ class AssetModule extends Module {
|
||||||
return Promise.resolve(false);
|
return Promise.resolve(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
getDependencies() {
|
readCached(): ReadResult {
|
||||||
return Promise.resolve(this._dependencies);
|
|
||||||
}
|
|
||||||
|
|
||||||
read(): Promise<ReadResult> {
|
|
||||||
/** $FlowFixMe: improper OOP design. AssetModule, being different from a
|
/** $FlowFixMe: improper OOP design. AssetModule, being different from a
|
||||||
* normal Module, shouldn't inherit it in the first place. */
|
* normal Module, shouldn't inherit it in the first place. */
|
||||||
return Promise.resolve({});
|
return {dependencies: this._dependencies};
|
||||||
|
}
|
||||||
|
|
||||||
|
readFresh(): Promise<ReadResult> {
|
||||||
|
return Promise.resolve(this.readCached());
|
||||||
}
|
}
|
||||||
|
|
||||||
getName() {
|
getName() {
|
||||||
|
|
|
@ -141,6 +141,11 @@ class ResolutionRequest {
|
||||||
return cacheResult(this._resolveNodeDependency(fromModule, toModuleName));
|
return cacheResult(this._resolveNodeDependency(fromModule, toModuleName));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resolveModuleDependencies(module: Module, dependencyNames: Array<string>): [Array<string>, Array<Module>] {
|
||||||
|
const dependencies = dependencyNames.map(name => this.resolveDependency(module, name));
|
||||||
|
return [dependencyNames, dependencies];
|
||||||
|
}
|
||||||
|
|
||||||
getOrderedDependencies({
|
getOrderedDependencies({
|
||||||
response,
|
response,
|
||||||
transformOptions,
|
transformOptions,
|
||||||
|
@ -158,11 +163,13 @@ class ResolutionRequest {
|
||||||
let totalModules = 1;
|
let totalModules = 1;
|
||||||
let finishedModules = 0;
|
let finishedModules = 0;
|
||||||
|
|
||||||
const resolveDependencies = module =>
|
const resolveDependencies = module => Promise.resolve().then(() => {
|
||||||
module.getDependencies(transformOptions)
|
const result = module.readCached(transformOptions);
|
||||||
.then(dependencyNames => {
|
if (result != null) {
|
||||||
const dependencies = dependencyNames.map(name => this.resolveDependency(module, name));
|
return this.resolveModuleDependencies(module, result.dependencies);
|
||||||
return [dependencyNames, dependencies];
|
}
|
||||||
|
return module.read(transformOptions)
|
||||||
|
.then(({dependencies}) => this.resolveModuleDependencies(module, dependencies));
|
||||||
});
|
});
|
||||||
|
|
||||||
const collectedDependencies = new MapWithDefaults(module => collect(module));
|
const collectedDependencies = new MapWithDefaults(module => collect(module));
|
||||||
|
|
|
@ -95,6 +95,8 @@ class Module {
|
||||||
_sourceCode: ?string;
|
_sourceCode: ?string;
|
||||||
_readPromises: Map<string, Promise<ReadResult>>;
|
_readPromises: Map<string, Promise<ReadResult>>;
|
||||||
|
|
||||||
|
_readResultsByOptionsKey: Map<string, ?ReadResult>;
|
||||||
|
|
||||||
constructor({
|
constructor({
|
||||||
cache,
|
cache,
|
||||||
depGraphHelpers,
|
depGraphHelpers,
|
||||||
|
@ -123,6 +125,7 @@ class Module {
|
||||||
this._globalCache = globalTransformCache;
|
this._globalCache = globalTransformCache;
|
||||||
|
|
||||||
this._readPromises = new Map();
|
this._readPromises = new Map();
|
||||||
|
this._readResultsByOptionsKey = new Map();
|
||||||
}
|
}
|
||||||
|
|
||||||
isHaste(): Promise<boolean> {
|
isHaste(): Promise<boolean> {
|
||||||
|
@ -186,6 +189,7 @@ class Module {
|
||||||
invalidate() {
|
invalidate() {
|
||||||
this._cache.invalidate(this.path);
|
this._cache.invalidate(this.path);
|
||||||
this._readPromises.clear();
|
this._readPromises.clear();
|
||||||
|
this._readResultsByOptionsKey.clear();
|
||||||
this._sourceCode = null;
|
this._sourceCode = null;
|
||||||
this._docBlock = null;
|
this._docBlock = null;
|
||||||
this._hasteNameCache = null;
|
this._hasteNameCache = null;
|
||||||
|
@ -250,10 +254,9 @@ class Module {
|
||||||
*/
|
*/
|
||||||
_finalizeReadResult(
|
_finalizeReadResult(
|
||||||
source: string,
|
source: string,
|
||||||
id: ?string,
|
|
||||||
extern: boolean,
|
|
||||||
result: TransformedCode,
|
result: TransformedCode,
|
||||||
): ReadResult {
|
): ReadResult {
|
||||||
|
const id = this._getHasteName();
|
||||||
if (this._options.cacheTransformResults === false) {
|
if (this._options.cacheTransformResults === false) {
|
||||||
const {dependencies} = result;
|
const {dependencies} = result;
|
||||||
/* $FlowFixMe: this code path is dead, remove. */
|
/* $FlowFixMe: this code path is dead, remove. */
|
||||||
|
@ -334,41 +337,61 @@ class Module {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read everything about a module: source code, transformed code,
|
* Shorthand for reading both from cache or from fresh for all call sites that
|
||||||
* dependencies, etc. The overall process is to read the cache first, and if
|
* are asynchronous by default.
|
||||||
* it's a miss, we let the worker write to the cache and read it again.
|
|
||||||
*/
|
*/
|
||||||
read(transformOptions: TransformOptions): Promise<ReadResult> {
|
read(transformOptions: TransformOptions): Promise<ReadResult> {
|
||||||
|
return Promise.resolve().then(() => {
|
||||||
|
const cached = this.readCached(transformOptions);
|
||||||
|
if (cached != null) {
|
||||||
|
return cached;
|
||||||
|
}
|
||||||
|
return this.readFresh(transformOptions);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as `readFresh`, but reads from the cache instead of transforming
|
||||||
|
* the file from source. This has the benefit of being synchronous. As a
|
||||||
|
* result it is possible to read many cached Module in a row, synchronously.
|
||||||
|
*/
|
||||||
|
readCached(transformOptions: TransformOptions): ?ReadResult {
|
||||||
|
const key = stableObjectHash(transformOptions || {});
|
||||||
|
if (this._readResultsByOptionsKey.has(key)) {
|
||||||
|
return this._readResultsByOptionsKey.get(key);
|
||||||
|
}
|
||||||
|
const result = this._readFromTransformCache(transformOptions);
|
||||||
|
this._readResultsByOptionsKey.set(key, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read again from the TransformCache, on disk. `readCached` should be favored
|
||||||
|
* so it's faster in case the results are already in memory.
|
||||||
|
*/
|
||||||
|
_readFromTransformCache(transformOptions: TransformOptions): ?ReadResult {
|
||||||
|
const cacheProps = this._getCacheProps(transformOptions);
|
||||||
|
const cachedResult = TransformCache.readSync(cacheProps);
|
||||||
|
if (cachedResult) {
|
||||||
|
return this._finalizeReadResult(cacheProps.sourceCode, cachedResult);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gathers relevant data about a module: source code, transformed code,
|
||||||
|
* dependencies, etc. This function reads and transforms the source from
|
||||||
|
* scratch. We don't repeat the same work as `readCached` because we assume
|
||||||
|
* call sites have called it already.
|
||||||
|
*/
|
||||||
|
readFresh(transformOptions: TransformOptions): Promise<ReadResult> {
|
||||||
const key = stableObjectHash(transformOptions || {});
|
const key = stableObjectHash(transformOptions || {});
|
||||||
const promise = this._readPromises.get(key);
|
const promise = this._readPromises.get(key);
|
||||||
if (promise != null) {
|
if (promise != null) {
|
||||||
return promise;
|
return promise;
|
||||||
}
|
}
|
||||||
const freshPromise = Promise.resolve().then(() => {
|
const freshPromise = Promise.resolve().then(() => {
|
||||||
const sourceCode = this._readSourceCode();
|
const cacheProps = this._getCacheProps(transformOptions);
|
||||||
const moduleDocBlock = this._readDocBlock();
|
|
||||||
const id = this._getHasteName();
|
|
||||||
// Ignore requires in JSON files or generated code. An example of this
|
|
||||||
// is prebuilt files like the SourceMap library.
|
|
||||||
const extern = this.isJSON() || 'extern' in moduleDocBlock;
|
|
||||||
if (extern) {
|
|
||||||
transformOptions = {...transformOptions, extern};
|
|
||||||
}
|
|
||||||
const getTransformCacheKey = this._getTransformCacheKey;
|
|
||||||
const cacheProps = {
|
|
||||||
filePath: this.path,
|
|
||||||
sourceCode,
|
|
||||||
getTransformCacheKey,
|
|
||||||
transformOptions,
|
|
||||||
cacheOptions: {
|
|
||||||
resetCache: this._options.resetCache,
|
|
||||||
reporter: this._reporter,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const cachedResult = TransformCache.readSync(cacheProps);
|
|
||||||
if (cachedResult) {
|
|
||||||
return Promise.resolve(this._finalizeReadResult(sourceCode, id, extern, cachedResult));
|
|
||||||
}
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
this._getAndCacheTransformedCode(
|
this._getAndCacheTransformedCode(
|
||||||
cacheProps,
|
cacheProps,
|
||||||
|
@ -378,15 +401,40 @@ class Module {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
invariant(freshResult != null, 'inconsistent state');
|
invariant(freshResult != null, 'inconsistent state');
|
||||||
resolve(this._finalizeReadResult(sourceCode, id, extern, freshResult));
|
resolve(this._finalizeReadResult(cacheProps.sourceCode, freshResult));
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
}).then(result => {
|
||||||
|
this._readResultsByOptionsKey.set(key, result);
|
||||||
|
return result;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
this._readPromises.set(key, freshPromise);
|
this._readPromises.set(key, freshPromise);
|
||||||
return freshPromise;
|
return freshPromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_getCacheProps(transformOptions: TransformOptions) {
|
||||||
|
const sourceCode = this._readSourceCode();
|
||||||
|
const moduleDocBlock = this._readDocBlock();
|
||||||
|
const getTransformCacheKey = this._getTransformCacheKey;
|
||||||
|
// Ignore requires in JSON files or generated code. An example of this
|
||||||
|
// is prebuilt files like the SourceMap library.
|
||||||
|
const extern = this.isJSON() || 'extern' in moduleDocBlock;
|
||||||
|
if (extern) {
|
||||||
|
transformOptions = {...transformOptions, extern};
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
filePath: this.path,
|
||||||
|
sourceCode,
|
||||||
|
getTransformCacheKey,
|
||||||
|
transformOptions,
|
||||||
|
cacheOptions: {
|
||||||
|
resetCache: this._options.resetCache,
|
||||||
|
reporter: this._reporter,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
hash() {
|
hash() {
|
||||||
return `Module : ${this.path}`;
|
return `Module : ${this.path}`;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue