# Configure for Storybook

To configure Rsbuild for Storybook, execute the following steps 👇

# Install the packages

pnpm add -D @workleap/rsbuild-configs @workleap/browserslist-config @rsbuild/core @rspack/core browserslist storybook-react-rsbuild
yarn add -D @workleap/rsbuild-configs @workleap/browserslist-config @rsbuild/core @rspack/core browserslist storybook-react-rsbuild
npm install -D @workleap/rsbuild-configs @workleap/browserslist-config @rsbuild/core @rspack/core browserslist storybook-react-rsbuild

# Configure Rsbuild

# Browserslist

First, let's set up Browserlist to define the minimum browser versions supported by the application. Rsbuild will automatically detect and load the browser versions from the nearest .browserslistrc configuration file.

First, create a browserslistrc file at the root of the project:

storybook
├── .storybook
├──── main.ts
├──── preview.tsx
├── .browserslistrc
├── package.json

Then, open the newly created file and extend the default configuration with the shared configuration provided by @workleap/browserslist-config:

.browserslistrc
extends @workleap/browserslist-config

# rsbuild.config.ts

Next, create a configuration file named rsbuild.config.ts under the storybook folder:

storybook
├── .storybook
├──── main.ts
├──── preview.tsx
├──── rsbuild.configts
├── .browserslistrc
├── package.json

Then, open the newly created file and export the Rsbuild configuration by using the defineStorybookConfig(options) function:

rsbuild.config.ts
import { defineStorybookConfig } from "@workleap/rsbuild-configs";

export default defineStorybookConfig();

# main.ts

Finally, open the .storybook/main.ts file and set storybook-react-rsbuild as the framework to use:

main.ts
import type { StorybookConfig } from "storybook-react-rsbuild";

const storybookConfig: StorybookConfig = {
    framework: "storybook-react-rsbuild",
    stories: [
        "../../src/**/*.stories.(tsx|mdx)"
    ]
};

export default storybookConfig;

# Use predefined options

The defineStorybookConfig(options) function can be used as shown in the previous example, however, if you wish to customize the default configuration, the function also accept a few predefined options to help with that 👇

# plugins

Append the provided Rsbuild plugins to the configuration.

rsbuild.config.ts
import { defineStorybookConfig } from "@workleap/rsbuild-configs";
import { pluginAssetsRetry } from "@rsbuild/plugin-assets-retry";

export default defineStorybookConfig({
    plugins: [pluginAssetsRetry()]
});

# sourceMap

  • Type: false or an object literal accepting any output.sourceMap options.
  • Default: { js: "cheap-module-source-map", css: true }

Whether or not to generate source map. To disable source map, set the option to false.

rsbuild.config.ts
import { defineStorybookConfig } from "@workleap/rsbuild-configs";

export default defineStorybookConfig({
    sourceMap: false
});

To customize the source map configuration, provide an object literal.

rsbuild.config.ts
import { defineStorybookConfig } from "@workleap/rsbuild-configs";

export default defineStorybookConfig({
    sourceMap: {
        css: false
    }
});

# react

  • Type: false or (defaultOptions: PluginReactOptions) => PluginReactOptions
  • Default: defaultOptions => defaultOptions

Whether or not to transform React code. To disable React code transformation, set the option to false.

rsbuild.config.ts
import { defineStorybookConfig } from "@workleap/rsbuild-configs";

export default defineStorybookConfig({
    react: false
});

To customize plugin-react, provide a function to extend the default options.

rsbuild.config.ts
import { defineStorybookConfig } from "@workleap/rsbuild-configs";

export default defineStorybookConfig({
    react: defaultOptions => {
        return {
            ...defaultOptions,
            swcReactOptions: {
                ...(defaultOptions.swcReactOptions ?? {}),
                runtime: "classic"
            }
        };
    }
});

# svgr

  • Type: false or (defaultOptions: PluginSvgrOptions) => PluginSvgrOptions
  • Default: defaultOptions => defaultOptions

Whether or not to handle .svg files with plugin-svgr. When the option is set to false, the .svg files will be handled by the asset/resource rule.

rsbuild.config.ts
import { defineStorybookConfig } from "@workleap/rsbuild-configs";

export default defineStorybookConfig({
    svgr: false
});

To customize plugin-svgr, provide a function extending the default options.

rsbuild.config.ts
import { defineStorybookConfig } from "@workleap/rsbuild-configs";

export default defineStorybookConfig({
    svgr: defaultOptions => {
        return {
            svgrOptions: {
                ...(defaultOptions.svgrOptions ?? {}),
                ref: true
            }
            ...defaultOptions,

        }
    }
});

