CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-rsbuild--core

The Rspack-based build tool providing high-performance bundling with comprehensive development features and plugin system.

Pending
Overview
Eval results
Files

plugin-system.mddocs/

Plugin System

Comprehensive plugin architecture with lifecycle hooks, configuration modification, and inter-plugin communication. Rsbuild's plugin system provides extensive customization capabilities through a rich set of hooks and utilities.

Capabilities

Plugin Definition

Define plugins with lifecycle hooks and configuration modification capabilities.

/**
 * Plugin interface for extending Rsbuild functionality
 */
interface RsbuildPlugin {
  /** Unique plugin identifier */
  name: string;
  /** Plugin setup function called during initialization */
  setup: (api: RsbuildPluginAPI) => MaybePromise<void>;
  /** Conditional application based on command or context */
  apply?: 'serve' | 'build' | ((config: any, context: any) => boolean);
  /** Execution order enforcement */
  enforce?: 'pre' | 'post';
  /** Plugins that must run before this plugin */
  pre?: string[];
  /** Plugins that must run after this plugin */
  post?: string[];
  /** Plugin names to remove from the plugin list */
  remove?: string[];
}

type MaybePromise<T> = T | Promise<T>;

Usage Examples:

import type { RsbuildPlugin } from "@rsbuild/core";

// Basic plugin
const myPlugin = (): RsbuildPlugin => ({
  name: "my-plugin",
  setup(api) {
    api.modifyRsbuildConfig((config) => {
      config.source = config.source || {};
      config.source.alias = {
        ...config.source.alias,
        "@components": "./src/components",
      };
    });
  },
});

// Conditional plugin (dev only)
const devOnlyPlugin = (): RsbuildPlugin => ({
  name: "dev-only-plugin",
  apply: "serve",
  setup(api) {
    api.onAfterStartDevServer(({ port, urls }) => {
      console.log(`Dev server running on port ${port}`);
    });
  },
});

// Plugin with execution order
const criticalPlugin = (): RsbuildPlugin => ({
  name: "critical-plugin",
  enforce: "pre",
  setup(api) {
    // Runs before other plugins
  },
});

// Plugin with dependencies
const dependentPlugin = (): RsbuildPlugin => ({
  name: "dependent-plugin",
  pre: ["rsbuild:css", "rsbuild:html"],
  setup(api) {
    // Runs after CSS and HTML plugins
  },
});

Plugin API

The plugin API provides access to configuration, hooks, and utilities.

/**
 * API interface provided to plugins during setup
 */
interface RsbuildPluginAPI {
  /** Read-only build context */
  context: RsbuildContext;
  /** Logging utilities */
  logger: Logger;
  
  // Configuration modification hooks
  modifyRsbuildConfig: ModifyRsbuildConfigHook;
  modifyEnvironmentConfig: ModifyEnvironmentConfigHook;
  modifyBundlerChain: ModifyBundlerChainHook;
  modifyRspackConfig: ModifyRspackConfigHook;
  modifyWebpackConfig?: ModifyWebpackConfigHook;
  
  // HTML processing hooks
  modifyHTML: ModifyHTMLHook;
  modifyHTMLTags: ModifyHTMLTagsHook;
  
  // Advanced processing hooks
  transform: TransformHook;
  processAssets: ProcessAssetsHook;
  resolve: ResolveHook;
  
  // Plugin communication
  expose: <T = any>(id: string, api: T) => void;
  useExposed: <T = any>(id: string) => T | undefined;
  
  // Lifecycle hooks (inherited from RsbuildInstance)
  onBeforeBuild: (fn: OnBeforeBuildFn) => void;
  onAfterBuild: (fn: OnAfterBuildFn) => void;
  onCloseBuild: (fn: OnCloseBuildFn) => void;
  onBeforeDevCompile: (fn: OnBeforeDevCompileFn) => void;
  onAfterDevCompile: (fn: OnAfterDevCompileFn) => void;
  onDevCompileDone: (fn: OnDevCompileDoneFn) => void;
  onBeforeStartDevServer: (fn: OnBeforeStartDevServerFn) => void;
  onAfterStartDevServer: (fn: OnAfterStartDevServerFn) => void;
  onCloseDevServer: (fn: OnCloseDevServerFn) => void;
  onBeforeCreateCompiler: (fn: OnBeforeCreateCompilerFn) => void;
  onAfterCreateCompiler: (fn: OnAfterCreateCompilerFn) => void;
  onExit: (fn: OnExitFn) => void;
}

