SVGR Plugin

By default, Rsbuild will treat SVG files as static assets. For processing rules, please refer to: Import Static Assets.

With SVGR plugin, Rsbuild supports transform SVG to React components via SVGR.

Quick Start

Install Plugin

You can install the plugin using the following command:

npm
yarn
pnpm
bun
npm add @rsbuild/plugin-svgr -D

Register Plugin

You can register the plugin in the rsbuild.config.ts file:

rsbuild.config.ts
import { pluginSvgr } from '@rsbuild/plugin-svgr';

export default {
  plugins: [pluginSvgr()],
};

Example

After registering the plugin, when import an SVG in a JS file, if the imported path contains the ?react suffix, Rsbuild will call SVGR to transform the SVG into a React component.

App.jsx
import Logo from './logo.svg?react';

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

@rsbuild/plugin-svgr supports the above usage since v0.4.14.

If the imported path does not contain the ?react suffix, then the SVG will be treated as a normal static asset and you will get a URL:

import logoURL from './static/logo.svg';

console.log(logoURL); // => "/static/logo.6c12aba3.png"

Rsbuild also supports named imports of the ReactComponent to use SVGR:

App.jsx
import { ReactComponent as Logo } from './logo.svg';

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

Options

If you need to customize the compilation behavior of Svgr, you can use the following configs.

  • Type:
type PluginSvgrOptions = {
  /**
   * Configure SVGR options.
   */
  svgrOptions?: import('@svgr/core').Config;
  /**
   * Whether to allow the use of default import and named import at the same time.
   * @default false
   */
  mixedImport?: boolean;
};

svgrOptions

Modify the options of SVGR, the passed object will be deep merged with the default value. See SVGR - Options for details.

  • Type: import('@svgr/core').Config
  • Default:
const defaultSvgrOptions = {
  svgo: true,
  svgoConfig: {
    plugins: [
      {
        name: 'preset-default',
        params: {
          overrides: {
            removeViewBox: false,
          },
        },
      },
      'prefixIds',
    ],
  },
};
  • Example:
pluginSvgr({
  svgrOptions: {
    svgoConfig: {
      datauri: 'base64',
    },
  },
});

svgrOptions.exportType

Set the export type of SVG React components.

  • Type: 'default' | 'named'
  • Default: undefined

exportType can be set as:

  • default: use default export
  • named: use named export (ReactComponent)

For example, set the default export of SVG file as a React component:

pluginSvgr({
  svgrOptions: {
    exportType: 'default',
  },
});

Then import the SVG, you'll get a React component instead of a URL:

import Logo from './logo.svg';

console.log(Logo); // => React Component

At this time, you can also specify the ?url query to import the URL, for example:

import logo from './logo.svg?url';

console.log(logo); // => asset url
TIP

When svgrOptions.exportType is set to 'default', the named imports (ReactComponent) cannot be used.

mixedImport

  • Type: boolean
  • Default: false
  • Version: >= 0.5.0

Whether to enable mixed import, allowing to use default import and named import at the same time.

Mixed import is usually used with svgrOptions.exportType: 'named', for example:

pluginSvgr({
  mixedImport: true,
  svgrOptions: {
    exportType: 'named',
  },
});

At this time, the imported SVG file will export both URL and the React component:

import logoUrl, { ReactComponent as Logo } from './logo.svg';

console.log(logoUrl); // -> string
console.log(Logo); // -> React component

Limitations

It is recommended to use ?react to transform SVG to React component instead of using mixed import. Because mixed import has the following limitations:

  1. Increased bundle size: Mixed import causes a single SVG module to be compiled into two types of code (even if some exports are not used), which will increase the bundle size.
  2. Slow down compiling: Mixed import will cause extra compilation overhead. Even if the ReactComponent export is not used in the code, the SVG file will still be compiled by SVGR. And SVGR is based on Babel, which has a high performance overhead.

query

  • Type: RegExp
  • Default: /react/
  • Version: >= 0.5.2

Used to custom the query suffix to match SVGR transformation.

For example, if you need to match import paths with the ?svgr suffix:

pluginSvgr({
  query: /svgr/,
});
App.jsx
import Logo from './logo.svg?svgr';

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

exclude

Exclude some SVG files, they will not be transformed by SVGR.

For example, if a project includes a.svg and b.svg, you can add b.svg to exclude:

pluginSvgr({
  svgrOptions: {
    exportType: 'default',
  },
  exclude: /b\.svg/,
});

When imported, a.svg will be transformed into a React component, while b.svg will be treated as a regular static asset:

src/index.ts
import component from './a.svg';
import url from './b.svg';

console.log(component); // => React component
console.log(url); // => resource url

excludeImporter

Exclude some modules, the SVGs imported by these modules will not be transformed by SVGR.

For example, if your project contains page-a/index.ts and page-b/index.ts, you can add page-b to excludeImporter:

pluginSvgr({
  svgrOptions: {
    exportType: 'default',
  },
  excludeImporter: /\/page-b\/index\.ts/,
});
  • SVGs referenced in page-a will be transformed to React components:
page-a/index.ts
import Logo from './logo.svg';

console.log(Logo); // => React component
  • SVGs referenced in page-b will be treated as static assets:
page-b/index.ts
import url from './logo.svg';

console.log(url); // => Resource url
TIP

The query in the module path has a higher priority than exclude and excludeImporter. For example, if a module is excluded, adding ?react can still make it transformed by SVGR.

Type Declaration

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, please create a src/env.d.ts file, and add the type declaration.

  • By default, you can add the following type declarations:
declare module '*.svg' {
  const content: string;
  export default content;
}
declare module '*.svg?react' {
  const ReactComponent: React.FunctionComponent<React.SVGProps<SVGSVGElement>>;
  export default ReactComponent;
}
  • If the value of svgrOptions.exportType is 'default', set the type declaration to:
declare module '*.svg' {
  const ReactComponent: React.FunctionComponent<React.SVGProps<SVGSVGElement>>;
  export default ReactComponent;
}
declare module '*.svg?react' {
  const ReactComponent: React.FunctionComponent<React.SVGProps<SVGSVGElement>>;
  export default ReactComponent;
}
  • If the value of svgrOptions.exportType is 'named', set the type declaration to:
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;
}
  • If the value of svgrOptions.exportType is 'named', and mixedImport is enabled, set the type declaration to:
declare module '*.svg' {
  export const ReactComponent: React.FunctionComponent<
    React.SVGProps<SVGSVGElement>
  >;
  const content: string;
  export default content;
}
declare module '*.svg?react' {
  const ReactComponent: React.FunctionComponent<React.SVGProps<SVGSVGElement>>;
  export default ReactComponent;
}

After adding the type declarations, if the type error still exists, you can try to restart the IDE, or adjust the directory where env.d.ts is located, making sure the TypeScript can correctly identify the type definition.