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

Fix a race condition in @babel/core #14843

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 Gulpfile.mjs
Expand Up @@ -265,7 +265,7 @@ async function buildBabel(useWorker, ignore = []) {
const dest = "./" + mapSrcToLib(file.slice(2));
promises.push(worker.transform(file, dest));
}
return Promise.all(promises).finally(() => {
return Promise.allSettled(promises).finally(() => {
if (worker.end !== undefined) {
worker.end();
}
Expand Down
4 changes: 2 additions & 2 deletions babel-worker.cjs
@@ -1,4 +1,4 @@
const { transformSync } = require("@babel/core");
const { transformAsync } = require("@babel/core");
const { mkdirSync, statSync, readFileSync, writeFileSync } = require("fs");
const { dirname } = require("path");
const fancyLog = require("fancy-log");
Expand Down Expand Up @@ -32,7 +32,7 @@ exports.transform = async function transform(src, dest) {
}
fancyLog(`Compiling '${chalk.cyan(src)}'...`);
const content = readFileSync(src, { encoding: "utf8" });
const { code } = transformSync(content, {
const { code } = await transformAsync(content, {
filename: src,
caller: {
// We have wrapped packages/babel-core/src/config/files/configuration.js with feature detection
Expand Down
46 changes: 16 additions & 30 deletions packages/babel-core/src/config/config-descriptors.ts
@@ -1,6 +1,5 @@
import gensync from "gensync";

import type { Handler } from "gensync";
import gensync, { type Handler } from "gensync";
import { once } from "../gensync-utils/functional";

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

Expand Down Expand Up @@ -123,35 +122,22 @@ export function createUncachedDescriptors(
options: ValidatedOptions,
alias: string,
): OptionsAndDescriptors {
// The returned result here is cached to represent a config object in
// memory, so we build and memoize the descriptors to ensure the same
// values are returned consistently.
let plugins: UnloadedDescriptor[];
let presets: UnloadedDescriptor[];

return {
options: optionsWithResolvedBrowserslistConfigFile(options, dirname),
*plugins() {
if (!plugins) {
plugins = yield* createPluginDescriptors(
options.plugins || [],
dirname,
alias,
);
}
return plugins;
},
*presets() {
if (!presets) {
presets = yield* createPresetDescriptors(
options.presets || [],
dirname,
alias,
!!options.passPerPreset,
);
}
return presets;
},
// The returned result here is cached to represent a config object in
// memory, so we build and memoize the descriptors to ensure the same
// values are returned consistently.
plugins: once(() =>
createPluginDescriptors(options.plugins || [], dirname, alias),
),
presets: once(() =>
createPresetDescriptors(
options.presets || [],
dirname,
alias,
!!options.passPerPreset,
),
),
};
}

Expand Down
31 changes: 31 additions & 0 deletions packages/babel-core/src/gensync-utils/functional.ts
@@ -0,0 +1,31 @@
import type { Handler } from "gensync";

import { isAsync, waitFor } from "./async";

export function once<R>(fn: () => Handler<R>): () => Handler<R> {
let result: R;
let resultP: Promise<R>;
return function* () {
if (result) return result;
if (!(yield* isAsync())) return (result = yield* fn());
if (resultP) return yield* waitFor(resultP);

let resolve: (result: R) => void, reject: (error: unknown) => void;
resultP = new Promise((res, rej) => {
resolve = res;
reject = rej;
});

try {
result = yield* fn();
// Avoid keeping the promise around
// now that we have the result.
resultP = null;
resolve(result);
return result;
} catch (error) {
reject(error);
throw error;
}
};
}