Configuration Modification Hooks

Modify Rsbuild Configuration

Modify the main Rsbuild configuration object.

/**
 * Hook to modify Rsbuild configuration
 */
interface ModifyRsbuildConfigHook {
  (fn: ModifyRsbuildConfigFn): void;
}

type ModifyRsbuildConfigFn = (
  config: RsbuildConfig,
  utils: ModifyRsbuildConfigUtils
) => RsbuildConfig | void | Promise<RsbuildConfig | void>;

interface ModifyRsbuildConfigUtils {
  mergeConfig: typeof mergeRsbuildConfig;
}

Usage Examples:

const configPlugin = (): RsbuildPlugin => ({
  name: "config-plugin",
  setup(api) {
    api.modifyRsbuildConfig((config, { mergeConfig }) => {
      // Direct modification
      config.output = config.output || {};
      config.output.assetPrefix = "/static/";
      
      // Using merge utility
      return mergeConfig(config, {
        source: {
          alias: {
            "@utils": "./src/utils",
          },
        },
        performance: {
          chunkSplit: {
            strategy: "split-by-experience",
          },
        },
      });
    });
  },
});

Modify Environment Configuration

Modify environment-specific configuration.

/**
 * Hook to modify environment-specific configuration
 */
interface ModifyEnvironmentConfigHook {
  (fn: ModifyEnvironmentConfigFn): void;
}

type ModifyEnvironmentConfigFn = (
  config: EnvironmentConfig,
  utils: ModifyEnvironmentConfigUtils
) => EnvironmentConfig | void | Promise<EnvironmentConfig | void>;

interface ModifyEnvironmentConfigUtils {
  /** Environment name */
  name: string;
  /** Merge configuration utility */
  mergeConfig: (config: EnvironmentConfig) => EnvironmentConfig;
}

Modify Bundler Chain

Modify bundler configuration using rspack-chain or webpack-chain.

/**
 * Hook to modify bundler configuration via chain API
 */
interface ModifyBundlerChainHook {
  (fn: ModifyBundlerChainFn): void;
}

type ModifyBundlerChainFn = (
  chain: RspackChain,
  utils: ModifyBundlerChainUtils
) => void | Promise<void>;

interface ModifyBundlerChainUtils {
  env: string;
  target: RsbuildTarget;
  isDev: boolean;
  isProd: boolean;
  CHAIN_ID: ChainIdentifier;
  bundler: BundlerType;
  getCompiledPath: (name: string) => string;
}

type BundlerType = 'rspack' | 'webpack';

Usage Examples:

const chainPlugin = (): RsbuildPlugin => ({
  name: "chain-plugin",
  setup(api) {
    api.modifyBundlerChain((chain, { CHAIN_ID }) => {
      // Add a new loader
      chain.module
        .rule("my-rule")
        .test(/\.special$/)
        .use("my-loader")
        .loader("my-loader")
        .options({
          customOption: true,
        });
      
      // Modify existing plugin
      chain.plugin(CHAIN_ID.PLUGIN.HTML).tap((args) => {
        args[0].title = "My App";
        return args;
      });
      
      // Add environment-specific configuration
      if (utils.isDev) {
        chain.devtool("eval-cheap-module-source-map");
      }
    });
  },
});

Modify Rspack Configuration

Directly modify the Rspack configuration object.

/**
 * Hook to modify Rspack configuration directly
 */
interface ModifyRspackConfigHook {
  (fn: ModifyRspackConfigFn): void;
}

type ModifyRspackConfigFn = (
  config: RspackConfig,
  utils: ModifyRspackConfigUtils
) => RspackConfig | void | Promise<RspackConfig | void>;

interface ModifyRspackConfigUtils {
  env: string;
  target: RsbuildTarget;
  isDev: boolean;
  isProd: boolean;
  rspack: typeof import('@rspack/core');
}

HTML Processing Hooks

Modify HTML Content

Modify the final HTML content before output.

