What do we need to make `usage-global` injection work with `@babel/runtime`?
💻
- [ ] Would you like to work on this feature?
What problem are you trying to solve?
@nyngwang has been going around a bit checking how our polyfill injection works (thank you very much!), and after going through their comments I realized that our injection story for usage-global is pretty bad when it comes to helpers.
If you have this config:
{
"plugins": [
"@babel/transform-runtime"
]
}
Babel will inject imports for helpers like import _typeof from "@babel/runtime/helpers/typeof".
Then you decide that you want to inject global polyfills through core-js, so you update your config to this:
{
"plugins": [
"@babel/transform-runtime",
["babel-plugin-polyfill-corejs3", { "method": "usage-global" }]
]
}
now Babel will inject imports like import "core-js/modules/es.array.flat.js";, but suddently your imports for helpers will become import "@babel/runtime-corejs3/helpers/typeof" (which depends on core-js-pure). This is to make sure that the helpers are also polyfilled, but:
- you asked for global-modifying polyfills, and now in your dependencies you have both
core-jsandcore-js-pure - injecting global polyfills forced you to change one of your dependencies.
If you still want to use @babel/runtime (because @babel/runtime-corejs3 includes polyfills down to ES5), you have to instead use this config:
{
"plugins": [
["@babel/transform-runtime", { "moduleName": "@babel/runtime" }],
["babel-plugin-polyfill-corejs3", { "method": "usage-global" }]
]
}
NOTE: I think this behavior is good when it comes to
usage-pure, because we are just changing the@babel/runtimeimports to a different package that uses exactly the pure polyfill the user asked for.
Describe the solution you'd like
What if for each helper we maintained the list of built-ins that it relies on, and when injecting a import "@babel/runtime/typeof/helpers" we called the polyfill provider saying "hey, we included a helper that uses Symbol and Array.prototype.flat: if needed for the configured target, consider injecting imports to these polyfills".
Then, when compiling typeof foo and using ["babel-plugin-polyfill-corejs3", { "method": "usage-global" }], we would generate some code like
import "core-js/modules/es.symbol.js";
import _typeof from "@babel/runtime/helpers/typeof";
_typeof(foo);
rather than
import _typeof from "@babel/runtime-corejs3/helpers/typeof";
_typeof(foo);
This list would probably need to be manually-maintained by us for each helper, and:
- we could try linting using our existing polyfill provider infrastructure, to make sure that we aren't missing any builtin in our list
- even if we change the helper to not rely on X anymore, we still need to include X in the list of features for compatibility with older
@babel/runtimeversions
Describe alternatives you've considered
Do nothing
Documentation, Adoption, Migration Strategy
No response
I don't remember how internally works @babel/transform-runtime, but what about a naive solution like this?
- Inject a helper as usually, without runtime
- Inject
core-jspolyfills viababel-plugin-polyfill-corejs3for code and this helper as usually - Just replace this helper to import from runtime
It looks slower than the predefined list of dependencies but simpler for maintenance.
As I'm a naive user, I like what @zloirock proposed as it has the following two advantages:
- No more confusion about why "my code" does not include those extracted helpers when adding polyfills for my code. (If the link does not highlight the specific sentence, please search the page with:
but with that config babel includes polyfills when you use that feature in your code!)- In short, they tried to teach people that the option
useBuiltIns: 'usage'might miss some polyfills because "code of helpers" is not included in "my code" when determining what needs to be polyfilled. It was very frustrating when I tried to understand the entire thread. The thread is still open btw.
- In short, they tried to teach people that the option
- It can be easily explained/documented in one simple sentence without leaky abstractions:
babel-plugin-polyfill-corejs3will add all polyfills you need to run your app/library for your browser targets.@babel/transform-runtimewill extract helpers. Extracting it or not has nothing to do with whether my app/library will be polyfilled correctly.