CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-babel-plugin-component

Babel plugin that transforms named component imports into specific module paths for tree-shaking optimization

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

Babel Plugin Component

Babel Plugin Component is a Babel transformation plugin that enables modular component imports by transforming named imports into specific module paths. It automatically handles both JavaScript module imports and CSS style imports, enabling tree-shaking optimization and reducing bundle sizes for component libraries like Element UI, Ant Design, and custom libraries.

Package Information

  • Package Name: babel-plugin-component
  • Package Type: npm
  • Language: JavaScript
  • Installation: npm install babel-plugin-component -D

Core Imports

// As Babel plugin in .babelrc
{
  "plugins": [["component", options]]
}
// Programmatic usage
const plugin = require('babel-plugin-component');

Basic Usage

// .babelrc configuration
{
  "plugins": [["component", {
    "libraryName": "element-ui",
    "style": true
  }]]
}
// Input code
import { Button, message } from 'element-ui';

// Output after transformation (with Babel helpers)
require("element-ui/lib/button/style.css");
var _Button = _interopRequireDefault(require("element-ui/lib/button")).default;
require("element-ui/lib/message/style.css");
var _message = _interopRequireDefault(require("element-ui/lib/message")).default;

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

Architecture

Babel Plugin Component operates through several key mechanisms:

  • AST Transformation: Uses Babel's visitor pattern to transform import declarations and component references
  • Import Resolution: Maps component names to specific module paths using configurable directory structures
  • Style Handling: Automatically injects CSS imports based on component usage and configuration
  • Multi-Library Support: Handles multiple component libraries in a single project through configuration arrays
  • Cache Management: Maintains internal caches to optimize repeated transformations and handle complex import scenarios

Capabilities

Plugin Factory Function

Core function that creates the Babel plugin with specified default library name.

/**
 * Creates a Babel plugin function with specified default library name
 * @param {string} defaultLibraryName - Default library name to use when not specified in options
 * @returns {Function} Babel plugin function
 */
function core(defaultLibraryName);

Main Plugin Export

Default export that provides a pre-configured plugin for Element UI.

/**
 * Default plugin export configured for 'element-ui' library
 * @returns {Function} Babel plugin configured for Element UI
 */
module.exports; // Returns core('element-ui')

Plugin Configuration Options

Complete configuration interface for customizing plugin behavior.

interface PluginOptions {
  /** Name of the library to transform imports for */
  libraryName?: string;
  /** Library directory path (default: 'lib') */
  libDir?: string;
  /** Style import handling - true for default style.css, string for custom path, false for none */
  style?: boolean | string;
  /** Root directory for components */
  root?: string;
  /** Convert camelCase to dash-case for component names (default: true) */
  camel2Dash?: boolean;
  /** File extension for style files (default: '.css') */
  ext?: string;
  /** Style library name - regular name or prefixed with ~ for independent theme */
  styleLibraryName?: string;
  /** Advanced style library configuration */
  styleLibrary?: StyleLibraryConfig;
}

interface StyleLibraryConfig {
  /** Style library name (same as styleLibraryName) */
  name: string;
  /** Include base.css file (default: true) */
  base?: boolean;
  /** Template for style file paths, supports [module] placeholder */
  path?: string;
  /** Fallback to component's own style if theme style not found */
  mixin?: boolean;
  /** Root directory for styles */
  root?: string;
}

Multiple Library Configuration

Configuration for handling multiple component libraries.

/**
 * Multiple library configuration array
 * Each array element: [plugin, options, libraryIdentifier]
 */
type MultiLibraryConfig = Array<[Function, PluginOptions, string]>;

Usage Example:

{
  "plugins": [
    ["component", {
      "libraryName": "antd",
      "style": true
    }, "antd"],
    ["component", {
      "libraryName": "element-ui",
      "style": true
    }, "element-ui"]
  ]
}

Import Transformation Patterns

The plugin handles various import and usage patterns:

Named Imports:

// Input
import { Button, Input } from 'antd';

// Output (with style: true, simplified for clarity)
require("antd/lib/button/style.css");
var _Button = _interopRequireDefault(require("antd/lib/button")).default;
require("antd/lib/input/style.css");
var _Input = _interopRequireDefault(require("antd/lib/input")).default;

Function Calls:

// Input
import { message } from 'element-ui';
message('Hello');

// Output
require("element-ui/lib/message/style.css");
var _message = require("element-ui/lib/message").default;
_message('Hello');

Member Expressions:

// Input
import Components from 'antd';
Components.Button;

// Output
var _Components = require("antd/lib").default;
_Components.Button;

Array Usage:

// Input
import { Button, Input } from 'antd';
const components = [Button, Input];

// Output
var _Button = require("antd/lib/button").default;
var _Input = require("antd/lib/input").default;
const components = [_Button, _Input];

Style Import Strategies

Different approaches for handling CSS and style imports:

Basic Style Import:

// Configuration
{ "style": true }

// Transforms to
require("library/lib/component/style.css");

Custom Style Path:

// Configuration
{ "style": "custom.css" }

// Transforms to
require("library/lib/component/custom.css");

Style Library with Theme:

// Configuration
{
  "styleLibraryName": "theme-default"
}

// Transforms to
require("library/lib/theme-default/component.css");

Independent Theme Package:

// Configuration
{
  "styleLibraryName": "~my-theme"
}

// Transforms to (resolved to current working directory)
require("/path/to/cwd/my-theme/component.css");

Advanced Style Library:

// Configuration
{
  "styleLibrary": {
    "name": "theme-custom",
    "base": true,
    "path": "[module]/index.css",
    "mixin": true
  }
}

// Base style import
require("library/lib/theme-custom/base.css");

// Component style import
require("library/lib/theme-custom/button/index.css");

Component Directory Structure Support

The plugin supports various component library directory structures:

Standard Structure:

- lib/
  - component-name/
    - index.js
    - style.css

Theme Structure:

- lib/
  - theme-default/
    - base.css
    - index.css
    - component-name.css
  - component-name/
    - index.js

Custom Path Structure:

- lib/
  - theme-custom/
    - component-name/
      - index.css
  - component-name/
    - index.js

Name Transformation

Component name transformation options:

/**
 * Converts component name based on camel2Dash setting
 * @param {string} str - Component name to transform
 * @param {boolean} camel2Dash - Whether to convert camelCase to dash-case
 * @returns {string} Transformed name
 */
function parseName(str, camel2Dash);

Examples:

// camel2Dash: true (default)
'DatePicker' → 'date-picker'
'Button' → 'button'

// camel2Dash: false
'DatePicker' → 'DatePicker'
'Button' → 'Button'

Error Handling

The plugin includes error handling for common configuration issues:

Import Conflict Error:

// Throws error when mixing import-all and on-demand imports
throw Error('[babel-plugin-component] If you are using both on-demand and importing all, make sure to invoke the importing all first.');

File Existence Checking:

/**
 * Checks if style file exists when using mixin option
 * Falls back to component's own style if theme style not found
 */
const isExist = require('fs').existsSync;

Babel Visitor Methods

The plugin implements the following Babel visitor methods to transform different AST node types:

Program:

  • Description: Initializes plugin state for each file
  • Purpose: Resets internal tracking objects for component imports

ImportDeclaration:

  • Description: Transforms import statements for the target library
  • Handles: Named imports, default imports, namespace imports
  • Purpose: Identifies and tracks component imports to be transformed

CallExpression:

  • Description: Transforms function calls using imported components
  • Purpose: Replaces component function calls with transformed imports

MemberExpression:

  • Description: Transforms member access on imported components
  • Purpose: Handles object property access on imported components

AssignmentExpression:

  • Description: Transforms assignments involving imported components
  • Purpose: Handles variable assignments with component references

ArrayExpression:

  • Description: Transforms array elements that reference imported components
  • Purpose: Processes component references within array literals

Property:

  • Description: Transforms object property values
  • Purpose: Handles component references in object property assignments

VariableDeclarator:

  • Description: Transforms variable declarations
  • Purpose: Processes component references in variable initializations

LogicalExpression:

  • Description: Transforms logical expressions (&&, ||)
  • Purpose: Handles component references in logical operations

ConditionalExpression:

  • Description: Transforms ternary conditional expressions
  • Purpose: Processes component references in conditional expressions

IfStatement:

  • Description: Transforms if statement conditions
  • Purpose: Handles component references in if conditions and tests

Dependencies

The plugin relies on the following external dependencies:

/**
 * Babel helper for adding module imports
 */
const { addSideEffect, addDefault } = require('@babel/helper-module-imports');

/**
 * Node.js built-in modules
 */
const resolve = require('path').resolve;
const isExist = require('fs').existsSync;

Types

/**
 * Babel plugin function signature
 */
type BabelPlugin = ({ types }: { types: any }) => {
  visitor: {
    [key: string]: (path: any, state: { opts: PluginOptions }) => void;
  };
};

/**
 * Internal cache structures
 */
interface Cache {
  [libraryName: string]: number; // 1 = import-all, 2 = on-demand
}

interface CachePath {
  [libraryName: string]: string; // Resolved style library paths
}

interface ImportAll {
  [libraryPath: string]: boolean; // Tracks import-all usage
}
Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/babel-plugin-component@1.1.x
Publish Source
CLI
Badge
tessl/npm-babel-plugin-component badge