@babel/plugin-transform-modules-systemjs is a Babel plugin that transforms ES2015 (ES6) module syntax to SystemJS format, enabling dynamic module loading in environments that don't natively support ES modules. The plugin converts import/export statements into SystemJS register calls, handling various module patterns including default exports, named exports, namespace imports, and export-all declarations.
npm install --save-dev @babel/plugin-transform-modules-systemjsimport transformModulesSystemJS from "@babel/plugin-transform-modules-systemjs";
// Also exports utility function
import { getExportSpecifierName } from "@babel/plugin-transform-modules-systemjs";For CommonJS:
const transformModulesSystemJS = require("@babel/plugin-transform-modules-systemjs");
const { getExportSpecifierName } = require("@babel/plugin-transform-modules-systemjs");// babel.config.js
module.exports = {
plugins: ["@babel/plugin-transform-modules-systemjs"]
};With options:
// babel.config.js
module.exports = {
plugins: [
["@babel/plugin-transform-modules-systemjs", {
systemGlobal: "System",
allowTopLevelThis: false
}]
]
};Input (ES2015 modules):
import { helper } from './helper';
export const value = 42;
export default function main() {
return helper() + value;
}Output (SystemJS):
System.register(["./helper"], function (_export, _context) {
"use strict";
var helper;
return {
setters: [function (_helper) {
helper = _helper.helper;
}],
execute: function () {
const value = 42;
_export("value", value);
function main() {
return helper() + value;
}
_export("default", main);
}
};
});The default export is the main Babel plugin function that performs the module transformation.
import type { PluginObj, PluginPass } from "@babel/core";
/**
* Main Babel plugin function that transforms ES2015 modules to SystemJS format
* @param api - Babel API object with version assertion and types
* @param options - Plugin configuration options
* @returns Babel plugin object with visitor methods
*/
declare function transformModulesSystemJS(
api: any,
options?: Options
): PluginObj<PluginPass & PluginState>;
interface PluginState {
/** Context identifier used in SystemJS output */
contextIdent: string;
/** Set of string specifiers that cannot be converted to identifiers */
stringSpecifiers: Set<string>;
}Helper function to extract export specifier names from AST nodes, handling both identifier and string literal specifiers.
import type { Node, Identifier, StringLiteral } from "@babel/types";
/**
* Helper function to extract export specifier names from AST nodes
* @param node - Babel AST node (Identifier or StringLiteral)
* @param stringSpecifiers - Set to track string-based specifiers
* @returns String name of the export specifier
* @throws Error if node is not Identifier or StringLiteral
*/
function getExportSpecifierName(
node: Identifier | StringLiteral,
stringSpecifiers: Set<string>
): string;The plugin uses internal template functions for generating SystemJS output structure.
import type { NodePath, Expression } from "@babel/core";
/**
* Internal function that constructs export call statements for SystemJS
* Used internally by the plugin to generate proper export syntax
* @internal
*/
function constructExportCall(
path: NodePath<t.Program>,
exportIdent: t.Identifier,
exportNames: string[],
exportValues: t.Expression[],
exportStarTarget: t.Identifier | null,
stringSpecifiers: Set<string>
): t.Statement[];import type { PluginOptions } from "@babel/helper-module-transforms";
interface Options extends PluginOptions {
/**
* Allow top-level `this` usage in transformed modules.
* When false, replaces `this` with `undefined` in module scope.
* @default false
*/
allowTopLevelThis?: boolean;
/**
* Name of the SystemJS global variable to use in output.
* Changes `System.register()` to `[systemGlobal].register()`.
* @default "System"
*/
systemGlobal?: string;
}The plugin handles various ES module constructs:
import foo from 'module'import { foo, bar } from 'module'import * as foo from 'module'import 'module'export default valueexport { foo, bar }export const foo = 'value'export { foo } from 'module'export * from 'module'import('./module') → _context.import('./module')import.meta → _context.meta__moduleName → _context.idSupports string literal specifiers for compatibility with non-standard module names:
import { "any unicode" as foo } from "some-module";
export { "special-name" as bar };The plugin detects top-level await expressions and generates async SystemJS execute functions:
// Input
const data = await fetch('/api/data');
export { data };
// Output (simplified)
System.register([], function (_export, _context) {
return {
setters: [],
execute: async function () {
const data = await fetch('/api/data');
_export("data", data);
}
};
});Automatically updates exports when exported variables are reassigned:
// Input
export let counter = 0;
counter++; // This will trigger export update
// Output includes automatic re-export callsThe plugin includes specific error handling for:
@babel/plugin-transform-dynamic-import@babel/plugin-transform-dynamic-importapi.assertVersion()/** Warning message shown in Babel 7 when dynamic import plugin is missing */
const MISSING_PLUGIN_WARNING: string;
/** Error message shown in Babel 8 when dynamic import plugin is missing */
const MISSING_PLUGIN_ERROR: string;The plugin depends on the following @babel packages:
@babel/helper-module-transforms: Core module transformation utilities@babel/helper-plugin-utils: Plugin utility functions (declare function)@babel/helper-validator-identifier: Identifier name validation@babel/traverse: AST traversal (conditional dependency)@babel/core: Core Babel functionality (peer dependency)The plugin generates SystemJS modules using the standard System.register format:
System.register(
[/* dependency array */],
function (_export, _context) {
"use strict";
/* variable declarations */
return {
setters: [/* setter functions for dependencies */],
execute: function () {
/* module code */
}
};
}
);This format enables: