Add an "experimentalCaches" flag all the way down to Module

Reviewed By: jeanlauliac

Differential Revision: D6976974

fbshipit-source-id: fea0a3655fec924798567d690e2ee4f24465d5c5
This commit is contained in:
Miguel Jimenez Esun 2018-02-23 03:49:07 -08:00 committed by Facebook Github Bot
parent 7486444a0a
commit bd91fcf131
5 changed files with 94 additions and 18 deletions

View File

@ -145,6 +145,8 @@ class Bundler {
assetExts: opts.assetExts,
assetRegistryPath: opts.assetRegistryPath,
blacklistRE: opts.blacklistRE,
// TODO: T26134860 Only use experimental caches if stores are provided.
experimentalCaches: !!opts.cacheStores.length,
extraNodeModules: opts.extraNodeModules,
getPolyfills: opts.getPolyfills,
getTransformCacheKey: getTransformCacheKeyFn({

View File

@ -47,6 +47,7 @@ type Options = {|
+assetExts: Array<string>,
+assetRegistryPath: string,
+blacklistRE?: RegExp,
+experimentalCaches: boolean,
+extraNodeModules: ?{},
+getPolyfills: ({platform: ?string}) => $ReadOnlyArray<string>,
+getTransformCacheKey: GetTransformCacheKey,
@ -202,6 +203,7 @@ class DependencyGraph extends EventEmitter {
{
assetDependencies: [_opts.assetRegistryPath],
depGraphHelpers: this._helpers,
experimentalCaches: _opts.experimentalCaches,
getClosestPackage: this._getClosestPackage.bind(this),
getTransformCacheKey: _opts.getTransformCacheKey,
globalTransformCache: _opts.globalTransformCache,

View File

@ -16,8 +16,7 @@ const fs = require('fs');
const invariant = require('fbjs/lib/invariant');
const isAbsolutePath = require('absolute-path');
const jsonStableStringify = require('json-stable-stringify');
const {join: joinPath, relative: relativePath} = require('path');
const path = require('path');
import type {
TransformedCode,
@ -70,12 +69,13 @@ export type Options = {
export type ConstructorArgs = {
depGraphHelpers: DependencyGraphHelpers,
experimentalCaches: boolean,
file: string,
getTransformCacheKey: GetTransformCacheKey,
localPath: LocalPath,
moduleCache: ModuleCache,
options: Options,
transformCode: ?TransformCode,
transformCode: TransformCode,
};
type DocBlock = {+[key: string]: string};
@ -85,8 +85,10 @@ class Module {
path: string;
type: string;
_experimentalCaches: boolean;
_moduleCache: ModuleCache;
_transformCode: ?TransformCode;
_transformCode: TransformCode;
_getTransformCacheKey: GetTransformCacheKey;
_depGraphHelpers: DependencyGraphHelpers;
_options: Options;
@ -100,9 +102,10 @@ class Module {
constructor({
depGraphHelpers,
localPath,
experimentalCaches,
file,
getTransformCacheKey,
localPath,
moduleCache,
options,
transformCode,
@ -115,6 +118,8 @@ class Module {
this.path = file;
this.type = 'Module';
this._experimentalCaches = experimentalCaches;
this._moduleCache = moduleCache;
this._transformCode = transformCode;
this._getTransformCacheKey = getTransformCacheKey;
@ -138,6 +143,12 @@ class Module {
}
getName(): string {
// TODO: T26134860 Used for debugging purposes only; disabled with the new
// caches.
if (this._experimentalCaches) {
return path.basename(this.path);
}
if (this.isHaste()) {
const name = this._getHasteName();
if (name != null) {
@ -157,10 +168,9 @@ class Module {
return this.path;
}
return joinPath(packageName, relativePath(p.root, this.path)).replace(
/\\/g,
'/',
);
return path
.join(packageName, path.relative(p.root, this.path))
.replace(/\\/g, '/');
}
getPackage() {
@ -177,9 +187,16 @@ class Module {
* code.
*/
invalidate() {
this._sourceCode = null;
// TODO: T26134860 Caches present in Module are not used with experimental
// caches, except for the one related to source code.
if (this._experimentalCaches) {
return;
}
this._readPromises.clear();
this._readResultsByOptionsKey.clear();
this._sourceCode = null;
this._docBlock = null;
this._hasteNameCache = null;
}
@ -295,15 +312,24 @@ class Module {
* Shorthand for reading both from cache or from fresh for all call sites that
* are asynchronous by default.
*/
read(transformOptions: WorkerOptions): Promise<ReadResult> {
return Promise.resolve().then(() => {
const cached = this.readCached(transformOptions);
async read(transformOptions: WorkerOptions): Promise<ReadResult> {
// TODO: T26134860 Cache layer lives inside the transformer now; just call
// the transform method.
if (this._experimentalCaches) {
const sourceCode = this._readSourceCode();
if (cached != null) {
return cached;
}
return this.readFresh(transformOptions);
});
return {
...(await this._transformCode(this, sourceCode, transformOptions)),
sourceCode,
};
}
const cached = this.readCached(transformOptions);
if (cached != null) {
return cached;
}
return this.readFresh(transformOptions);
}
/**

View File

@ -31,6 +31,7 @@ type GetClosestPackageFn = (filePath: string) => ?string;
type Options = {|
assetDependencies: Array<string>,
depGraphHelpers: DependencyGraphHelpers,
experimentalCaches: boolean,
hasteImplModulePath?: string,
getClosestPackage: GetClosestPackageFn,
getTransformCacheKey: GetTransformCacheKey,
@ -45,6 +46,7 @@ type Options = {|
class ModuleCache {
_assetDependencies: Array<string>;
_depGraphHelpers: DependencyGraphHelpers;
_experimentalCaches: boolean;
_getClosestPackage: GetClosestPackageFn;
_getTransformCacheKey: GetTransformCacheKey;
_globalTransformCache: ?GlobalTransformCache;
@ -61,6 +63,7 @@ class ModuleCache {
const {
assetDependencies,
depGraphHelpers,
experimentalCaches,
getClosestPackage,
getTransformCacheKey,
globalTransformCache,
@ -70,6 +73,7 @@ class ModuleCache {
} = options;
this._opts = options;
this._assetDependencies = assetDependencies;
this._experimentalCaches = experimentalCaches;
this._getClosestPackage = getClosestPackage;
this._getTransformCacheKey = getTransformCacheKey;
this._globalTransformCache = globalTransformCache;
@ -87,6 +91,7 @@ class ModuleCache {
if (!this._moduleCache[filePath]) {
this._moduleCache[filePath] = new Module({
depGraphHelpers: this._depGraphHelpers,
experimentalCaches: this._experimentalCaches,
file: filePath,
getTransformCacheKey: this._getTransformCacheKey,
localPath: toLocalPath(this._roots, filePath),
@ -110,6 +115,7 @@ class ModuleCache {
*/
this._moduleCache[filePath] = new AssetModule({
depGraphHelpers: this._depGraphHelpers,
experimentalCaches: this._experimentalCaches,
file: filePath,
getTransformCacheKey: this._getTransformCacheKey,
globalTransformCache: this._globalTransformCache,

View File

@ -85,6 +85,46 @@ describe('Module', () => {
transformCache.mock.reset();
});
describe('Experimental caches', () => {
it('Calls into the transformer directly when having experimental caches on', async () => {
const transformCode = jest.fn().mockReturnValue({
code: 'code',
dependencies: ['dep1', 'dep2'],
map: [],
});
const module = new Module({
cache,
experimentalCaches: true,
depGraphHelpers: new DependencyGraphHelpers(),
file: fileName,
getTransformCacheKey: () => transformCacheKey,
localPath: fileName,
moduleCache: new ModuleCache({cache}),
options: {transformCache},
transformCode,
});
mockIndexFile('originalCode');
jest.spyOn(fs, 'readFileSync');
// Read the first time, transform code is called.
const res1 = await module.read({foo: 3});
expect(res1.code).toBe('code');
expect(res1.dependencies).toEqual(['dep1', 'dep2']);
expect(transformCode).toHaveBeenCalledTimes(1);
// Read a second time, transformCode is called again!
const res2 = await module.read({foo: 3});
expect(res2.code).toBe('code');
expect(res2.dependencies).toEqual(['dep1', 'dep2']);
expect(transformCode).toHaveBeenCalledTimes(2);
// Code was only read once, though.
expect(fs.readFileSync).toHaveBeenCalledTimes(1);
});
});
describe('Module ID', () => {
const moduleId = 'arbitraryModule';
const source = `/**