Cache individual programmatic descriptors along with the overall list. (#8494)
This commit is contained in:
parent
c2a2e24965
commit
3a399d1eb9
@ -41,6 +41,22 @@ export type UnloadedDescriptor = {
|
|||||||
} | void,
|
} | void,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function isEqualDescriptor(
|
||||||
|
a: UnloadedDescriptor,
|
||||||
|
b: UnloadedDescriptor,
|
||||||
|
): boolean {
|
||||||
|
return (
|
||||||
|
a.name === b.name &&
|
||||||
|
a.value === b.value &&
|
||||||
|
a.options === b.options &&
|
||||||
|
a.dirname === b.dirname &&
|
||||||
|
a.alias === b.alias &&
|
||||||
|
a.ownPass === b.ownPass &&
|
||||||
|
(a.file && a.file.request) === (b.file && b.file.request) &&
|
||||||
|
(a.file && a.file.resolved) === (b.file && b.file.resolved)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export type ValidatedFile = {
|
export type ValidatedFile = {
|
||||||
filepath: string,
|
filepath: string,
|
||||||
dirname: string,
|
dirname: string,
|
||||||
@ -50,7 +66,7 @@ export type ValidatedFile = {
|
|||||||
/**
|
/**
|
||||||
* Create a set of descriptors from a given options object, preserving
|
* Create a set of descriptors from a given options object, preserving
|
||||||
* descriptor identity based on the identity of the plugin/preset arrays
|
* descriptor identity based on the identity of the plugin/preset arrays
|
||||||
* themselves.
|
* themselves, and potentially on the identity of the plugins/presets + options.
|
||||||
*/
|
*/
|
||||||
export function createCachedDescriptors(
|
export function createCachedDescriptors(
|
||||||
dirname: string,
|
dirname: string,
|
||||||
@ -113,26 +129,82 @@ export function createUncachedDescriptors(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const PRESET_DESCRIPTOR_CACHE = new WeakMap();
|
||||||
const createCachedPresetDescriptors = makeWeakCache(
|
const createCachedPresetDescriptors = makeWeakCache(
|
||||||
(items: PluginList, cache: CacheConfigurator<string>) => {
|
(items: PluginList, cache: CacheConfigurator<string>) => {
|
||||||
const dirname = cache.using(dir => dir);
|
const dirname = cache.using(dir => dir);
|
||||||
return makeStrongCache((alias: string) =>
|
return makeStrongCache((alias: string) =>
|
||||||
makeStrongCache((passPerPreset: boolean) =>
|
makeStrongCache((passPerPreset: boolean) =>
|
||||||
createPresetDescriptors(items, dirname, alias, passPerPreset),
|
createPresetDescriptors(items, dirname, alias, passPerPreset).map(
|
||||||
|
// Items are cached using the overall preset array identity when
|
||||||
|
// possibly, but individual descriptors are also cached if a match
|
||||||
|
// can be found in the previously-used descriptor lists.
|
||||||
|
desc => loadCachedDescriptor(PRESET_DESCRIPTOR_CACHE, desc),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const PLUGIN_DESCRIPTOR_CACHE = new WeakMap();
|
||||||
const createCachedPluginDescriptors = makeWeakCache(
|
const createCachedPluginDescriptors = makeWeakCache(
|
||||||
(items: PluginList, cache: CacheConfigurator<string>) => {
|
(items: PluginList, cache: CacheConfigurator<string>) => {
|
||||||
const dirname = cache.using(dir => dir);
|
const dirname = cache.using(dir => dir);
|
||||||
return makeStrongCache((alias: string) =>
|
return makeStrongCache((alias: string) =>
|
||||||
createPluginDescriptors(items, dirname, alias),
|
createPluginDescriptors(items, dirname, alias).map(
|
||||||
|
// Items are cached using the overall plugin array identity when
|
||||||
|
// possibly, but individual descriptors are also cached if a match
|
||||||
|
// can be found in the previously-used descriptor lists.
|
||||||
|
desc => loadCachedDescriptor(PLUGIN_DESCRIPTOR_CACHE, desc),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When no options object is given in a descriptor, this object is used
|
||||||
|
* as a WeakMap key in order to have consistent identity.
|
||||||
|
*/
|
||||||
|
const DEFAULT_OPTIONS = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given the cache and a descriptor, returns a matching descriptor from the
|
||||||
|
* cache, or else returns the input descriptor and adds it to the cache for
|
||||||
|
* next time.
|
||||||
|
*/
|
||||||
|
function loadCachedDescriptor(
|
||||||
|
cache: WeakMap<{} | Function, WeakMap<{}, Array<UnloadedDescriptor>>>,
|
||||||
|
desc: UnloadedDescriptor,
|
||||||
|
) {
|
||||||
|
const { value, options = DEFAULT_OPTIONS } = desc;
|
||||||
|
if (options === false) return desc;
|
||||||
|
|
||||||
|
let cacheByOptions = cache.get(value);
|
||||||
|
if (!cacheByOptions) {
|
||||||
|
cacheByOptions = new WeakMap();
|
||||||
|
cache.set(value, cacheByOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
let possibilities = cacheByOptions.get(options);
|
||||||
|
if (!possibilities) {
|
||||||
|
possibilities = [];
|
||||||
|
cacheByOptions.set(options, possibilities);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (possibilities.indexOf(desc) === -1) {
|
||||||
|
const matches = possibilities.filter(possibility =>
|
||||||
|
isEqualDescriptor(possibility, desc),
|
||||||
|
);
|
||||||
|
if (matches.length > 0) {
|
||||||
|
return matches[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
possibilities.push(desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
return desc;
|
||||||
|
}
|
||||||
|
|
||||||
function createPresetDescriptors(
|
function createPresetDescriptors(
|
||||||
items: PluginList,
|
items: PluginList,
|
||||||
dirname: string,
|
dirname: string,
|
||||||
|
|||||||
@ -29,10 +29,10 @@ describe("@babel/core config loading", () => {
|
|||||||
filename: FILEPATH,
|
filename: FILEPATH,
|
||||||
presets: skipProgrammatic
|
presets: skipProgrammatic
|
||||||
? null
|
? null
|
||||||
: [require("./fixtures/config-loading/preset3")],
|
: [[require("./fixtures/config-loading/preset3"), {}]],
|
||||||
plugins: skipProgrammatic
|
plugins: skipProgrammatic
|
||||||
? null
|
? null
|
||||||
: [require("./fixtures/config-loading/plugin6")],
|
: [[require("./fixtures/config-loading/plugin6"), {}]],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -213,7 +213,7 @@ describe("@babel/core config loading", () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should invalidate the plugins when given a fresh arrays", () => {
|
it("should not invalidate the plugins when given a fresh arrays", () => {
|
||||||
const opts = makeOpts();
|
const opts = makeOpts();
|
||||||
|
|
||||||
const options1 = loadConfig(opts).options;
|
const options1 = loadConfig(opts).options;
|
||||||
@ -224,6 +224,38 @@ describe("@babel/core config loading", () => {
|
|||||||
}).options;
|
}).options;
|
||||||
expect(options2.plugins.length).toBe(options1.plugins.length);
|
expect(options2.plugins.length).toBe(options1.plugins.length);
|
||||||
|
|
||||||
|
for (let i = 0; i < options2.plugins.length; i++) {
|
||||||
|
expect(options2.plugins[i]).toBe(options1.plugins[i]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should not invalidate the presets when given a fresh arrays", () => {
|
||||||
|
const opts = makeOpts();
|
||||||
|
|
||||||
|
const options1 = loadConfig(opts).options;
|
||||||
|
|
||||||
|
const options2 = loadConfig({
|
||||||
|
...opts,
|
||||||
|
presets: opts.presets.slice(),
|
||||||
|
}).options;
|
||||||
|
expect(options2.plugins.length).toBe(options1.plugins.length);
|
||||||
|
|
||||||
|
for (let i = 0; i < options2.plugins.length; i++) {
|
||||||
|
expect(options2.plugins[i]).toBe(options1.plugins[i]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should invalidate the plugins when given a fresh options", () => {
|
||||||
|
const opts = makeOpts();
|
||||||
|
|
||||||
|
const options1 = loadConfig(opts).options;
|
||||||
|
|
||||||
|
const options2 = loadConfig({
|
||||||
|
...opts,
|
||||||
|
plugins: opts.plugins.map(([plg, opt]) => [plg, { ...opt }]),
|
||||||
|
}).options;
|
||||||
|
expect(options2.plugins.length).toBe(options1.plugins.length);
|
||||||
|
|
||||||
for (let i = 0; i < options2.plugins.length; i++) {
|
for (let i = 0; i < options2.plugins.length; i++) {
|
||||||
if (i === 2) {
|
if (i === 2) {
|
||||||
expect(options2.plugins[i]).not.toBe(options1.plugins[i]);
|
expect(options2.plugins[i]).not.toBe(options1.plugins[i]);
|
||||||
@ -233,14 +265,14 @@ describe("@babel/core config loading", () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should invalidate the presets when given a fresh arrays", () => {
|
it("should invalidate the presets when given a fresh options", () => {
|
||||||
const opts = makeOpts();
|
const opts = makeOpts();
|
||||||
|
|
||||||
const options1 = loadConfig(opts).options;
|
const options1 = loadConfig(opts).options;
|
||||||
|
|
||||||
const options2 = loadConfig({
|
const options2 = loadConfig({
|
||||||
...opts,
|
...opts,
|
||||||
presets: opts.presets.slice(),
|
presets: opts.presets.map(([plg, opt]) => [plg, { ...opt }]),
|
||||||
}).options;
|
}).options;
|
||||||
expect(options2.plugins.length).toBe(options1.plugins.length);
|
expect(options2.plugins.length).toBe(options1.plugins.length);
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user