Comprehensive plugin loading, configuration management, and preset system for extensible JavaScript transformations with Babel's plugin architecture.
Functions for resolving and loading plugins by name or path.
/**
* Resolve plugin by name or path
* @param {string} name - Plugin name or path to resolve
* @returns {Object} Resolved plugin object
*/
function resolvePlugin(name);
/**
* Resolve preset by name or path
* @param {string} name - Preset name or path to resolve
* @returns {Object} Resolved preset object
*/
function resolvePreset(name);Usage Examples:
const babel = require("babel-core");
// Resolve plugin by name
const arrowPlugin = babel.resolvePlugin("transform-es2015-arrow-functions");
console.log(arrowPlugin); // Plugin object
// Resolve preset by name
const es2015Preset = babel.resolvePreset("es2015");
console.log(es2015Preset); // Preset configuration
// Use resolved plugins in transform
const result = babel.transform("const fn = () => 42;", {
plugins: [arrowPlugin]
});
console.log(result.code);Advanced option processing and normalization for complex plugin configurations.
/**
* Option Manager for processing transformation options
*/
class OptionManager {
/**
* Create new OptionManager instance
* @param {Logger} log - Logger instance (optional)
* @param {Pipeline} pipeline - Pipeline instance (optional)
*/
constructor(log, pipeline);
/**
* Initialize and normalize options
* @param {Object} opts - Raw options object
* @returns {Object} Normalized options
*/
init(opts);
/**
* Create bare options object with defaults
* @returns {Object} Default options object
*/
static createBareOptions();
/**
* Normalize plugin object
* @param {any} plugin - Plugin to normalize
* @param {string} loc - Plugin location for errors
* @param {number} i - Plugin index for errors
* @param {string} alias - Plugin alias
* @returns {Plugin} Normalized plugin instance
*/
static normalisePlugin(plugin, loc, i, alias);
}
// Access OptionManager
const OptionManager = babel.OptionManager;Usage Examples:
const babel = require("babel-core");
// Create option manager
const OptionManager = babel.OptionManager;
const optionManager = new OptionManager();
// Process raw options
const rawOptions = {
presets: ["es2015"],
plugins: ["transform-runtime"],
sourceMaps: true,
filename: "input.js"
};
const normalizedOptions = optionManager.init(rawOptions);
console.log(normalizedOptions); // Fully processed options
// Create default options
const defaultOptions = OptionManager.createBareOptions();
console.log(defaultOptions); // Default option setBabel Core exports a configuration schema object defining all available options.
/**
* Configuration schema object defining all available Babel options
*/
const options;Usage Examples:
const babel = require("babel-core");
// Access configuration schema
console.log(babel.options); // Configuration schema object
// Schema includes definitions for:
// - filename, filenameRelative, inputSourceMap
// - env, mode, retainLines, highlightCode
// - presets, plugins, babelrc, extends
// - ignore, only, sourceMaps, sourceType
// - parserOpts, generatorOpts, etc.
// Use schema for validation or tool integration
function validateBabelConfig(userConfig) {
const schema = babel.options;
// Validate user config against schema
for (const key in userConfig) {
if (!(key in schema)) {
console.warn(`Unknown option: ${key}`);
}
}
return userConfig;
}
const config = validateBabelConfig({
presets: ['es2015'],
sourceMaps: true,
filename: 'input.js'
});Detailed plugin and preset configuration patterns.
// Plugin configuration formats (multiple valid types):
// - string: Plugin name
// - Function: Plugin function
// - [string]: Plugin name in array
// - [string, Object]: Plugin with options
// - [Function, Object]: Plugin function with options
// - PluginObject: Direct plugin object
// PluginObject structure:
const pluginObject = {
visitor: Object, // VisitorObject with AST visitor methods
pre: Function, // Pre-transformation hook (optional)
post: Function, // Post-transformation hook (optional)
manipulateOptions: Function, // Option manipulation hook (optional)
inherits: Object, // Plugin inheritance (optional)
name: String // Plugin name (optional)
};
// VisitorObject structure:
const visitorObject = {
// Each nodeType can be:
// - Function (single visitor function)
// - { enter: Function, exit: Function } (enter/exit visitors)
// - Array<Function> (multiple visitors)
Identifier: Function,
FunctionDeclaration: {
enter: Function,
exit: Function
},
CallExpression: [Function, Function] // Multiple visitors
};Plugin Configuration Examples:
// String plugin names
{
plugins: [
"transform-es2015-arrow-functions",
"transform-es2015-classes"
]
}
// Plugin with options
{
plugins: [
["transform-es2015-modules-commonjs", {
allowTopLevelThis: true,
strict: false
}]
]
}
// Function plugin
{
plugins: [
function customPlugin(babel) {
const t = babel.types;
return {
visitor: {
Identifier(path) {
if (path.node.name === "oldName") {
path.node.name = "newName";
}
}
}
};
}
]
}
// Plugin object
{
plugins: [
{
visitor: {
CallExpression: {
enter(path) {
console.log("Entering call expression");
},
exit(path) {
console.log("Exiting call expression");
}
}
},
pre(file) {
console.log("Starting transformation of:", file.opts.filename);
},
post(file) {
console.log("Finished transformation of:", file.opts.filename);
}
}
]
}Preset system for bundling multiple plugins with shared configuration.
// Preset configuration formats
type PresetConfig =
| string // Preset name
| Function // Preset function
| [string] // Preset name in array
| [string, Object] // Preset with options
| [Function, Object] // Preset function with options
| PresetObject; // Direct preset object
interface PresetObject {
plugins?: Array<PluginConfig>; // Plugins in preset
presets?: Array<PresetConfig>; // Sub-presets
options?: Object; // Preset options
}Preset Configuration Examples:
// Basic preset usage
{
presets: ["es2015", "react"]
}
// Preset with options
{
presets: [
["es2015", {
modules: false, // Keep ES6 modules
loose: true // Use loose transformations
}],
["react", {
pragma: "h" // Use 'h' instead of React.createElement
}]
]
}
// Custom preset function
{
presets: [
function customPreset(context, options = {}) {
return {
plugins: [
"transform-es2015-arrow-functions",
"transform-es2015-classes",
options.includeRuntime ? "transform-runtime" : null
].filter(Boolean)
};
}
]
}
// Environment-specific presets
{
presets: [
["es2015", { modules: false }]
],
env: {
test: {
presets: [
["es2015", { modules: "commonjs" }] // CommonJS for testing
]
}
}
}// Complete plugin with all hooks
function myCustomPlugin(babel) {
const t = babel.types;
return {
name: "my-custom-plugin",
// Pre-transformation setup
pre(file) {
this.customData = new Map();
console.log("Processing file:", file.opts.filename);
},
// Visitor pattern for AST transformation
visitor: {
// Transform arrow functions
ArrowFunctionExpression(path) {
const { node } = path;
// Convert to function expression
const funcExpr = t.functionExpression(
null, // no name
node.params,
t.isExpression(node.body)
? t.blockStatement([t.returnStatement(node.body)])
: node.body
);
path.replaceWith(funcExpr);
},
// Track variable declarations
VariableDeclarator: {
enter(path) {
const name = path.node.id.name;
this.customData.set(name, path.node.init);
}
},
// Transform specific identifiers
Identifier(path) {
if (path.node.name === "DEBUG" && path.isReferencedIdentifier()) {
path.replaceWith(t.booleanLiteral(process.env.NODE_ENV !== 'production'));
}
}
},
// Post-transformation cleanup
post(file) {
console.log("Transformed variables:", Array.from(this.customData.keys()));
this.customData.clear();
},
// Manipulate parser options
manipulateOptions(opts, parserOpts) {
// Enable JSX parsing if not already enabled
if (!parserOpts.plugins.includes('jsx')) {
parserOpts.plugins.push('jsx');
}
}
};
}
// Use custom plugin
const result = babel.transform(code, {
plugins: [myCustomPlugin]
});// Plugin with options and state
function configurablePlugin(babel, options = {}) {
const t = babel.types;
const {
prefix = 'transformed_',
exclude = [],
verbose = false
} = options;
return {
visitor: {
Identifier: {
enter(path, state) {
// Access plugin options
const shouldTransform = !exclude.includes(path.node.name);
// Access file-level state
if (!state.transformedCount) {
state.transformedCount = 0;
}
if (shouldTransform && path.isReferencedIdentifier()) {
const newName = prefix + path.node.name;
path.node.name = newName;
state.transformedCount++;
if (verbose) {
console.log(`Transformed identifier: ${path.node.name} -> ${newName}`);
}
}
}
}
},
post(file) {
if (verbose) {
console.log(`Total transformations: ${file.transformedCount || 0}`);
}
}
};
}
// Usage with options
const result = babel.transform(code, {
plugins: [
[configurablePlugin, {
prefix: 'renamed_',
exclude: ['React', 'document'],
verbose: true
}]
]
});// EnvironmentConfig structure:
const environmentConfig = {
env: {
// Environment-specific configurations
development: {
plugins: Array, // Development plugins
presets: Array, // Development presets
sourceMaps: Boolean // Any other options
},
production: {
plugins: Array, // Production plugins
presets: Array, // Production presets
minified: Boolean // Any other options
},
test: {
plugins: Array, // Test plugins
presets: Array // Test presets
}
// Additional environments...
}
};Usage Examples:
// Environment-based configuration
const babelConfig = {
presets: [
["es2015", { modules: false }]
],
plugins: [
"transform-object-rest-spread"
],
env: {
// Development environment
development: {
plugins: [
"transform-react-jsx-source", // Add source info for debugging
"transform-react-jsx-self" // Add __self prop
]
},
// Production environment
production: {
plugins: [
"transform-react-remove-prop-types", // Remove PropTypes
"babel-plugin-transform-react-constant-elements" // Optimize React
]
},
// Test environment
test: {
presets: [
["es2015", { modules: "commonjs" }] // CommonJS for Jest
],
plugins: [
"transform-dynamic-import" // Transform dynamic imports
]
}
}
};
// Environment is determined by BABEL_ENV or NODE_ENV
process.env.NODE_ENV = 'production';
const result = babel.transform(code, babelConfig);// Dynamic plugin configuration
function createBabelConfig(options = {}) {
const plugins = [
"transform-object-rest-spread"
];
// Conditionally add plugins
if (options.includeRuntime) {
plugins.push(["transform-runtime", {
polyfill: false,
regenerator: true
}]);
}
if (options.optimizeReact) {
plugins.push(
"transform-react-constant-elements",
"transform-react-inline-elements"
);
}
if (options.removeConsole) {
plugins.push(["transform-remove-console", {
exclude: ["error", "warn"]
}]);
}
return {
presets: [
["es2015", { modules: options.modules || false }]
],
plugins
};
}
// Usage
const devConfig = createBabelConfig({
includeRuntime: true,
modules: "commonjs"
});
const prodConfig = createBabelConfig({
optimizeReact: true,
removeConsole: true
});// Plugin resolution follows these patterns:
const resolutionExamples = {
// Scoped plugins
"@babel/plugin-transform-arrow-functions": "@babel/plugin-transform-arrow-functions",
// Short names resolve to babel-plugin-*
"transform-arrow-functions": "babel-plugin-transform-arrow-functions",
// Relative paths
"./custom-plugin": "./custom-plugin.js",
// Absolute paths
"/path/to/plugin": "/path/to/plugin.js",
// Node modules
"my-babel-plugin": "my-babel-plugin"
};
// Preset resolution follows similar patterns with babel-preset-* prefix// Plugin loading error handling
try {
const result = babel.transform(code, {
plugins: ["nonexistent-plugin"]
});
} catch (err) {
if (err.message.includes('Cannot resolve plugin')) {
console.error('Plugin not found:', err.message);
// Fallback configuration
const fallbackResult = babel.transform(code, {
presets: ["es2015"] // Use preset instead
});
}
}
// Preset loading error handling
try {
const result = babel.transform(code, {
presets: ["invalid-preset"]
});
} catch (err) {
if (err.message.includes('Cannot resolve preset')) {
console.error('Preset not found:', err.message);
}
}