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 asynchronous configuration #9888

Open
guybedford opened this issue Apr 22, 2019 · 9 comments

Comments

@guybedford
Copy link
Contributor

commented Apr 22, 2019

I couldn't find an existing tracking issue for this feature, please mark as a duplicate if I've missed anything.

This is something that would be required for jspm support in Babel CLI, where we'd want to use dynamic import() to reference plugins directly, and so would need some kind of promise support in the configuration.

Currently an asynchronous configuration gives the following error:

Error: You appear to be using an async configuration, which your current version of Babel does not support. We may add support for this in the future, but if you're on the most recent version of @babel/core and still seeing this error, then you'll need to synchronously return your config.

And an asynchronous plugin gives the following error:

You appear to be using an async plugin, which your current version of Babel
does not support.If you're using a published plugin, you may need to upgrade your @babel/core version.

Either or both of these features would be really great to support.

The async plugin case effectively provides parity with top-level await workflows in future too. Happy to discuss further as well.

@babel-bot

This comment has been minimized.

Copy link
Collaborator

commented Apr 22, 2019

Hey @guybedford! We really appreciate you taking the time to report an issue. The collaborators
on this project attempt to help as many people as possible, but we're a limited number of volunteers,
so it's possible this won't be addressed swiftly.

If you need any help, or just have general Babel or JavaScript questions, we have a vibrant Slack
community
that typically always has someone willing to help. You can sign-up here
for an invite.

@nicolo-ribaudo

This comment has been minimized.

Copy link
Member

commented Apr 29, 2019

While developing Babel 7 beta, we added that errors to be able to introduce async config/plugins during the Babel 7 lifetime without breaking changes.

The biggest problem is that currently Babel can be called synchronously (var out = babel.transform(code, options)), and there is no way to make it work with async config/plugins.

@guybedford

This comment has been minimized.

Copy link
Contributor Author

commented Apr 29, 2019

Thanks for clarifying. Ok so how can we do this safely? Just throw when running under the sync transform only?

@nicolo-ribaudo

This comment has been minimized.

Copy link
Member

commented Apr 29, 2019

Just throw when running under the sync transform only?

Either that, or https://github.com/abbr/deasync.

I have done some research to understand how hard would be for the ecosystem to support async Babel configurations:

  1. babel-loader will support it without any change, it already uses Babel's async api.
  2. rollup-plugin-babel can be easily updated: it call's Babel sync transform inside an async function
  3. ESLint doesn't support async parsers: this is a problem for babel-eslint
@loganfsmyth

This comment has been minimized.

Copy link
Member

commented Apr 29, 2019

When I added the error my intention was to eventually

  1. Throw an exception if a plugin/config returns a promise in a context where Babel is used synchronously
  2. Expose an API on the first function parameter so that plugins could check which whether promises would be allowed, and change their behavior depending on that. That way a plugin could be async ideally and fall back to a sync implementation if it wanted or something.

That way if a plugin really wanted to use deasync or something, it could, but it wouldn't be something we'd do in our own plugins, or necessarily recommend, since that module really is ugly.

It'd also be interesting to continue working to make other implementations async, or at least optionally async. I had thought for instance that @babel/register could expose a mode that would precompile all of the modules in a set of files, before executing the application entrypoint, for instance, so require could be sync, but compilation could be async.

@guybedford

This comment has been minimized.

Copy link
Contributor Author

commented May 22, 2019

There seem to be quite a lot of ways to come at this problem.

Note also that an alternative way to support the use case mentioned above for jspm would be if Babel would support top-level await in the babel.config.js file.

If I created a tracking issue specifically for top-level await in babel.config.js would that be something that would be considered for a PR?

@nicolo-ribaudo

This comment has been minimized.

Copy link
Member

commented May 22, 2019

Since we aren't transpiling babel.config.js, supporting async configurations is way easier.

Also, I think that when plugins will be written using native node esm we will be forced to resolve them asynchronously, since we load them dynamically.

@guybedford

This comment has been minimized.

Copy link
Contributor Author

commented May 22, 2019

@nicolo-ribaudo do you mean this is because it is loaded via require("path/to/babel.config.js")?

I think that this can be made to support top-level await with a pattern something like (exact details may be slightly off since I'm writing this in a github comment):

function asyncRequire (name) {
  const Module = require('module').Module;
  const m = new Module(name);
  m.paths = Module._nodeModulePaths(path.resolve(name));
  const promise = eval(`(async function (exports, require, module, __filename, __dirname) {
${fs.readFileSync(name).toString()};
})(m.exports, m.require, m, __filename, __dirname)`;
  return promise;
}
@guybedford

This comment has been minimized.

Copy link
Contributor Author

commented May 22, 2019

Or preferably in the above via vm.runInThisContext.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
4 participants
You can’t perform that action at this time.