Skip to content

Commit c45da3d

Browse files
Fix a race condition in @babel/core (#14843)
Co-authored-by: Nicolò Ribaudo <nicolo.ribaudo@gmail.com>
1 parent a32cf83 commit c45da3d

5 files changed

Lines changed: 127 additions & 85 deletions

File tree

Gulpfile.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,7 @@ async function buildBabel(useWorker, ignore = []) {
265265
const dest = "./" + mapSrcToLib(file.slice(2));
266266
promises.push(worker.transform(file, dest));
267267
}
268-
return Promise.all(promises).finally(() => {
268+
return Promise.allSettled(promises).finally(() => {
269269
if (worker.end !== undefined) {
270270
worker.end();
271271
}

babel-worker.cjs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
const { transformSync } = require("@babel/core");
1+
const { transformAsync } = require("@babel/core");
22
const { mkdirSync, statSync, readFileSync, writeFileSync } = require("fs");
33
const { dirname } = require("path");
44
const { log } = require("./scripts/utils/logger.cjs");
@@ -32,7 +32,7 @@ exports.transform = async function transform(src, dest) {
3232
}
3333
log(`Compiling '${chalk.cyan(src)}'...`);
3434
const content = readFileSync(src, { encoding: "utf8" });
35-
const { code } = transformSync(content, {
35+
const { code } = await transformAsync(content, {
3636
filename: src,
3737
caller: {
3838
// We have wrapped packages/babel-core/src/config/files/configuration.js with feature detection

packages/babel-core/src/config/config-descriptors.ts

Lines changed: 16 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
import gensync from "gensync";
2-
3-
import type { Handler } from "gensync";
1+
import gensync, { type Handler } from "gensync";
2+
import { once } from "../gensync-utils/functional";
43

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

@@ -123,35 +122,22 @@ export function createUncachedDescriptors(
123122
options: ValidatedOptions,
124123
alias: string,
125124
): OptionsAndDescriptors {
126-
// The returned result here is cached to represent a config object in
127-
// memory, so we build and memoize the descriptors to ensure the same
128-
// values are returned consistently.
129-
let plugins: UnloadedDescriptor[];
130-
let presets: UnloadedDescriptor[];
131-
132125
return {
133126
options: optionsWithResolvedBrowserslistConfigFile(options, dirname),
134-
*plugins() {
135-
if (!plugins) {
136-
plugins = yield* createPluginDescriptors(
137-
options.plugins || [],
138-
dirname,
139-
alias,
140-
);
141-
}
142-
return plugins;
143-
},
144-
*presets() {
145-
if (!presets) {
146-
presets = yield* createPresetDescriptors(
147-
options.presets || [],
148-
dirname,
149-
alias,
150-
!!options.passPerPreset,
151-
);
152-
}
153-
return presets;
154-
},
127+
// The returned result here is cached to represent a config object in
128+
// memory, so we build and memoize the descriptors to ensure the same
129+
// values are returned consistently.
130+
plugins: once(() =>
131+
createPluginDescriptors(options.plugins || [], dirname, alias),
132+
),
133+
presets: once(() =>
134+
createPresetDescriptors(
135+
options.presets || [],
136+
dirname,
137+
alias,
138+
!!options.passPerPreset,
139+
),
140+
),
155141
};
156142
}
157143

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import type { Handler } from "gensync";
2+
3+
import { isAsync, waitFor } from "./async";
4+
5+
export function once<R>(fn: () => Handler<R>): () => Handler<R> {
6+
let result: R;
7+
let resultP: Promise<R>;
8+
return function* () {
9+
if (result) return result;
10+
if (!(yield* isAsync())) return (result = yield* fn());
11+
if (resultP) return yield* waitFor(resultP);
12+
13+
let resolve: (result: R) => void, reject: (error: unknown) => void;
14+
resultP = new Promise((res, rej) => {
15+
resolve = res;
16+
reject = rej;
17+
});
18+
19+
try {
20+
result = yield* fn();
21+
// Avoid keeping the promise around
22+
// now that we have the result.
23+
resultP = null;
24+
resolve(result);
25+
return result;
26+
} catch (error) {
27+
reject(error);
28+
throw error;
29+
}
30+
};
31+
}

0 commit comments

Comments
 (0)