mirror of https://github.com/status-im/metro.git
Pass cacheStores
Reviewed By: davidaurelio Differential Revision: D7023425 fbshipit-source-id: 84d0d6585af4075bd7ac11ac3c97520caeae7b01
This commit is contained in:
parent
eab7030b2e
commit
7486444a0a
|
@ -12,14 +12,14 @@
|
||||||
|
|
||||||
import type {CacheStore} from 'metro-cache';
|
import type {CacheStore} from 'metro-cache';
|
||||||
|
|
||||||
class Cache {
|
class Cache<T> {
|
||||||
_stores: $ReadOnlyArray<CacheStore>;
|
_stores: $ReadOnlyArray<CacheStore<T>>;
|
||||||
|
|
||||||
constructor(stores: $ReadOnlyArray<CacheStore>) {
|
constructor(stores: $ReadOnlyArray<CacheStore<T>>) {
|
||||||
this._stores = stores;
|
this._stores = stores;
|
||||||
}
|
}
|
||||||
|
|
||||||
async get(key: Buffer): Promise<mixed> {
|
async get(key: Buffer): Promise<?T> {
|
||||||
const stores = this._stores;
|
const stores = this._stores;
|
||||||
const length = stores.length;
|
const length = stores.length;
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ class Cache {
|
||||||
return null;
|
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 => {
|
Promise.all(this._stores.map(store => store.set(key, value))).catch(err => {
|
||||||
process.nextTick(() => {
|
process.nextTick(() => {
|
||||||
throw err;
|
throw err;
|
||||||
|
|
|
@ -52,6 +52,8 @@ describe('Cache', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('awaits for promises on stores, even if they return undefined', async () => {
|
it('awaits for promises on stores, even if they return undefined', async () => {
|
||||||
|
jest.useFakeTimers();
|
||||||
|
|
||||||
let resolve;
|
let resolve;
|
||||||
|
|
||||||
const store1 = createStore();
|
const store1 = createStore();
|
||||||
|
@ -67,7 +69,9 @@ describe('Cache', () => {
|
||||||
expect(store2.get).not.toHaveBeenCalled();
|
expect(store2.get).not.toHaveBeenCalled();
|
||||||
|
|
||||||
resolve(undefined);
|
resolve(undefined);
|
||||||
|
|
||||||
await promise;
|
await promise;
|
||||||
|
jest.runAllTimers();
|
||||||
|
|
||||||
expect(store1.get).toHaveBeenCalledTimes(1);
|
expect(store1.get).toHaveBeenCalledTimes(1);
|
||||||
expect(store2.get).toHaveBeenCalledTimes(1);
|
expect(store2.get).toHaveBeenCalledTimes(1);
|
||||||
|
|
|
@ -12,6 +12,9 @@
|
||||||
|
|
||||||
const Cache = require('./Cache');
|
const Cache = require('./Cache');
|
||||||
|
|
||||||
|
const stableHash = require('./stableHash');
|
||||||
|
|
||||||
export type {CacheStore} from './types.flow';
|
export type {CacheStore} from './types.flow';
|
||||||
|
|
||||||
module.exports.Cache = Cache;
|
module.exports.Cache = Cache;
|
||||||
|
module.exports.stableHash = stableHash;
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
export type CacheStore = {
|
export type CacheStore<T> = {
|
||||||
get(key: Buffer): ?mixed | Promise<?mixed>,
|
get(key: Buffer): ?T | Promise<?T>,
|
||||||
set(key: Buffer, value: mixed): void | Promise<void>,
|
set(key: Buffer, value: T): void | Promise<void>,
|
||||||
};
|
};
|
||||||
|
|
|
@ -34,6 +34,7 @@ var commonOptions = {
|
||||||
allowBundleUpdates: false,
|
allowBundleUpdates: false,
|
||||||
assetExts: defaults.assetExts,
|
assetExts: defaults.assetExts,
|
||||||
assetRegistryPath: '/AssetRegistry.js',
|
assetRegistryPath: '/AssetRegistry.js',
|
||||||
|
cacheStores: [],
|
||||||
cacheVersion: 'smth',
|
cacheVersion: 'smth',
|
||||||
enableBabelRCLookup: true,
|
enableBabelRCLookup: true,
|
||||||
extraNodeModules: {},
|
extraNodeModules: {},
|
||||||
|
|
|
@ -18,6 +18,7 @@ const defaults = require('../defaults');
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const getTransformCacheKeyFn = require('../lib/getTransformCacheKeyFn');
|
const getTransformCacheKeyFn = require('../lib/getTransformCacheKeyFn');
|
||||||
|
|
||||||
|
const {Cache, stableHash} = require('metro-cache');
|
||||||
const {
|
const {
|
||||||
toSegmentTuple,
|
toSegmentTuple,
|
||||||
fromRawMappings,
|
fromRawMappings,
|
||||||
|
@ -25,12 +26,16 @@ const {
|
||||||
} = require('metro-source-map');
|
} = require('metro-source-map');
|
||||||
|
|
||||||
import type {PostProcessModules} from '../DeltaBundler';
|
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 {DynamicRequiresBehavior} from '../ModuleGraph/worker/collectDependencies';
|
||||||
import type {GlobalTransformCache} from '../lib/GlobalTransformCache';
|
import type {GlobalTransformCache} from '../lib/GlobalTransformCache';
|
||||||
import type {TransformCache} from '../lib/TransformCaching';
|
import type {TransformCache} from '../lib/TransformCaching';
|
||||||
import type {Reporter} from '../lib/reporting';
|
import type {Reporter} from '../lib/reporting';
|
||||||
import type {BabelSourceMap} from '@babel/core';
|
import type {BabelSourceMap} from '@babel/core';
|
||||||
|
import type {CacheStore} from 'metro-cache';
|
||||||
import type {
|
import type {
|
||||||
MetroSourceMapSegmentTuple,
|
MetroSourceMapSegmentTuple,
|
||||||
MetroSourceMap,
|
MetroSourceMap,
|
||||||
|
@ -80,6 +85,7 @@ export type Options = {|
|
||||||
+assetRegistryPath: string,
|
+assetRegistryPath: string,
|
||||||
+asyncRequireModulePath: string,
|
+asyncRequireModulePath: string,
|
||||||
+blacklistRE?: RegExp,
|
+blacklistRE?: RegExp,
|
||||||
|
+cacheStores: $ReadOnlyArray<CacheStore<TransformedCode>>,
|
||||||
+cacheVersion: string,
|
+cacheVersion: string,
|
||||||
+dynamicDepsInPackages: DynamicRequiresBehavior,
|
+dynamicDepsInPackages: DynamicRequiresBehavior,
|
||||||
+enableBabelRCLookup: boolean,
|
+enableBabelRCLookup: boolean,
|
||||||
|
@ -108,16 +114,18 @@ export type Options = {|
|
||||||
|
|
||||||
class Bundler {
|
class Bundler {
|
||||||
_opts: Options;
|
_opts: Options;
|
||||||
|
_cache: ?Cache<TransformedCode>;
|
||||||
_transformer: Transformer;
|
_transformer: Transformer;
|
||||||
_depGraphPromise: Promise<DependencyGraph>;
|
_depGraphPromise: Promise<DependencyGraph>;
|
||||||
_projectRoots: $ReadOnlyArray<string>;
|
_projectRoots: $ReadOnlyArray<string>;
|
||||||
_getTransformOptions: void | GetTransformOptions;
|
_getTransformOptions: void | GetTransformOptions;
|
||||||
|
|
||||||
constructor(opts: Options) {
|
constructor(opts: Options) {
|
||||||
this._opts = opts;
|
|
||||||
|
|
||||||
opts.projectRoots.forEach(verifyRootExists);
|
opts.projectRoots.forEach(verifyRootExists);
|
||||||
|
|
||||||
|
this._opts = opts;
|
||||||
|
this._cache = opts.cacheStores.length ? new Cache(opts.cacheStores) : null;
|
||||||
|
|
||||||
this._transformer = new Transformer({
|
this._transformer = new Transformer({
|
||||||
asyncRequireModulePath: opts.asyncRequireModulePath,
|
asyncRequireModulePath: opts.asyncRequireModulePath,
|
||||||
maxWorkers: opts.maxWorkers,
|
maxWorkers: opts.maxWorkers,
|
||||||
|
@ -157,16 +165,7 @@ class Bundler {
|
||||||
reporter: opts.reporter,
|
reporter: opts.reporter,
|
||||||
resetCache: opts.resetCache,
|
resetCache: opts.resetCache,
|
||||||
sourceExts: opts.sourceExts,
|
sourceExts: opts.sourceExts,
|
||||||
transformCode: (module, code, transformCodeOptions) =>
|
transformCode: this._cachedTransformCode.bind(this),
|
||||||
this._transformer.transform(
|
|
||||||
module.path,
|
|
||||||
module.localPath,
|
|
||||||
code,
|
|
||||||
module.isPolyfill(),
|
|
||||||
transformCodeOptions,
|
|
||||||
this._opts.assetExts,
|
|
||||||
this._opts.assetRegistryPath,
|
|
||||||
),
|
|
||||||
transformCache: opts.transformCache,
|
transformCache: opts.transformCache,
|
||||||
watch: opts.watch,
|
watch: opts.watch,
|
||||||
});
|
});
|
||||||
|
@ -276,6 +275,50 @@ class Bundler {
|
||||||
map: result.map ? toBabelSegments(result.map).map(toSegmentTuple) : [],
|
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) {
|
function verifyRootExists(root) {
|
||||||
|
|
|
@ -20,6 +20,7 @@ import type {
|
||||||
PostProcessBundleSourcemap,
|
PostProcessBundleSourcemap,
|
||||||
} from './Bundler';
|
} from './Bundler';
|
||||||
import type {PostProcessModules} from './DeltaBundler';
|
import type {PostProcessModules} from './DeltaBundler';
|
||||||
|
import type {TransformedCode} from './JSTransformer/worker';
|
||||||
import type {DynamicRequiresBehavior} from './ModuleGraph/worker/collectDependencies';
|
import type {DynamicRequiresBehavior} from './ModuleGraph/worker/collectDependencies';
|
||||||
import type {IncomingMessage, ServerResponse} from 'http';
|
import type {IncomingMessage, ServerResponse} from 'http';
|
||||||
import type {CacheStore} from 'metro-cache';
|
import type {CacheStore} from 'metro-cache';
|
||||||
|
@ -35,7 +36,7 @@ export type ConfigT = {
|
||||||
/**
|
/**
|
||||||
* List of all store caches.
|
* 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
|
* Can be used to generate a key that will invalidate the whole metro cache
|
||||||
|
|
|
@ -30,6 +30,7 @@ const defaults = require('../../defaults');
|
||||||
const bundlerOptions = {
|
const bundlerOptions = {
|
||||||
allowBundleUpdates: false,
|
allowBundleUpdates: false,
|
||||||
assetExts: defaults.assetExts,
|
assetExts: defaults.assetExts,
|
||||||
|
cacheStores: [],
|
||||||
cacheVersion: 'smth',
|
cacheVersion: 'smth',
|
||||||
enableBabelRCLookup: true,
|
enableBabelRCLookup: true,
|
||||||
extraNodeModules: {},
|
extraNodeModules: {},
|
||||||
|
|
|
@ -40,12 +40,14 @@ import type {
|
||||||
PostMinifyProcess,
|
PostMinifyProcess,
|
||||||
PostProcessBundleSourcemap,
|
PostProcessBundleSourcemap,
|
||||||
} from '../Bundler';
|
} from '../Bundler';
|
||||||
|
import type {CacheStore} from 'metro-cache';
|
||||||
import type {MetroSourceMap} from 'metro-source-map';
|
import type {MetroSourceMap} from 'metro-source-map';
|
||||||
import type {TransformCache} from '../lib/TransformCaching';
|
import type {TransformCache} from '../lib/TransformCaching';
|
||||||
import type {Symbolicate} from './symbolicate';
|
import type {Symbolicate} from './symbolicate';
|
||||||
import type {AssetData} from '../Assets';
|
import type {AssetData} from '../Assets';
|
||||||
import type {RamBundleInfo} from '../DeltaBundler/Serializers';
|
import type {RamBundleInfo} from '../DeltaBundler/Serializers';
|
||||||
import type {PostProcessModules} from '../DeltaBundler';
|
import type {PostProcessModules} from '../DeltaBundler';
|
||||||
|
import type {TransformedCode} from '../JSTransformer/worker';
|
||||||
const {
|
const {
|
||||||
Logger: {createActionStartEntry, createActionEndEntry, log},
|
Logger: {createActionStartEntry, createActionEndEntry, log},
|
||||||
} = require('metro-core');
|
} = require('metro-core');
|
||||||
|
@ -66,6 +68,7 @@ class Server {
|
||||||
_opts: {
|
_opts: {
|
||||||
assetExts: Array<string>,
|
assetExts: Array<string>,
|
||||||
blacklistRE: void | RegExp,
|
blacklistRE: void | RegExp,
|
||||||
|
cacheStores: $ReadOnlyArray<CacheStore<TransformedCode>>,
|
||||||
cacheVersion: string,
|
cacheVersion: string,
|
||||||
createModuleIdFactory?: () => (path: string) => number,
|
createModuleIdFactory?: () => (path: string) => number,
|
||||||
enableBabelRCLookup: boolean,
|
enableBabelRCLookup: boolean,
|
||||||
|
@ -117,6 +120,7 @@ class Server {
|
||||||
assetExts: options.assetTransforms ? [] : assetExts,
|
assetExts: options.assetTransforms ? [] : assetExts,
|
||||||
assetRegistryPath: options.assetRegistryPath,
|
assetRegistryPath: options.assetRegistryPath,
|
||||||
blacklistRE: options.blacklistRE,
|
blacklistRE: options.blacklistRE,
|
||||||
|
cacheStores: options.cacheStores || [],
|
||||||
cacheVersion: options.cacheVersion,
|
cacheVersion: options.cacheVersion,
|
||||||
dynamicDepsInPackages: options.dynamicDepsInPackages || 'throwAtRuntime',
|
dynamicDepsInPackages: options.dynamicDepsInPackages || 'throwAtRuntime',
|
||||||
createModuleIdFactory: options.createModuleIdFactory,
|
createModuleIdFactory: options.createModuleIdFactory,
|
||||||
|
|
Loading…
Reference in New Issue