or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.md
tile.json

tessl/npm-babel-plugin-add-module-exports

Babel plugin that fixes CommonJS default export behavior by adding module.exports = exports.default when only a default export exists

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/babel-plugin-add-module-exports@1.0.x

To install, run

npx @tessl/cli install tessl/npm-babel-plugin-add-module-exports@1.0.0

index.mddocs/

babel-plugin-add-module-exports

A Babel plugin that fixes CommonJS default export behavior by adding module.exports = exports.default when only a default export exists. This plugin restores the Babel 5 behavior, eliminating the need to use .default when requiring modules in Node.js.

Package Information

  • Package Name: babel-plugin-add-module-exports
  • Package Type: npm
  • Language: JavaScript
  • Installation: npm install babel-plugin-add-module-exports --save-dev

Core Imports

This is a Babel plugin, not a runtime library. It's used in Babel configuration files:

{
  "plugins": ["add-module-exports"]
}

Basic Usage

Add the plugin to your Babel configuration to automatically fix CommonJS default exports:

{
  "presets": ["@babel/preset-env"],
  "plugins": ["add-module-exports"]
}

Input code:

export default 'foo';

Without plugin output:

'use strict';
Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = 'foo';

With plugin output:

'use strict';
Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = 'foo';
module.exports = exports.default;

Result: require('./bundle.js') returns 'foo' instead of { default: 'foo' }

Architecture

The plugin operates through Babel's plugin lifecycle system with several key architectural components:

  • Plugin Lifecycle Integration: Uses Babel's visitor pattern for initial setup and post-transformation hook for code generation
  • AST Analysis Engine: The ExportsFinder class analyzes the entire module structure to detect export patterns
  • Transformation Decision Logic: Applies transformations only when strict conditions are met (only default export, no named exports, etc.)
  • Code Generation: Uses Babel's template system to generate module.exports statements after module transformation is complete

Plugin Execution Flow

  1. Setup Phase: The visitor.Program method captures plugin options from the transformation state
  2. Analysis Phase: The post hook traverses the transformed AST to find exports.default patterns
  3. Decision Phase: ExportsFinder determines if transformation conditions are met
  4. Generation Phase: Template system generates and injects module.exports statements

This architecture ensures the plugin works correctly with Babel's module transformation pipeline while avoiding conflicts with other module formats and transformation steps.

Capabilities

Babel Plugin Factory

The main export is a Babel plugin factory function that creates a plugin configuration.

/**
 * Babel plugin factory function
 * @param {Object} babel - Babel instance with template helper
 * @param {Function} babel.template - Template helper for AST generation
 * @returns {BabelPluginConfig} Plugin configuration object
 */
function babelPluginAddModuleExports({ template }): BabelPluginConfig;

interface BabelPluginConfig {
  /** AST visitor configuration */
  visitor: {
    /** Captures plugin options from transformation state */
    Program(path: any, state: { opts: PluginOptions }): void;
  };
  /** Post-transformation hook that adds module.exports statements */
  post(fileMap: { path: any }): void;
}

Plugin Options

Configuration options that can be passed to the plugin.

interface PluginOptions {
  /** 
   * When true, adds both module.exports = exports.default and 
   * module.exports.default = exports.default for backward compatibility
   * @default false
   */
  addDefaultProperty?: boolean;
}

Usage with options:

{
  "presets": ["@babel/preset-env"],
  "plugins": [
    ["add-module-exports", { "addDefaultProperty": true }]
  ]
}

When addDefaultProperty is true, the plugin generates:

module.exports = exports.default;
module.exports.default = exports.default;

Transformation Behavior

The plugin applies transformations based on specific conditions:

Conditions for Transformation

  1. Only default export exists: Plugin only acts when exports.default is the only export
  2. No named exports: Presence of named exports (e.g., export const foo = 'bar') prevents transformation
  3. No existing module.exports: Plugin skips if module.exports is already assigned
  4. Not AMD module: Plugin skips AMD-wrapped code to avoid conflicts
  5. CommonJS or UMD modules: Works with CommonJS and UMD module formats only

Supported Export Patterns

// ✅ Transformed - only default export
export default 'value';
export default function() {};
export default { key: 'value' };

// ❌ Not transformed - has named exports
export default 'value';
export const named = 'other';

// ❌ Not transformed - already has module.exports
export default 'value';
module.exports = something;

// ❌ Not transformed - ES modules (modules: false)
export default 'value'; // when using { modules: false }

Module Format Support

/**
 * Supported Babel module transform formats
 */
type SupportedModuleFormats = 'commonjs' | 'umd' | 'cjs';

/**
 * Unsupported formats (plugin will skip transformation)
 */
type UnsupportedModuleFormats = 'amd' | 'systemjs' | false;

Detection Logic

The plugin uses internal analysis to determine when to apply transformations:

Export Pattern Detection

The plugin detects these export patterns:

  • Direct assignment: exports.default = value
  • Object.defineProperty: Object.defineProperty(exports, "default", ...)
  • Variations with _exports identifier

AST Visitor Patterns

/**
 * AST visitor patterns handled by the plugin
 */
interface VisitorPatterns {
  /** Handles Object.defineProperty(exports, "default", ...) calls */
  CallExpression: (path: any) => void;
  /** Handles exports.default = value assignments */
  AssignmentExpression: (path: any) => void;
}

Error Handling

The plugin handles edge cases gracefully:

  • Malformed exports: Silently skips transformation for invalid patterns
  • AMD conflicts: Automatically detects and avoids AMD module conflicts
  • Multiple transformations: Handles duplicate plugin references safely
  • No exceptions: Plugin never throws errors during normal operation

Integration Examples

With Webpack

{
  "presets": [["@babel/preset-env", { "modules": "commonjs" }]],
  "plugins": ["add-module-exports"]
}

With TypeScript

{
  "presets": ["@babel/preset-env", "@babel/preset-typescript"],
  "plugins": ["add-module-exports"]
}

With React

{
  "presets": ["@babel/preset-env", "@babel/preset-react"],
  "plugins": ["add-module-exports"]
}

Types

/**
 * Internal class for analyzing export patterns (not exported)
 */
interface ExportsFinder {
  constructor(exportsDefaultPath: any): ExportsFinder;
  getRootPath(): any;
  isOnlyExportsDefault(): boolean;
  findExports(path: any, property?: string): void;
  findExportsInCallExpression(path: any): void;
  isAmd(): boolean;
}