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

Default in Babel 8 to use @babel/plugin-transform-runtime #13157

Open
thernstig opened this issue Apr 15, 2021 · 2 comments
Open

Default in Babel 8 to use @babel/plugin-transform-runtime #13157

thernstig opened this issue Apr 15, 2021 · 2 comments
Milestone

Comments

@thernstig
Copy link

Feature Request

Is your feature request related to a problem?
We all want our bundles to be as small as possible. Using @babel/plugin-transform-runtime definitely does this.

Describe the solution you'd like
It would be nice if @babel/plugin-transform-runtime was run by default. This helps double-up since first it will inject imports into files instead of helper functions, and then bundlers like Webpack will be even smarter to just use the code once. This is only beneficial to users.

Documentation, Adoption, Migration Strategy
This needs to be done in babel 8 to not break current users setup.

@babel-bot
Copy link
Collaborator

Hey @thernstig! 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."

@nyngwang
Copy link

I think it's time to revive this thread now. Let's extend the requirement first:

We all want our bundles to be as small as possible, and it should be easy to setup and understood by beginners.

From my perspective, Babel is on the right track. In my usecase for building a frontend app with the advantages listed:

  • It's clear for intermediate users that by moduleName: '@babel/runtime' it does not include any pure polyfills in the helpers provided by @babel/plugin-transform-runtime. This removes the need for core-js-pure.
  • It's clear literally that corejs3 is probably the only polyfills provider and it adds global polyfills upon usage only.
  • It's clear for intermediate users that by removing "useBuiltIns" option from @babel/preset-env, it does not include any global polyfills.

My config looks like this:

// @filename: babel.config.mjs
return {
  plugins: [
    '@babel/plugin-transform-runtime', { moduleName: '@babel/runtime' },
    'babel-plugin-polyfill-corejs3', { method: 'usage-global' },
  ],
  presets: [
    ['@babel/preset-env', {...}], // without "useBuiltIns".
    // ...
  ]
}

As you can see, there are still some leaky abstractions. (I will explain the details for beginners in the following section.) But I think it is a good starting point for asking some questions:

  • Is it possible to simplify it further?
  • Do we really have a usecase where a user does not want to extract helpers by @babel/plugin-transform-runtime?
  • Do we really need to expose the ideas of pure/global polyfills to developers when they just want to build an app?

The following section is written for beginners.

It's intended to summarize/clarify the long-opening thread:

For a better referencing experience, please right-click every link with "Open Link in New Tab" to trigger the decent text-fragment feature I managed really hard for you.


🤔 Using @babel/plugin-transform-runtime for polyfills might not be a good idea for Apps

First of all, you might not know that this plugin can add pure corejs polyfills for you. I assume that most people are still using Babel v7(which is fine!), and I would like to mention some pitfalls before you might fall into any of those:

  1. If you're writing an app (i.e. anything will not be imported), you probably don't want to bloat your bundle size by including "too many" pure polyfills from @babel/plugin-transform-runtime when corejs set to either 2 or 3, as it will not respect your browser targets. See: the first problem under "Our old approach has two main problems".

  2. If you're writing a library, or maybe you prefer pure polyfills from @babel/plugin-transform-runtime for some reason, you should remove the "useBuiltIns" option from @babel/preset-env (in case you're using both). Otherwise, you will end up installing two core-js libraries with different work styles (pure vs global) fighting for the same job(and transform-runtime will win, as it will be executed first), which means a bloated bundle again.

On the other hand, you should be aware that the corejs option of @babel/plugin-transform-runtime will be removed in Babel v8. Why? That's for solving the second problem under "Our old approach has two main problems" and avoiding overlapping.


😵 Using @babel/plugin-transform-runtime before version v7.18.0 is a bit complicated

End of the pitfalls around polyfills for basic stuff. Now let's talk about the pitfalls around transpiling generator syntax:

  1. Before Babel v7.18.0, transforming generator syntax with only @babel/plugin-transform-regenerator(which is included in @babel/preset-env) was not enough as it relies on a global runtime helper, which was not implemented/included in the plugin itself. Instead, you had to either:

    1. Import it manually with import "regenerator-runtime".
    2. Import it automatically with @babel/preset-env's "useBuiltIns": "entry"(as there was a bug around "useBuiltIns": "usage")
    3. Import it automatically with @babel/transform-runtime's "regenerator": true. And yes, it was the only thing still left as global by @babel/transform-runtime when corejs: false.

As long as you're on Babel v7.18.0 or above, there is NO global runtime helper anymore. It's baked-in: (basically a summary for #14538)

  • @babel/preset-env does not depend on the global runtime helper. Instead, it becomes an inlined function. But it's huge, and you might want to consider @babel/transform-runtime.
  • @babel/transform-runtime does not treat generator syntax as a special case from helpers. (That's why both regenerator and helpers will be removed as there is no need to differentiate between them 🎉)

😤 What's the conclusion...?

Wait, that's wordy... Could you just show me how to use Babel for now?

I'm more than happy to share my experience so that more people can setup Babel as intended without any confusion. That's why I want to mention https://github.com/babel/babel-polyfills again:

[source]
As you can see, there is an overlap in what the two plugins can do. To avoid confusion, we are moving towards a model where plugins are handled by a separate package:

  • @babel/plugin-transform-runtime is only to inject imports to Babel helpers
  • @babel/preset-env is only for syntax transforms
  • babel-plugin-polyfill-corejs3 for polyfills, with an option to choose between polyfills installed by modifying globals or "pure" polyfills.

In fact, I tried it and encountered a bug: #16238, which is covered by #16241 immediately :)

Then, with the new moduleName, I tried something like the following (since my focus is on building an app) but it didn't work before this week:

// @filename: babel.config.mjs
plugins: [
  '@babel/plugin-transform-runtime', { moduleName: '@babel/runtime', regenerator: false },
  'babel-plugin-polyfill-corejs3', { method: 'usage-global' },
  'babel-plugin-polyfill-regenerator', { method: 'usage-global' } // I tried to use this to replace `regenerator: true`.
],
presets: [
  ['@babel/preset-env', {...}], // without "useBuiltIns".
  // ...
]

BUT, the fix has just been merged and landed on v7.24.1 days ago. With a better understanding of Babel, I simplified it even more, with my notes:

  • For @babel/plugin-transform-runtime
    • regenerator option is ignored from v7.18.0.
    • moduleName is set to @babel/runtime to avoid pure polyfill implied by polyfill-corejs3 below.
      • but this also implies that you will need to transpile @babel/runtime yourself. I'm fine with this.
  • For babel-plugin-polyfill-corejs3
    • this plugin is already included in @babel/preset-env.
    • I prefer to use usage-global to polyfill @babel/runtime above.
  • For babel-plugin-polyfill-regenerator
    • this plugin is already included in @babel/preset-env.
// @filename: babel.config.mjs
plugins: [
  '@babel/plugin-transform-runtime', { moduleName: '@babel/runtime' },
  'babel-plugin-polyfill-corejs3', { method: 'usage-global' },
],
presets: [
  ['@babel/preset-env', {...}], // without "useBuiltIns".
  // ...
]

Now we arrive at basically the same script I provided at the beginning of this comment!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants