core-js/stable vs core-js/actual for shared library polyfills
0 reputation · 06 Oct 2021, 16:10 UTC
0 reputation · 06 Oct 2021, 16:10 UTC
When developing a shared library intended for diverse environments, there is a tension between providing necessary polyfills and avoiding side effects in the host application. Core-js provides two primary documented paths for this: core-js/stable, which patches global objects, and core-js/actual, which provides polyfills as module bindings without mutating the global namespace.
Using core-js/stable ensures that all scripts on the page, including third-party dependencies, have access to the patched built-ins. However, this mutates globalThis, which may violate the constraints of a side-effect-free library. Conversely, core-js/actual keeps the library isolated and tree-shakeable, but it provides no coverage for other scripts in the bundle graph that may assume these globals exist.
Since core-js resolves to native implementations when they are correct, mixing these namespaces does not create duplicate identities on modern engines. However, on legacy engines, the boundary between global and explicit polyfills remains a manual architectural decision with no tooling to enforce consistency across a dependency graph.
core-js/actual and delegating global patching to the host application?1️⃣ Yes – a side‑effect‑free library should use core-js/actual and let the host decide whether to patch globals. 2️⃣ To satisfy its own internal dependencies, the library should import only the polyfills it needs from core-js/actual and keep those imports explicit.
core-js/actual is the safer defaultglobalThis untouched.core-js/stable or patches globals itself.Array.flat, Promise.allSettled).core-js/actual:
import 'core-js/actual/array/flat';
import 'core-js/actual/promise/all-settled';
sideEffects: false in package.json or use sideEffects: ['**/*.js'] for polyfill modules.@rollup/plugin-node-resolve with preferBuiltins: false and external: [] for polyfills.core-js/actual imports as side‑effect‑free.Array.prototype.flat is available in your library’s scope but globalThis.flat remains undefined unless the host imports core-js/stable.
export function installGlobals() {
import('core-js/stable');
}
This keeps the decision in the consumer’s hands.core-js/stable inside the libraryIn those rare cases, document the side effect clearly and provide a --no-global build flag that skips the global patching.
Do you need the library to support browsers older than ES2019 (e.g., IE11, Edge 14)? That would influence whether you keep the global patching strategy or provide a dedicated legacy bundle.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.