preset-env useBuiltIns and corejs: pinning the installed core-js major for compiled files
0 reputation · 04 Aug 2023, 16:25 UTC
0 reputation · 04 Aug 2023, 16:25 UTC
In the @babel/core 7.x line, @babel/preset-env can inject polyfills through useBuiltIns, but the corejs option must name a version that matches the core-js package actually installed. With useBuiltIns: 'usage', Babel rewrites each file it compiles to import only the core-js modules that file's syntax requires; with 'entry', it expands a single core-js/stable import. Babel errors when useBuiltIns is set without a corejs version, yet a version string that does not match the installed package can still produce resolution failures or target the wrong polyfill set.
The unresolved policy decision is where polyfills belong: preset-env's global injection with core-js as a runtime dependency, or transform-runtime's per-module imports via @babel/runtime-corejs3, which avoids global pollution but adds a heavier runtime package. A related boundary is that 'usage' only patches files Babel compiles, leaving untranspiled node_modules unpatched.
Which placement fits a library versus an application? How should the corejs option be kept in step with the installed core-js major? Does debug: true reveal enough to confirm the resolved targets and core-js version?
35275 reputation · 04 Aug 2023, 17:42 UTC
The choice between @babel/preset-env and @babel/plugin-transform-runtime depends on who controls the global environment.
Applications should use @babel/preset-env with useBuiltIns: 'usage' or 'entry'. Because the application is the final entry point, it is responsible for patching the global environment (e.g., window.Promise) to ensure all dependencies—including those in node_modules—can execute. core-js should be listed as a production dependency.
Libraries should use @babel/plugin-transform-runtime with the corejs: 3 option. This replaces global references with aliased imports (e.g., _corejs_pure_promise), preventing the library from polluting the global scope of the application that consumes it. In this setup, @babel/runtime-corejs3 is added as a dependency.
To prevent resolution failures or the injection of outdated polyfills, the corejs option in your Babel configuration must match the major (and ideally minor) version installed in your package.json.
Configuration Example:
// babel.config.json
{
"presets": [
[
"@babel/preset-env",
{
"useBuiltIns": "usage",
"corejs": "3.38", // Pin to the installed minor version
"targets": "defaults"
}
]
]
}
If you specify "corejs": 3, Babel defaults to 3.0, which may miss newer polyfills available in your installed version. Specifying the minor version (e.g., "3.38") ensures Babel utilizes the full feature set of the installed package.
Setting debug: true within @babel/preset-env provides a detailed console output during compilation. It confirms:
browserslist.core-js modules being injected into each file.If the debug output shows polyfills being injected that are missing from your node_modules, or if the bundle fails to resolve a module, there is a mismatch between your corejs config string and the installed version.
package.json for the installed core-js version.babel.config.json.debug: true and verify the "Polyfills" section of the log.Note: To provide a more specific recommendation on useBuiltIns: 'usage', please specify if you are using a bundler (like Webpack or Vite) that excludes node_modules from the Babel loader.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.