/**
 * Hook to modify HTML content
 */
interface ModifyHTMLHook {
  (fn: ModifyHTMLFn): void;
}

type ModifyHTMLFn = (
  html: string,
  context: ModifyHTMLContext
) => string | Promise<string>;

interface ModifyHTMLContext {
  assetPrefix: string;
  filename: string;
  environment: EnvironmentContext;
}

Modify HTML Tags

Modify HTML tags that are injected into the HTML.

/**
 * Hook to modify HTML tags
 */
interface ModifyHTMLTagsHook {
  (fn: ModifyHTMLTagsFn): void;
}

type ModifyHTMLTagsFn = (
  tags: HtmlTag[],
  context: ModifyHTMLTagsContext
) => HtmlTag[] | Promise<HtmlTag[]>;

interface ModifyHTMLTagsContext {
  assetPrefix: string;
  filename: string;
  environment: EnvironmentContext;
}

interface HtmlTag {
  tag: string;
  attrs?: Record<string, string | boolean | undefined>;
  children?: string;
  hash?: boolean | string;
}

Usage Examples:

const htmlPlugin = (): RsbuildPlugin => ({
  name: "html-plugin",
  setup(api) {
    // Modify HTML content
    api.modifyHTML((html, { filename }) => {
      if (filename.includes("index")) {
        return html.replace(
          "<head>",
          "<head>\n  <meta name=\"custom\" content=\"value\">"
        );
      }
      return html;
    });
    
    // Modify HTML tags
    api.modifyHTMLTags((tags, { environment }) => {
      // Add custom script tag
      tags.push({
        tag: "script",
        attrs: {
          src: "/analytics.js",
          async: true,
        },
      });
      
      // Add environment-specific tags
      if (environment.name === "production") {
        tags.push({
          tag: "meta",
          attrs: {
            name: "robots",
            content: "index,follow",
          },
        });
      }
      
      return tags;
    });
  },
});

Advanced Processing Hooks

Transform Hook

Transform module code during the build process.

/**
 * Hook to transform module code
 */
interface TransformHook {
  (descriptor: TransformDescriptor, handler: TransformHandler): void;
}

interface TransformDescriptor {
  /** File pattern to match */
  test?: RegExp | ((id: string) => boolean);
  /** Target environments */
  targets?: RsbuildTarget[];
  /** Transform order */
  order?: 'pre' | 'post';
}

type TransformHandler = (
  context: TransformContext
) => TransformResult | Promise<TransformResult>;

interface TransformContext {
  /** Module code */
  code: string;
  /** Module resource path with query */
  resource: string;
  /** Module resource path without query */
  resourcePath: string;
  /** Environment context */
  environment: EnvironmentContext;
  /** Add file dependency */
  addDependency: (file: string) => void;
  /** Emit file to output */
  emitFile: (name: string, content: string) => void;
}

interface TransformResult {
  /** Transformed code */
  code: string;
  /** Source map */
  map?: string | object;
}

Usage Examples:

const transformPlugin = (): RsbuildPlugin => ({
  name: "transform-plugin",
  setup(api) {
    // Transform TypeScript files
    api.transform(
      { test: /\.ts$/ },
      async ({ code, resourcePath }) => {
        // Add custom header to all TypeScript files
        const header = `// Generated by custom plugin\n`;
        return {
          code: header + code,
        };
      }
    );
    
    // Transform specific file pattern
    api.transform(
      { 
        test: (id) => id.includes("api/"),
        targets: ["web"],
      },
      ({ code, addDependency }) => {
        // Add runtime dependency
        addDependency("./runtime-helpers.js");
        
        // Transform API files
        const transformedCode = code.replace(
          /process\.env\.API_URL/g,
          '"https://api.example.com"'
        );
        
        return { code: transformedCode };
      }
    );
  },
});

Process Assets Hook

Process build assets before emission.

/**
 * Hook to process assets before emission
 */
interface ProcessAssetsHook {
  (descriptor: ProcessAssetsDescriptor, handler: ProcessAssetsHandler): void;
}

interface ProcessAssetsDescriptor {
  /** Processing stage */
  stage?: 'optimize' | 'optimize-count' | 'optimize-compatibility' | 'optimize-size' | 'dev-tooling' | 'optimize-inline' | 'summarize' | 'report';
}

