A Babel plugin to inject imports to core-js@3 polyfills based on usage patterns and browser compatibility targets
npx @tessl/cli install tessl/npm-babel-plugin-polyfill-corejs3@0.13.0A Babel plugin that provides automated polyfill injection for core-js@3, enabling selective loading of JavaScript polyfills based on compilation targets and actual usage in code. It analyzes code usage patterns and browser compatibility requirements to determine which ES6+ features need polyfilling for older browsers.
npm install --save-dev babel-plugin-polyfill-corejs3// Plugin is used via Babel configuration, not direct imports
// Add to babel.config.js or .babelrc.json:
{
"plugins": [["polyfill-corejs3", options]]
}The plugin is built using @babel/helper-define-polyfill-provider and depends on core-js-compat for polyfill data.
// babel.config.js
module.exports = {
plugins: [
["polyfill-corejs3", {
method: "usage-global",
version: "3.43"
}]
]
};// .babelrc.json
{
"plugins": [
["polyfill-corejs3", {
method: "usage-pure",
version: require("core-js-pure/package.json").version
}]
]
}The plugin is built using the @babel/helper-define-polyfill-provider framework, which provides a standardized pattern for polyfill injection plugins. It returns a provider object that Babel calls during transformation.
The plugin operates through three main injection methods:
The plugin integrates with Babel's compilation pipeline to transform code based on:
Main Babel plugin function that returns a polyfill provider.
/**
* Creates a Babel plugin for core-js@3 polyfill injection using defineProvider
* @param options - Plugin configuration options
* @returns Babel polyfill provider plugin object
*/
export default function(options: Options): PolyfillProvider;
interface Options {
/** core-js version to target (default: 3) */
version?: number | string;
/** Include ES proposals (default: false) */
proposals?: boolean;
/** Include shipped proposals (default: false) */
shippedProposals?: boolean;
}
interface PolyfillProvider {
/** Plugin identifier */
name: "corejs3";
/** Babel runtime name for integration */
runtimeName: string | null;
/** Available polyfills data from core-js-compat */
polyfills: object;
/** Filter function to determine which polyfills to include */
filterPolyfills(name: string): boolean;
/** Handle entry-global method transformation */
entryGlobal(meta: ImportMeta, utils: TransformUtils, path: NodePath): void;
/** Handle usage-global method transformation */
usageGlobal(meta: FeatureMeta, utils: TransformUtils, path: NodePath): boolean | void;
/** Handle usage-pure method transformation */
usagePure(meta: FeatureMeta, utils: TransformUtils, path: NodePath): void;
/** Babel visitor for AST transformation (usage-global method only) */
visitor?: {
CallExpression(path: NodePath): void;
Function(path: NodePath): void;
"ForOfStatement|ArrayPattern"(path: NodePath): void;
SpreadElement(path: NodePath): void;
YieldExpression(path: NodePath): void;
Class(path: NodePath): void;
};
}Usage Examples:
// Basic usage-global configuration
{
plugins: [
["polyfill-corejs3", {
method: "usage-global",
version: "3.43"
}]
]
}
// Library author configuration with version from package.json
{
plugins: [
["polyfill-corejs3", {
method: "usage-pure",
version: require("core-js-pure/package.json").version,
proposals: false
}]
]
}
// Application bundle with proposals enabled
{
plugins: [
["polyfill-corejs3", {
method: "entry-global",
version: require("core-js/package.json").version,
proposals: true,
shippedProposals: true
}]
]
}The plugin supports three injection methods controlled by Babel configuration:
Analyzes code usage patterns and injects global polyfills for detected ES6+ features.
/**
* Handles usage-global method transformation
* Injects global polyfills based on detected feature usage
* @param meta - Metadata about the detected feature
* @param utils - Babel transformation utilities
* @param path - AST node path
* @returns true if polyfill was injected, void otherwise
*/
usageGlobal(meta: FeatureMeta, utils: TransformUtils, path: NodePath): boolean | void;Injects pure (non-global) polyfill imports that don't modify global objects.
/**
* Handles usage-pure method transformation
* Injects pure polyfill imports without modifying globals
* @param meta - Metadata about the detected feature
* @param utils - Babel transformation utilities
* @param path - AST node path
*/
usagePure(meta: FeatureMeta, utils: TransformUtils, path: NodePath): void;Replaces existing core-js import statements with specific polyfill imports.
/**
* Handles entry-global method transformation
* Replaces core-js imports with specific polyfill imports
* @param meta - Import metadata
* @param utils - Babel transformation utilities
* @param path - AST node path
*/
entryGlobal(meta: ImportMeta, utils: TransformUtils, path: NodePath): void;Specifies the core-js version to target for polyfill compatibility.
interface VersionOption {
/** core-js version to target (default: "3.0") */
version?: number | string;
}Usage Examples:
// Using specific version
{
version: "3.43.0"
}
// Using version from package.json for applications
{
version: require("core-js/package.json").version
}
// Using version from package.json for libraries
{
version: require("core-js-pure/package.json").version
}Controls whether ES proposals are included in polyfill injection.
interface ProposalsOption {
/** Include ES proposals (default: false) */
proposals?: boolean;
}Controls whether shipped proposals are included in polyfill injection.
interface ShippedProposalsOption {
/** Include shipped proposals (default: false) */
shippedProposals?: boolean;
}Core utility functions used internally by the plugin for transformation logic.
/**
* Generates the full module path for a core-js polyfill
* @param name - Polyfill name (e.g., "es.array.includes")
* @returns Full module path (e.g., "core-js/modules/es.array.includes.js")
*/
function coreJSModule(name: string): string;
/**
* Generates pure helper import path for core-js features
* @param name - Helper name
* @param useBabelRuntime - Whether to use @babel/runtime-corejs3
* @param ext - File extension
* @returns Import path for pure helper
*/
function coreJSPureHelper(name: string, useBabelRuntime: boolean, ext: string): string;
/**
* Checks if a source string is a core-js import
* @param source - Import source string
* @returns Array of polyfill names if core-js source, false otherwise
*/
function isCoreJSSource(source: string): string[] | false;/**
* Transforms method calls with proper context handling
* @param path - AST node path
* @param id - Identifier to call
* @param optionalCall - Whether call should be optional
* @param wrapCallee - Optional function to wrap callee
*/
function callMethod(
path: NodePath,
id: t.Identifier,
optionalCall?: boolean,
wrapCallee?: (callee: t.Expression) => t.Expression
): void;
/**
* Memoizes object context for safe transformations
* @param node - Member expression node
* @param scope - Babel scope
* @returns Tuple of context expressions
*/
function maybeMemoizeContext(
node: t.MemberExpression | t.OptionalMemberExpression,
scope: NodePath["scope"]
): [t.Expression, t.Expression];
/**
* Extracts optional chaining check logic
* @param scope - Babel scope
* @param node - Optional member expression node
* @returns Function that wraps expression with null check
*/
function extractOptionalCheck(
scope: NodePath["scope"],
node: t.OptionalMemberExpression
): (expr: t.Expression) => t.ConditionalExpression;/** Babel runtime package name for core-js@3 integration */
const BABEL_RUNTIME: "@babel/runtime-corejs3";interface CoreJSPolyfillDescriptor {
/** Polyfill name */
name: string;
/** Pure import path (null if not available) */
pure: string | null;
/** Array of global polyfill dependencies */
global: string[];
/** Array of excluded patterns (null if none) */
exclude: string[] | null;
}
/** Built-in constructor polyfills */
const BuiltIns: { [key: string]: CoreJSPolyfillDescriptor };
/** Static method polyfills */
const StaticProperties: { [key: string]: { [key: string]: CoreJSPolyfillDescriptor } };
/** Instance method polyfills */
const InstanceProperties: { [key: string]: { [key: string]: CoreJSPolyfillDescriptor } };
/** Common iterator polyfills */
const CommonIterators: string[];
/** Promise-related polyfills */
const PromiseDependencies: string[];
/** Promise polyfills with iterator support */
const PromiseDependenciesWithIterators: string[];
/** Decorator metadata polyfills */
const DecoratorMetadataDependencies: string[];/** Supported stable @babel/runtime-corejs3 paths */
const stable: Set<string>;
/** Supported proposal @babel/runtime-corejs3 paths */
const proposals: Set<string>;/** Set of shipped proposal polyfill names auto-generated from core-js */
const shippedProposalsList: Set<string>;/**
* Determines if specific polyfills can be skipped based on usage patterns
* @param desc - Polyfill descriptor
* @param path - AST node path
* @returns true if polyfill can be skipped
*/
function canSkipPolyfill(desc: CoreJSPolyfillDescriptor, path: NodePath): boolean;interface FeatureMeta {
kind: "global" | "static" | "instance" | "property" | "in";
object?: string;
property?: string;
key?: string;
placement?: "prototype" | "static";
}
interface ImportMeta {
kind: "import";
source: string;
}
interface TransformUtils {
injectGlobalImport(source: string, name: string): void;
injectDefaultImport(source: string, hint: string): t.Identifier;
}
type NodePath = import("@babel/traverse").NodePath;
type t = typeof import("@babel/types");