Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support .mjs plugins/presets and async factories #12266

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/babel-core/package.json
Expand Up @@ -53,7 +53,7 @@
"@babel/types": "workspace:^7.12.1",
"convert-source-map": "^1.7.0",
"debug": "^4.1.0",
"gensync": "^1.0.0-beta.1",
"gensync": "^1.0.0-beta.2",
"json5": "^2.1.2",
"lodash": "^4.17.19",
"resolve": "^1.3.2",
Expand Down
16 changes: 8 additions & 8 deletions packages/babel-core/src/config/config-chain.js
Expand Up @@ -154,7 +154,7 @@ export function* buildRootChain(
programmaticLogger,
);
if (!programmaticChain) return null;
const programmaticReport = programmaticLogger.output();
const programmaticReport = yield* programmaticLogger.output();

let configFile;
if (typeof opts.configFile === "string") {
Expand Down Expand Up @@ -186,7 +186,7 @@ export function* buildRootChain(
configFileLogger,
);
if (!result) return null;
configReport = configFileLogger.output();
configReport = yield* configFileLogger.output();

// Allow config files to toggle `.babelrc` resolution on and off and
// specify where the roots are.
Expand Down Expand Up @@ -244,7 +244,7 @@ export function* buildRootChain(
if (!result) {
isIgnored = true;
} else {
babelRcReport = babelrcLogger.output();
babelRcReport = yield* babelrcLogger.output();
mergeChain(fileChain, result);
}
}
Expand Down Expand Up @@ -599,7 +599,7 @@ function makeChainWalker<ArgT: { options: ValidatedOptions, dirname: string }>({
}

logger(config, index, envName);
mergeChainOpts(chain, config);
yield* mergeChainOpts(chain, config);
}
return chain;
};
Expand Down Expand Up @@ -657,13 +657,13 @@ function mergeChain(target: ConfigChain, source: ConfigChain): ConfigChain {
return target;
}

