A Babel plugin that transforms ES2015 (ES6) module syntax to Universal Module Definition (UMD) format, enabling JavaScript modules to work across different module systems including AMD, CommonJS, and browser globals.
npm install --save-dev babel-plugin-transform-es2015-modules-umdThis is a Babel plugin that is configured rather than imported directly in user code:
For Babel configuration (.babelrc):
{
"plugins": ["transform-es2015-modules-umd"]
}For importing the plugin module itself:
const umdPlugin = require("babel-plugin-transform-es2015-modules-umd");For ES modules:
import umdPlugin from "babel-plugin-transform-es2015-modules-umd";Via Node API:
require("babel-core").transform("code", {
plugins: ["transform-es2015-modules-umd"]
});Via CLI:
babel --plugins transform-es2015-modules-umd script.jsInput ES2015:
export default 42;Output UMD:
(function (global, factory) {
if (typeof define === "function" && define.amd) {
define(["exports"], factory);
} else if (typeof exports !== "undefined") {
factory(exports);
} else {
var mod = { exports: {} };
factory(mod.exports);
global.actual = mod.exports;
}
})(this, function (exports) {
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = 42;
});Input ES2015:
import * as foo from "foo";
foo.bar();Output UMD:
(function (global, factory) {
if (typeof define === "function" && define.amd) {
define(["foo"], factory);
} else if (typeof exports !== "undefined") {
factory(require("foo"));
} else {
var mod = { exports: {} };
factory(global.foo);
global.actual = mod.exports;
}
})(this, function (_foo) {
"use strict";
var foo = babelHelpers.interopRequireWildcard(_foo);
foo.bar();
});This plugin extends babel-plugin-transform-es2015-modules-amd and wraps AMD module output with a UMD factory pattern. The transformation process:
babel-plugin-transform-es2015-modules-amdThe plugin requires the following dependencies:
/**
* Core dependencies used by the plugin
*/
const dependencies = {
"babel-plugin-transform-es2015-modules-amd": "^6.24.1", // Base AMD transformation
"babel-template": "^6.24.1", // Template building utilities
"babel-runtime": "^6.22.0" // Babel runtime helpers
};Main plugin factory function exported as the default export that returns a Babel plugin configuration.
/**
* Main plugin factory function
* @param {Object} params - Babel plugin parameters
* @param {Object} params.types - Babel types utility (t)
* @returns {Object} Babel plugin configuration with visitor pattern
*/
export default function ({ types: t }) {
function isValidDefine(path) {
// Validates AMD define call structure
}
return {
inherits: require("babel-plugin-transform-es2015-modules-amd"),
visitor: {
Program: {
exit(path, state) {
// Transform AMD output to UMD pattern
}
}
}
};
}Internal template builders used to generate UMD wrapper code.
/**
* Template for prerequisite assignments in nested global namespace creation
*/
const buildPrerequisiteAssignment = template(`
GLOBAL_REFERENCE = GLOBAL_REFERENCE || {}
`);
/**
* Template for global export section in UMD wrapper
*/
const buildGlobalExport = template(`
var mod = { exports: {} };
factory(BROWSER_ARGUMENTS);
PREREQUISITE_ASSIGNMENTS
GLOBAL_TO_ASSIGN = mod.exports;
`);
/**
* Template for complete UMD wrapper pattern
*/
const buildWrapper = template(`
(function (global, factory) {
if (typeof define === "function" && define.amd) {
define(MODULE_NAME, AMD_ARGUMENTS, factory);
} else if (typeof exports !== "undefined") {
factory(COMMON_ARGUMENTS);
} else {
GLOBAL_EXPORT
}
})(this, FUNC);
`);Internal helper function that validates AMD define call structure.
/**
* Validates whether a path represents a valid AMD define call
* @param {Object} path - Babel AST path
* @returns {boolean} True if path is a valid define call
*/
function isValidDefine(path) {
if (!path.isExpressionStatement()) return;
const expr = path.get("expression");
if (!expr.isCallExpression()) return false;
if (!expr.get("callee").isIdentifier({ name: "define" })) return false;
const args = expr.get("arguments");
if (args.length === 3 && !args.shift().isStringLiteral()) return false;
if (args.length !== 2) return false;
if (!args.shift().isArrayExpression()) return false;
if (!args.shift().isFunctionExpression()) return false;
return true;
}Maps module names to global variable names for the browser environment. When not using exactGlobals, uses module basename for mapping. When using exactGlobals, uses full import string.
/**
* Configuration option for mapping module names to global variables
* @type {Object<string, string>}
* @default {}
*/
const globals = {
"module-name": "GlobalVariableName",
"foo-bar": "fooBAR",
"./mylib/foo-bar": "mylib.fooBar"
};Usage:
{
"plugins": [
["transform-es2015-modules-umd", {
"globals": {
"es6-promise": "Promise",
"lodash": "_"
}
}]
]
}Enables exact global name matching and member expression support.
/**
* Configuration option for exact global name handling
* @type {boolean}
* @default false
*/
const exactGlobals = false;When exactGlobals: true:
"MyNamespace.MyLib")toIdentifier transformationUsage:
{
"plugins": [
["transform-es2015-modules-umd", {
"globals": {
"my/custom/module": "My.Custom.Module"
},
"exactGlobals": true
}]
]
}The plugin returns a standard Babel plugin configuration object.
/**
* @typedef {Object} BabelPlugin
* @property {Object} inherits - Inherits functionality from AMD plugin
* @property {Object} visitor - Visitor pattern for AST transformation
* @property {Object} visitor.Program - Program visitor
* @property {Function} visitor.Program.exit - Exit handler for Program node
*/
/**
* @typedef {Object} PluginState
* @property {Object} opts - Plugin configuration options
* @property {Object<string, string>} [opts.globals] - Global variable mapping
* @property {boolean} [opts.exactGlobals=false] - Enable exact global matching
* @property {Object} file - Babel file information
* @property {Object} file.opts - File options
* @property {string} file.opts.basename - Current file basename
*/By default, the plugin uses module basenames for global variables:
// Multiple imports with same basename
import fooBar1 from "foo-bar";
import fooBar2 from "./mylib/foo-bar";Both resolve to the same global:
factory(global.fooBar, global.fooBar);Override global names using the globals option:
{
"plugins": [
["transform-es2015-modules-umd", {
"globals": {
"es6-promise": "Promise",
"jquery": "$",
"lodash": "_"
}
}]
]
}Enable member expressions and full import string matching:
{
"plugins": [
["transform-es2015-modules-umd", {
"globals": {
"foo-bar": "fooBAR",
"./mylib/foo-bar": "mylib.fooBar"
},
"exactGlobals": true
}]
]
}Output:
factory(global.fooBAR, global.mylib.fooBar);With exactGlobals: true, you can override the exported global name:
{
"plugins": [
["transform-es2015-modules-umd", {
"globals": {
"my/custom/module/name": "My.Custom.Module.Name"
},
"exactGlobals": true
}]
],
"moduleId": "my/custom/module/name"
}Output includes namespace creation:
global.My = global.My || {};
global.My.Custom = global.My.Custom || {};
global.My.Custom.Module = global.My.Custom.Module || {};
global.My.Custom.Module.Name = mod.exports;The plugin performs validation on AMD define calls:
define function callsInvalid define calls are left unchanged, preventing malformed UMD output.