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

[Documentation-Bug]: Can @babel/plugin-transform-runtime be used together with useBuiltIns ? #16149

Open
1 task
qiulang opened this issue Dec 4, 2023 · 12 comments
Labels

Comments

@qiulang
Copy link

qiulang commented Dec 4, 2023

💻

  • Would you like to work on a fix?

How are you using Babel?

babel-loader (webpack)

Input code

Sorry, this is really not a bug but a question but I have asked at #16127 and #16145 but I didn't get an answer.

https://babeljs.io/docs/babel-plugin-transform-runtime is confusing about whether it can be used with useBuiltIns.

On one hand, it says, "use @babel/preset-env's useBuiltIns option."

useBuiltIns

On the other hand, It says "When this plugin is enabled, the useBuiltIns option in @babel/preset-env must not be set. "

useBuiltIns 2

So what does "When this plugin is enabled" mean? I thought putting it in bable.config.json is to enable it.

Configuration file name

babel.config.json

Configuration

        "production": {
            "presets": [
                [
                    "@babel/preset-env",
                    {
                        "targets": "> 0.25%, not dead",
                        "modules": "commonjs",
                        "debug": true,
                        "useBuiltIns": "usage",
                        "shippedProposals": true,
                        "corejs": "3.33"
                    }
                ]
            ],
            "plugins": [["@babel/plugin-transform-runtime", {}]]
        }

Current and expected behavior

I use them together and I didn't find a problem.

Environment

 System:
    OS: macOS 14.0
  Binaries:
    Node: 16.20.0 - /usr/local/bin/node
    Yarn: 1.22.19 - /usr/local/bin/yarn
    npm: 8.19.4 - /usr/local/bin/npm
  npmPackages:
    @babel/core: ^7.0.0 => 7.20.5
    @babel/plugin-transform-runtime: ^7.0.0 => 7.19.6
    @babel/preset-env: ^7.0.0 => 7.20.2
    @babel/runtime-corejs3: ^7.12.13 => 7.20.6
    babel-eslint: ^10.0.1 => 10.1.0
    babel-loader: ^8.0.0 => 8.3.0
    babelify: ^8.0.0 => 8.0.0
    eslint: ^5.11.0 => 5.16.0
    gulp-babel: ^7.0.1 => 7.0.1
    webpack: ^4.37.0 => 4.46.0

Possible solution

No response

Additional context

I can't find a definite answer for it, e.g. stackoverflow has answers that do NOT agree with each other.

The comment from JMarkoski in #9853, which is quoted in many places say this,

Should I use useBuiltIns: 'usage' and corejs option on @babel/preset-env together with @babel/transform-runtime with core-js option set to false?

The answer is NO...

But I have use "plugins": [["@babel/plugin-transform-runtime", {}]] together with "useBuiltIns": "usage" all the time and I did not experience any problem while with a smaller bundled file size.

@babel-bot
Copy link
Collaborator

Hey @qiulang! 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
Copy link
Member

nicolo-ribaudo commented Dec 4, 2023

This is what these plugins/presets do:

  • @babel/plugin-transform-runtime with no options injects imports to Babel helpers
  • @babel/plugin-transform-runtime with the corejs option injects imports to polyfills for used features without installing them on global objects
    • When using core-js 2, this does not work for prototype methods
  • @babel/preset-env with useBuiltIns injects imports to polyfills by installing them on global objects (i.e. by modifying the built-in objects and methods)

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.

@qiulang
Copy link
Author

qiulang commented Dec 4, 2023

@nicolo-ribaudo thanks for replying to me. I know @babel/transform-runtime with the corejs option injecting corejs without global pollution while @babel/preset-env with useBuiltIns does.

So with your answer, can we draw the conclusions that:

  1. The Danger section in https://babeljs.io/docs/babel-plugin-transform-runtime, "When this plugin is enabled" actually means when @babel/plugin-transform-runtime with the corejs option is set, the useBuiltIns option in @babel/preset-env must not be set.
  2. JMarkoski's comments in Using @babel/runtime-corejs2 and @babel/runtime-corejs3 leads to larger bundle sizes #9853, "The answer is NO" to "use useBuiltIns: 'usage' and corejs option on @babel/preset-env together with @babel/transform-runtime with core-js option set to false?" is wrong

My following setting is okay.

"presets": [
                [
                    "@babel/preset-env",
                    {
                        ...
                        "useBuiltIns": "usage",
                        "shippedProposals": true,
                        "corejs": "3.33"
                    }
                ]
  ],
"plugins": [["@babel/plugin-transform-runtime", {}]]

@nicolo-ribaudo
Copy link
Member

That configuration is correct, with a caveat: @babel/plugin-transform-runtime will inject imports to @babel/runtime, and some of the files of @babel/runtime might need some polyfills in old browsers. If you are not compiling /node_modules/ with Babel, @babel/preset-env will not inject polyfills for @babel/runtime internal files (or for any other of your dependencies).

On the other hand, if you inject polyfills through @babel/plugin-transform-runtime it will use @babel/runtime-corejs3, which is already polyfilled internally.

@qiulang
Copy link
Author

qiulang commented Dec 4, 2023