When you reference an SVG asset in TypeScript code, TypeScript may prompt that the module is missing a type definition:

TS2307: Cannot find module './logo.svg' or its corresponding type declarations.

To fix this, you need to add type declaration for the SVG assets, create a src/env.d.ts file, and add the type declaration.

src/env.d.ts
declare module '*.svg' {
  export const ReactComponent: React.FunctionComponent<
    React.SVGProps<SVGSVGElement>
  >;
}
declare module '*.svg?react' {
  const ReactComponent: React.FunctionComponent<React.SVGProps<SVGSVGElement>>;
  export default ReactComponent;
}

For additional information, refer to the plugin documentation.

# Import images

By default, plugin-svgr is configured to support named import for ReactComponent:

import { ReactComponent as Logo } from "./logo.svg";

export const App = () => <Logo />;

# verbose

  • Type: boolean
  • Default: false

Start the Rsbuild process with verbose logging turned on.

rsbuild.config.ts
import { defineStorybookConfig } from "@workleap/rsbuild-configs";

export default defineStorybookConfig({
    verbose: true
});

# Configuration transformers

The predefined options are useful to quickly customize the default Storybook configuration of @workleap/rsbuild-configs, but only covers a subset of an Rsbuild configuration. If you need full control over the configuration, you can provide configuration transformer functions through the transformers option of the defineBuildConfig function. Remember, no locked in ❤️✌️.

To view the default build configuration of @workleap/rsbuild-configs, have a look at the storybook.ts configuration file on GitHub.

# transformers

  • Type: ((config: RsbuildConfig, context: RsbuildConfigTransformerContext) => RsbuildConfig)[]
  • Default: []
transformer(config: RsbuildConfig, context: RsbuildConfigTransformerContext) => RsbuildConfig
rsbuild.config.ts
import { defineBuildConfig, type RsbuildConfig, type RsbuildConfigTransformer } from "@workleap/rsbuild-configs";

const useInlineStylesTransformer: RsbuildConfigTransformer = (config: RsbuildConfig) => {
    config.output = {
        ...(config.ouput ?? {}),
        inlineStyles: true
    };

    return config;
};

export default defineBuildConfig({
    transformers: [useInlineStylesTransformer]
});

# Execution context

Generic transformers can use the context parameter to gather additional information about their execution context, like the environment they are operating in.

transformer.ts
export const transformer: RsbuildConfigTransformer = (config: RsbuildConfig) => {
    if (context.environment === "storybook") {
        config.output = {
            ...(config.ouput ?? {}),
            inlineStyles: true
        };
    }

    return config;
}
  • environment: "dev" | "build" | "storybook"
  • verbose: boolean

# Add CLI scripts

To create the bundle files for production, add the following scripts to your project package.json file:

package.json
{
    "dev": "storybook dev -p 6006",
    "build": "storybook build"
}

# Use environment variables

# cross-env

We recommend instead to define environment variables using cross-env. With cross-env, the environment variables will be made available to any Node.js files that are executed by the script process (dev and build in the example below 👇):

package.json
{
    "dev": "cross-env DEBUG=true storybook dev -p 6006",
    "build": "cross-env DEBUG=true storybook build"
}
rsbuild.config.ts
import { defineStorybookConfig } from "@workleap/rsbuild-configs";

if (process.env.DEBUG) {
    console.log("Configuring Rsbuild in debug mode!");
}

export default defineStorybookConfig();

However, there's a catch. When using cross-env, the variables will not be available in the application files because cross-env only makes them available to files that are executed by the process at build time while the application files are executed at runtime by a browser.

To make them accessible to the application files, Rsbuild must be aware of those environment variables and render them into the compiled application files. This is the purpose of the environmentVariables option.

# environmentVariables

  • Type: Record<string, unknown>
  • Default: {}

First, define the variables with environmentVariables:

rsbuild.config.ts
import { defineStorybookConfig } from "@workleap/rsbuild-configs";

export default defineStorybookConfig({
    environmentVariables: {
        "DEBUG": process.env.DEBUG === "true"
    }
});

Then, use the variables in any file:

src/Button.tsx
export function Button() {
    if (process.env.DEBUG) {
        console.log("The Button component is in debug mode!");
    }

    return null;
}

# Try it 🚀

To test your new Rsbuild configuration, open a terminal at the root of the project and execute the CLI scripts added earlier. Either the Storybook development server should start without outputting any error in the terminal or the Storybook application bundle files should be available in the /storybook-static folder (or any other folder you configured).