Pass cacheStores

Reviewed By: davidaurelio

Differential Revision: D7023425

fbshipit-source-id: 84d0d6585af4075bd7ac11ac3c97520caeae7b01
This commit is contained in:
Miguel Jimenez Esun 2018-02-23 03:49:06 -08:00 committed by Facebook Github Bot
parent eab7030b2e
commit 7486444a0a
9 changed files with 79 additions and 22 deletions

View File

@ -12,14 +12,14 @@
import type {CacheStore} from 'metro-cache';
class Cache {
_stores: $ReadOnlyArray<CacheStore>;
class Cache<T> {
_stores: $ReadOnlyArray<CacheStore<T>>;
constructor(stores: $ReadOnlyArray<CacheStore>) {
constructor(stores: $ReadOnlyArray<CacheStore<T>>) {
this._stores = stores;
}
async get(key: Buffer): Promise<mixed> {
async get(key: Buffer): Promise<?T> {
const stores = this._stores;
const length = stores.length;
@ -38,7 +38,7 @@ class Cache {
return null;
}
set(key: Buffer, value: mixed): void {
set(key: Buffer, value: T): void {
Promise.all(this._stores.map(store => store.set(key, value))).catch(err => {
process.nextTick(() => {
throw err;

View File

@ -52,6 +52,8 @@ describe('Cache', () => {
});
it('awaits for promises on stores, even if they return undefined', async () => {
jest.useFakeTimers();
let resolve;
const store1 = createStore();
@ -67,7 +69,9 @@ describe('Cache', () => {
expect(store2.get).not.toHaveBeenCalled();
resolve(undefined);
await promise;
jest.runAllTimers();
expect(store1.get).toHaveBeenCalledTimes(1);
expect(store2.get).toHaveBeenCalledTimes(1);

View File

@ -12,6 +12,9 @@
const Cache = require('./Cache');
const stableHash = require('./stableHash');
export type {CacheStore} from './types.flow';
module.exports.Cache = Cache;
module.exports.stableHash = stableHash;

View File

@ -10,7 +10,7 @@
'use strict';
export type CacheStore = {
get(key: Buffer): ?mixed | Promise<?mixed>,
set(key: Buffer, value: mixed): void | Promise<void>,
export type CacheStore<T> = {
get(key: Buffer): ?T | Promise<?T>,
set(key: Buffer, value: T): void | Promise<void>,
};

View File

@ -34,6 +34,7 @@ var commonOptions = {
allowBundleUpdates: false,
assetExts: defaults.assetExts,
assetRegistryPath: '/AssetRegistry.js',
cacheStores: [],
cacheVersion: 'smth',
enableBabelRCLookup: true,
extraNodeModules: {},

View File

@ -18,6 +18,7 @@ const defaults = require('../defaults');
const fs = require('fs');
const getTransformCacheKeyFn = require('../lib/getTransformCacheKeyFn');
const {Cache, stableHash} = require('metro-cache');
const {
toSegmentTuple,
fromRawMappings,
@ -25,12 +26,16 @@ const {
} = require('metro-source-map');
import type {PostProcessModules} from '../DeltaBundler';
import type {Options as JSTransformerOptions} from '../JSTransformer/worker';
import type {
Options as JSTransformerOptions,
TransformedCode,
} from '../JSTransformer/worker';
import type {DynamicRequiresBehavior} from '../ModuleGraph/worker/collectDependencies';
import type {GlobalTransformCache} from '../lib/GlobalTransformCache';
import type {TransformCache} from '../lib/TransformCaching';
import type {Reporter} from '../lib/reporting';
import type {BabelSourceMap} from '@babel/core';
import type {CacheStore} from 'metro-cache';
import type {
MetroSourceMapSegmentTuple,
MetroSourceMap,
@ -80,6 +85,7 @@ export type Options = {|
+assetRegistryPath: string,
+asyncRequireModulePath: string,
+blacklistRE?: RegExp,
+cacheStores: $ReadOnlyArray<CacheStore<TransformedCode>>,
+cacheVersion: string,
+dynamicDepsInPackages: DynamicRequiresBehavior,
+enableBabelRCLookup: boolean,
@ -108,16 +114,18 @@ export type Options = {|
class Bundler {
_opts: Options;
_cache: ?Cache<TransformedCode>;
_transformer: Transformer;
_depGraphPromise: Promise<DependencyGraph>;
_projectRoots: $ReadOnlyArray<string>;
_getTransformOptions: void | GetTransformOptions;
constructor(opts: Options) {
this._opts = opts;
opts.projectRoots.forEach(verifyRootExists);
this._opts = opts;
this._cache = opts.cacheStores.length ? new Cache(opts.cacheStores) : null;
this._transformer = new Transformer({
asyncRequireModulePath: opts.asyncRequireModulePath,
maxWorkers: opts.maxWorkers,
@ -157,16 +165,7 @@ class Bundler {
reporter: opts.reporter,
resetCache: opts.resetCache,
sourceExts: opts.sourceExts,
transformCode: (module, code, transformCodeOptions) =>
this._transformer.transform(
module.path,
module.localPath,
code,
module.isPolyfill(),
transformCodeOptions,
this._opts.assetExts,
this._opts.assetRegistryPath,
),
transformCode: this._cachedTransformCode.bind(this),
transformCache: opts.transformCache,
watch: opts.watch,
});
@ -276,6 +275,50 @@ class Bundler {
map: result.map ? toBabelSegments(result.map).map(toSegmentTuple) : [],
};
}
async _cachedTransformCode(
module,
code,
transformCodeOptions,
): Promise<TransformedCode> {
const cache = this._cache;
let result;
let key;
// First, try getting the result from the cache if enabled.
if (cache) {
key = stableHash([
module.localPath,
code,
transformCodeOptions,
this._opts.assetExts,
this._opts.assetRegistryPath,
this._opts.cacheVersion,
]);
result = await cache.get(key);
}
// Second, if there was no result, compute it ourselves.
if (!result) {
result = await this._transformer.transform(
module.path,
module.localPath,
code,
module.isPolyfill(),
transformCodeOptions,
this._opts.assetExts,
this._opts.assetRegistryPath,
);
}
// Third, propagate the result to all cache layers.
if (key && cache) {
cache.set(key, result);
}
return result;
}
}
function verifyRootExists(root) {

View File

@ -20,6 +20,7 @@ import type {
PostProcessBundleSourcemap,
} from './Bundler';
import type {PostProcessModules} from './DeltaBundler';
import type {TransformedCode} from './JSTransformer/worker';
import type {DynamicRequiresBehavior} from './ModuleGraph/worker/collectDependencies';
import type {IncomingMessage, ServerResponse} from 'http';
import type {CacheStore} from 'metro-cache';
@ -35,7 +36,7 @@ export type ConfigT = {
/**
* List of all store caches.
*/
cacheStores: Array<CacheStore>,
cacheStores: Array<CacheStore<TransformedCode>>,
/**
* Can be used to generate a key that will invalidate the whole metro cache

View File

@ -30,6 +30,7 @@ const defaults = require('../../defaults');
const bundlerOptions = {
allowBundleUpdates: false,
assetExts: defaults.assetExts,
cacheStores: [],
cacheVersion: 'smth',
enableBabelRCLookup: true,
extraNodeModules: {},

View File

@ -40,12 +40,14 @@ import type {
PostMinifyProcess,
PostProcessBundleSourcemap,
} from '../Bundler';
import type {CacheStore} from 'metro-cache';
import type {MetroSourceMap} from 'metro-source-map';
import type {TransformCache} from '../lib/TransformCaching';
import type {Symbolicate} from './symbolicate';
import type {AssetData} from '../Assets';
import type {RamBundleInfo} from '../DeltaBundler/Serializers';
import type {PostProcessModules} from '../DeltaBundler';
import type {TransformedCode} from '../JSTransformer/worker';
const {
Logger: {createActionStartEntry, createActionEndEntry, log},
} = require('metro-core');
@ -66,6 +68,7 @@ class Server {
_opts: {
assetExts: Array<string>,
blacklistRE: void | RegExp,
cacheStores: $ReadOnlyArray<CacheStore<TransformedCode>>,
cacheVersion: string,
createModuleIdFactory?: () => (path: string) => number,
enableBabelRCLookup: boolean,
@ -117,6 +120,7 @@ class Server {
assetExts: options.assetTransforms ? [] : assetExts,
assetRegistryPath: options.assetRegistryPath,
blacklistRE: options.blacklistRE,
cacheStores: options.cacheStores || [],
cacheVersion: options.cacheVersion,
dynamicDepsInPackages: options.dynamicDepsInPackages || 'throwAtRuntime',
createModuleIdFactory: options.createModuleIdFactory,