I read JMarkoski's words in #9853 again and realized his reason for "NO", "You need a way to transpile the babel helpers, and that's not good." was actually what you just said "with a caveat: @babel/plugin-transform-runtime will inject imports to @babel/runtime, and some of the files of @babel/runtime might need some polyfills in old browsers. " And zloirock also said there "as transform-runtime injects helpers and some helpers depends on globals which should be polyfilled."

So if I use "useBuiltIns": "usage", the safest way to make sure it works for all old browsers is NOT to use "plugins": [["@babel/plugin-transform-runtime", {}]], right ?

@qiulang
Copy link
Author

qiulang commented Dec 5, 2023

@nicolo-ribaudo useBuiltIns: entry vs useBuiltIns: usage is another confusing setting.

zloirock also said (in 2019 but quoted in many places) in #9853 (comment)

useBuiltIns + runtime for helpers is preferable way for applications. However, I recommend useBuiltIns: entry with required parts of core-js since it's much simpler in configuration and much more predictable. useBuiltIns: usage makes sense only for small applications and, for correct work, much harder in configuration.

While you said in #14443 (reply in thread)

usage works in almost every case, I personally have never used entry 🤷

@nyngwang
Copy link

nyngwang commented Jan 18, 2024

To @nicolo-ribaudo:

[...]
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.

Does the new model with babel-plugin-polyfill-corejs3 handle the caveat you said? Quoted here again:

That configuration is correct, with a caveat: @babel/plugin-transform-runtime will inject imports to @babel/runtime, and some of the files of @babel/runtime might need some polyfills in old browsers.

Sincerely,
NW.

@nicolo-ribaudo
Copy link
Member

@nyngwang Unfortunately not yet -- for now, if you need to add polyfills for @babel/runtime internal code you have two options:

  • If you are using a bundler, you can configure it to remap @babel/runtime to @babel/runtime-corejs3
  • You can transpile @babel/runtime, as you would need to do for any other dependency that uses non-ES5 code and thus needs to be polyfilled/transpiled.

I'm working on something to make @babel/plugin-transform-runtime capable of injecting imports to @babel/runtime-corejs3 when using babel-plugin-polyfill-corejs3

@gtempesta-pixartprinting
Copy link

gtempesta-pixartprinting commented Feb 2, 2024

I'm in a similar situation, and I figured out that my production code breaks when I have this configuration:

options: {
  cacheDirectory: true,
  presets: [
    [
      '@babel/preset-env',
      {
        useBuiltIns: 'usage',
        targets: {
          browsers: ['> 0.25% and supports es6-module', 'not dead', 'Firefox ESR'],
        },
        corejs: {
          version: '3.35',
          proposals: true,
        },
      },
    ],
  ],
  plugins: [['@babel/plugin-transform-runtime', { corejs: 3 }]],
},

What I mean is that Webpack is able to build it, but I get a runtime error in the browser which I'm not able to track, from one of the bundles.

Uncaught TypeError: i.f is not a function

So at this point the alternatives are either removing useBuiltIns and corejs from the configuration of @babel/preset-env

options: {
  cacheDirectory: true,
  presets: [
    [
      '@babel/preset-env',
      {
        targets: {
          browsers: ['> 0.25% and supports es6-module', 'not dead', 'Firefox ESR'],
        },
      },
    ],
  ],
  plugins: [['@babel/plugin-transform-runtime', { corejs: 3 }]],
},

or removing the corejs from @babel/plugin-transform-runtime and installing the fallback library @babel/runtime option (as suggested here and here by zloirock):

options: {
  cacheDirectory: true,
  presets: [
    [
      '@babel/preset-env',
      {
        useBuiltIns: 'usage',
        targets: {
          browsers: ['> 0.25% and supports es6-module', 'not dead', 'Firefox ESR'],
        },
        corejs: {
          version: '3.35',
          proposals: true,
        },
      },
    ],
  ],
  plugins: [['@babel/plugin-transform-runtime']],
},

So I have a question: which are the differences between the two? I've seen that the code size grows with the first option, so I tend towards the second one, but I would like to know which are the pros and cons.

@nyngwang
Copy link

nyngwang commented Feb 2, 2024

So I have a question: which are the differences between the two? I've seen that the code size grows with the first option, so I tend towards the second one, but I would like to know which are the pros and cons.

@gtempesta-pixartprinting Let me1 save you a week with a link for a (IMOO, the only) clean summary: https://github.com/babel/babel-polyfills/?tab=readme-ov-file#history-and-motivation.

If you need my own words: Since you are probably not writing a library, follow your instinct:

[...] so I tend towards the second one

And you can (I guess that you haven't) read the comment above which mentioned the new way recommended by one of the maintainers:

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.

Footnotes

  1. just a nobody who had struggled with the same question for a month reading all related comments you can find on both babel/babel and babel/babel-polyfills.

@qiulang
Copy link
Author

qiulang commented Feb 4, 2024

@nicolo-ribaudo @nyngwang I hit another transpile vs polyfill problem that I am desperate to need some help, can you guys take a look ? useBuiltIns: 'usage' will only transpile but not polyfill my nuxt v2 app

Thanks a lot.

@gtempesta-pixartprinting

@nyngwang Ok so I will stick to the second configuration. Thank you for the explanation.

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

No branches or pull requests

5 participants