function mergeChainOpts(
function* mergeChainOpts(
target: ConfigChain,
{ options, plugins, presets }: OptionsAndDescriptors,
): ConfigChain {
): Handler<ConfigChain> {
target.options.push(options);
target.plugins.push(...plugins());
target.presets.push(...presets());
target.plugins.push(...(yield* plugins()));
target.presets.push(...(yield* presets()));

return target;
}
Expand Down
93 changes: 60 additions & 33 deletions packages/babel-core/src/config/config-descriptors.js
@@ -1,12 +1,15 @@
// @flow

import gensync, { type Handler } from "gensync";

import { loadPlugin, loadPreset } from "./files";

import { getItemDescriptor } from "./item";

import {
makeWeakCacheSync,
makeStrongCacheSync,
makeStrongCache,
type CacheConfigurator,
} from "./caching";

Expand All @@ -21,8 +24,8 @@ import type {
// the options object actually ends up being applicable.
export type OptionsAndDescriptors = {
options: ValidatedOptions,
plugins: () => Array<UnloadedDescriptor>,
presets: () => Array<UnloadedDescriptor>,
plugins: () => Handler<Array<UnloadedDescriptor>>,
presets: () => Handler<Array<UnloadedDescriptor>>,
};

// Represents a plugin or presets at a given location in a config object.
Expand Down Expand Up @@ -63,6 +66,11 @@ export type ValidatedFile = {
options: ValidatedOptions,
};

// eslint-disable-next-line require-yield
function* handlerOf<T>(value: T): Handler<T> {
return value;
}

/**
* Create a set of descriptors from a given options object, preserving
* descriptor identity based on the identity of the plugin/preset arrays
Expand All @@ -78,13 +86,13 @@ export function createCachedDescriptors(
options,
plugins: plugins
? () => createCachedPluginDescriptors(plugins, dirname)(alias)
: () => [],
: () => handlerOf([]),
presets: presets
? () =>
createCachedPresetDescriptors(presets, dirname)(alias)(
!!passPerPreset,
)
: () => [],
: () => handlerOf([]),
};
}

Expand All @@ -105,19 +113,19 @@ export function createUncachedDescriptors(

return {
options,
plugins: () => {
*plugins() {
if (!plugins) {
plugins = createPluginDescriptors(
plugins = yield* createPluginDescriptors(
options.plugins || [],
dirname,
alias,
);
}
return plugins;
},
presets: () => {
*presets() {
if (!presets) {
presets = createPresetDescriptors(
presets = yield* createPresetDescriptors(
options.presets || [],
dirname,
alias,
Expand All @@ -134,14 +142,22 @@ const createCachedPresetDescriptors = makeWeakCacheSync(
(items: PluginList, cache: CacheConfigurator<string>) => {
const dirname = cache.using(dir => dir);
return makeStrongCacheSync((alias: string) =>
makeStrongCacheSync((passPerPreset: boolean) =>
createPresetDescriptors(items, dirname, alias, passPerPreset).map(
makeStrongCache(function* (
passPerPreset: boolean,
): Handler<Array<UnloadedDescriptor>> {
const descriptors = yield* createPresetDescriptors(
items,
dirname,
alias,
passPerPreset,
);
return descriptors.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),
),
),
);
}),
);
},
);
Expand All @@ -150,14 +166,17 @@ const PLUGIN_DESCRIPTOR_CACHE = new WeakMap();
const createCachedPluginDescriptors = makeWeakCacheSync(
(items: PluginList, cache: CacheConfigurator<string>) => {
const dirname = cache.using(dir => dir);
return makeStrongCacheSync((alias: string) =>
createPluginDescriptors(items, dirname, alias).map(
return makeStrongCache(function* (
alias: string,
): Handler<Array<UnloadedDescriptor>> {
const descriptors = yield* createPluginDescriptors(items, dirname, alias);
return descriptors.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),
),
);
);
});
},
);

Expand Down Expand Up @@ -205,36 +224,44 @@ function loadCachedDescriptor(
return desc;
}

function createPresetDescriptors(
function* createPresetDescriptors(
items: PluginList,
dirname: string,
alias: string,
passPerPreset: boolean,
): Array<UnloadedDescriptor> {
return createDescriptors("preset", items, dirname, alias, passPerPreset);
): Handler<Array<UnloadedDescriptor>> {
return yield* createDescriptors(
"preset",
items,
dirname,
alias,
passPerPreset,
);
}

function createPluginDescriptors(
function* createPluginDescriptors(
items: PluginList,
dirname: string,
alias: string,
): Array<UnloadedDescriptor> {
return createDescriptors("plugin", items, dirname, alias);
): Handler<Array<UnloadedDescriptor>> {
return yield* createDescriptors("plugin", items, dirname, alias);
}

function createDescriptors(
function* createDescriptors(
type: "plugin" | "preset",
items: PluginList,
dirname: string,
alias: string,
ownPass?: boolean,
): Array<UnloadedDescriptor> {
const descriptors = items.map((item, index) =>
createDescriptor(item, dirname, {
type,
alias: `${alias}$${index}`,
ownPass: !!ownPass,
}),
): Handler<Array<UnloadedDescriptor>> {
const descriptors = yield* gensync.all(
items.map((item, index) =>
createDescriptor(item, dirname, {
type,
alias: `${alias}$${index}`,
ownPass: !!ownPass,
}),
),
);

assertNoDuplicates(descriptors);
Expand All @@ -245,7 +272,7 @@ function createDescriptors(
/**
* Given a plugin/preset item, resolve it into a standard format.
*/
export function createDescriptor(
export function* createDescriptor(
pair: PluginItem,
dirname: string,
{
Expand All @@ -257,7 +284,7 @@ export function createDescriptor(
alias: string,
ownPass?: boolean,
},
): UnloadedDescriptor {
): Handler<UnloadedDescriptor> {
const desc = getItemDescriptor(pair);
if (desc) {
return desc;
Expand Down Expand Up @@ -285,7 +312,7 @@ export function createDescriptor(
const resolver = type === "plugin" ? loadPlugin : loadPreset;
const request = value;

({ filepath, value } = resolver(value, dirname));
({ filepath, value } = yield* resolver(value, dirname));

file = {
request,
Expand Down
4 changes: 2 additions & 2 deletions packages/babel-core/src/config/files/index-browser.js
Expand Up @@ -80,7 +80,7 @@ export function resolvePreset(name: string, dirname: string): string | null {
export function loadPlugin(
name: string,
dirname: string,
): { filepath: string, value: mixed } {
): Handler<{ filepath: string, value: mixed }> {
throw new Error(
`Cannot load plugin ${name} relative to ${dirname} in a browser`,
);
Expand All @@ -89,7 +89,7 @@ export function loadPlugin(
export function loadPreset(
name: string,
dirname: string,
): { filepath: string, value: mixed } {
): Handler<{ filepath: string, value: mixed }> {
throw new Error(
`Cannot load preset ${name} relative to ${dirname} in a browser`,
);
Expand Down
14 changes: 9 additions & 5 deletions packages/babel-core/src/config/files/module-types.js
Expand Up @@ -12,13 +12,15 @@ try {
export default function* loadCjsOrMjsDefault(
filepath: string,
asyncError: string,
// TODO(Babel 8): Remove this
fallbackToTranspiledModule: boolean = false,
): Handler<mixed> {
switch (guessJSModuleType(filepath)) {
case "cjs":
return loadCjsDefault(filepath);
return loadCjsDefault(filepath, fallbackToTranspiledModule);
case "unknown":
try {
return loadCjsDefault(filepath);
return loadCjsDefault(filepath, fallbackToTranspiledModule);
} catch (e) {
if (e.code !== "ERR_REQUIRE_ESM") throw e;
}
Expand All @@ -42,10 +44,12 @@ function guessJSModuleType(filename: string): "cjs" | "mjs" | "unknown" {
}
}

function loadCjsDefault(filepath: string) {
function loadCjsDefault(filepath: string, fallbackToTranspiledModule: boolean) {
const module = (require(filepath): mixed);
// TODO (Babel 8): Remove "undefined" fallback
return module?.__esModule ? module.default || undefined : module;
return module?.__esModule
? // TODO (Babel 8): Remove "module" and "undefined" fallback
module.default || (fallbackToTranspiledModule ? module : undefined)
: module;
}

async function loadMjsDefault(filepath: string) {
Expand Down