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 5 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
8 changes: 6 additions & 2 deletions packages/babel-core/src/config/config-descriptors.ts
Expand Up @@ -133,22 +133,26 @@ export function createUncachedDescriptors(
options: optionsWithResolvedBrowserslistConfigFile(options, dirname),
*plugins() {
if (!plugins) {
plugins = yield* createPluginDescriptors(
const _plugins = yield* createPluginDescriptors(
options.plugins || [],
dirname,
alias,
);
// check plugins again to avoid race conditions
plugins ??= _plugins;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of just ignoring the result of the second createPluginDescriptors call, can we avoid calling it twice in the first place? Something like this:

  let pluginsGen;
  return {
    options: optionsWithResolvedBrowserslistConfigFile(options, dirname),
    *plugins() {
      pluginsGen ??= createPluginDescriptors(
        options.plugins || [],
        dirname,
        alias,
      );
      return yield* pluginsGen;
    }
  };

Copy link
Contributor Author

@JLHwung JLHwung Aug 13, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we cache the iterator instead, test will fail because the finished iterator always return undefined: https://github.com/JLHwung/babel/runs/7819160996?check_suite_focus=true

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I pushed a commit to do the caching, so that now:

  • The first call runs createPluginDescriptors, and after a while returns it
  • The second call waits for the result of the first call, and returns it

Instead of

  • The first call runs createPluginDescriptors, and returns the result of the createPluginDescriptors that finishes first
  • The second call runs createPluginDescriptors, and returns the result of the createPluginDescriptors that finishes first

This avoids resolving the same plugins/presets multiple times, which is a costly operation because it involves the filesystem.

}
return plugins;
},
*presets() {
if (!presets) {
presets = yield* createPresetDescriptors(
const _presets = yield* createPresetDescriptors(
options.presets || [],
dirname,
alias,
!!options.passPerPreset,
);
// check presets again to avoid race conditions
presets ??= _presets;
}
return presets;
},
Expand Down