type ProcessAssetsHandler = (
  assets: Record<string, Source>
) => void | Promise<void>;

interface Source {
  source(): string | Buffer;
  size(): number;
  map(): object | null;
}

Resolve Hook

Intercept and modify module resolution.

/**
 * Hook to intercept module resolution
 */
interface ResolveHook {
  (handler: ResolveHandler): void;
}

type ResolveHandler = (
  data: ResolveData
) => ResolveResult | void | Promise<ResolveResult | void>;

interface ResolveData {
  /** Module request */
  request: string;
  /** Context directory */
  context: string;
  /** Import kind */
  kind: 'entry' | 'import' | 'require' | 'dynamic-import';
}

interface ResolveResult {
  /** Resolved path */
  path?: string;
  /** External module */
  external?: boolean;
}

Plugin Communication

Expose API

Expose plugin APIs for use by other plugins.

/**
 * Expose plugin API for use by other plugins
 * @param id - Unique identifier for the exposed API
 * @param api - API object to expose
 */
expose<T = any>(id: string, api: T): void;

Use Exposed API

Use APIs exposed by other plugins.

/**
 * Use API exposed by another plugin
 * @param id - Identifier of the exposed API
 * @returns The exposed API or undefined if not found
 */
useExposed<T = any>(id: string): T | undefined;

Usage Examples:

// Plugin that exposes an API
const providerPlugin = (): RsbuildPlugin => ({
  name: "provider-plugin",
  setup(api) {
    const sharedAPI = {
      getConfig: () => ({ theme: "dark" }),
      transform: (input: string) => input.toUpperCase(),
    };
    
    api.expose("provider-api", sharedAPI);
  },
});

// Plugin that uses the exposed API
const consumerPlugin = (): RsbuildPlugin => ({
  name: "consumer-plugin",
  enforce: "post", // Run after provider
  setup(api) {
    const providerAPI = api.useExposed<{
      getConfig: () => any;
      transform: (input: string) => string;
    }>("provider-api");
    
    if (providerAPI) {
      const config = providerAPI.getConfig();
      console.log("Theme:", config.theme);
      
      api.modifyRsbuildConfig((config) => {
        // Use the shared API
        const transformed = providerAPI.transform("hello");
        config.source = config.source || {};
        config.source.define = {
          ...config.source.define,
          TRANSFORMED_VALUE: `"${transformed}"`,
        };
      });
    }
  },
});

Chain Identifiers

Predefined identifiers for common configuration elements when using the chain API.

interface ChainIdentifier {
  PLUGIN: {
    HTML: string;
    APP_ICON: string;
    INLINE_CHUNK: string;
    BUNDLE_ANALYZER: string;
    // ... more plugin identifiers
  };
  RULE: {
    JS: string;
    TS: string;
    CSS: string;
    SASS: string;
    LESS: string;
    // ... more rule identifiers
  };
  USE: {
    SWC: string;
    CSS: string;
    POSTCSS: string;
    // ... more use identifiers
  };
}

Built-in Plugin Names

const PLUGIN_CSS_NAME = 'rsbuild:css';
const PLUGIN_SWC_NAME = 'rsbuild:swc';

Plugin Registration

type RsbuildPlugins = (RsbuildPlugin | RsbuildPluginOptions)[];

interface RsbuildPluginOptions {
  plugin: RsbuildPlugin;
  options?: any;
}

Usage Examples:

import { defineConfig } from "@rsbuild/core";
import { myPlugin, anotherPlugin } from "./plugins";

export default defineConfig({
  plugins: [
    myPlugin(),
    anotherPlugin({ option: "value" }),
    
    // Conditional plugin
    process.env.NODE_ENV === "development" && devPlugin(),
    
    // Plugin with options
    {
      plugin: complexPlugin(),
      options: {
        advanced: true,
      },
    },
  ].filter(Boolean), // Remove falsy values
});

Install with Tessl CLI

npx tessl i tessl/npm-rsbuild--core

docs

cli-integration.md

configuration-management.md

core-build-system.md

development-server.md

environment-system.md

environment-variables.md

index.md

plugin-system.md

tile.json