builtin:swc-loader

builtin:swc-loaderswc-loader 的 Rust 版本,旨在提供更优的性能, Loader 的配置与 JS 版本的 swc-loader 保持对齐(SWC 插件将会在未来版本进行提供,暂不支持)。

如需要在项目中使用 builtin:swc-loader,需进行如下配置。

如对 ts 文件进行转译:

module.exports = {
  module: {
    rules: [
      {
        test: /\.ts$/,
        exclude: [/node_modules/],
        loader: 'builtin:swc-loader',
        options: {
          sourceMap: true,
          jsc: {
            parser: {
              syntax: 'typescript',
            },
          },
        },
        type: 'javascript/auto',
      },
    ],
  },
};

或是对 jsx 文件进行转译:

module.exports = {
  module: {
    rules: [
      {
        test: /\.jsx$/,
        use: {
          loader: 'builtin:swc-loader',
          options: {
            sourceMap: true,
            jsc: {
              parser: {
                syntax: 'ecmascript',
                jsx: true,
              },
              transform: {
                react: {
                  pragma: 'React.createElement',
                  pragmaFrag: 'React.Fragment',
                  throwIfNamespace: true,
                  development: false,
                  useBuiltins: false,
                },
              },
            },
          },
        },
        type: 'javascript/auto',
      },
    ],
  },
};

另外,你也可以直接参考 example-builtin-swc-loader 查看更多使用指南。

options

参考 SWC 配置

options.rspackExperiments

Rspack 内置的实验性功能。

options.rspackExperiments.import

Stability: Experimental

移植自 babel-plugin-import,配置基本保持一致。

但不能使用函数进行配置,例如 customNamecustomStyleName 等,这是因为这些函数必须由 Rust 调用,这种调用会造成一些性能劣化,受到 modularize_imports 的启发,简单的函数逻辑其实可以通过模版来代替,因此 customNamecustomStyleName ,这些配置可以传入字符串作为模版来代替函数,提高性能。

我们以下面代码为例说明:

import { MyButton as Btn } from 'foo';

添加以下配置:

rspack.config.js
module.exports = {
  module: {
    rules: [
      {
        use: 'builtin:swc-loader',
        options: {
          ...
          rspackExperiments: {
            import: [{
               libraryName: 'foo',
               customName: 'foo/es/{{ member }}',
            }]
          }
        }
      }
    ]
  }
};

其中的 {{ member }} 会被替换为相应的引入成员,转换后:

import Btn from 'foo/es/MyButton';

可以看出配置 customName: "foo/es/{{ member }}" 的效果等同于配置 customName: (member) => `foo/es/${member}` ,但是不会有 Node-API 的调用开销。

这里使用到的模版是 handlebars,模版配置中还内置了一些有用的辅助函数,还是以上面的导入语句为例:

配置如下:

rspack.config.js
module.exports = {
  module: {
    rules: [
      {
        use: 'builtin:swc-loader',
        options: {
          ...
          rspackExperiments: {
            import: [{
               libraryName: 'foo',
               customName: 'foo/es/{{ kebabCase member }}',
            }]
          }
        }
      }
    ]
  }
};

会转换成下面的结果:

import Btn from 'foo/es/my-button';

除了 kebabCase 以外还有 camelCasesnakeCaseupperCaselowerCase 可以使用。

其他配置可以直接查看 babel-plugin-import

再以经典的 4 版本的 ant-design 为例,我们只需要如下配置:

rspack.config.js
module.exports = {
  module: {
    rules: [
      {
        use: 'builtin:swc-loader',
        options: {
          ...
          rspackExperiments: {
            import: [
              {
                libraryName: 'antd',
                style: '{{member}}/style/index.css',
            },
            ]
          }
        }
      }
    ]
  }
};

上面的配置会将 import { Button } from 'antd'; 转换成

import Button from 'antd/es/button';
import 'antd/es/button/style/index.css';

然后就可以在页面中看到样式文件自动被引入并且生效了。

当然如果你已经配置了对 less 的支持,也可以直接使用如下配置:

rspack.config.js
module.exports = {
  module: {
    rules: [
      {
        use: 'builtin:swc-loader',
        options: {
          ...
          rspackExperiments: {
            import: [
              {
                libraryName: 'antd',
                style: true,
            },
            ]
          }
        }
      }
    ]
  }
};

上面的配置会将 import { Button } from 'antd'; 转换成:

import Button from 'antd/es/button';
import 'antd/es/button/style';

options.rspackExperiments.relay

Stability: Experimental

将项目中的 graphql 调用转换成相对应的 require

  • 类型:
type RelayOptions =
  | undefined
  | boolean
  | {
      artifactDirectory?: string;
      language: 'javascript' | 'typescript' | 'flow'; // 默认 'javascript'
    };
  • 默认值: undefined

当该配置为 true 时,Rspack 会从依次尝试寻找 context 目录下的 relay.config.jsonrelay.config.js 以及 package.json,详情可以参考 relay-compiler 文档,如果没找到则会使用默认配置。 如果传入具体的配置则不会尝试查找任何 relay 配置文件,而是直接使用传入的配置。

options.rspackExperiments.emotion

Stability: Experimental

用于设置对 emotion 的编译优化。

  • 类型:
type EmotionOptions =
  | boolean
  | {
      sourceMap?: boolean;
      autoLabel?: 'never' | 'dev-only' | 'always';
      labelFormat?: string;
      importMap?: {
        [packageName: string]: {
          [exportName: string]: {
            canonicalImport?: [string, string];
          };
        };
      };
    };
  • 默认值: false

若你在项目中使用了 emotion,并且想要类似 @emotion/babel-plugin 的能力,你可以开启 rspackExperiments.emotion 配置,启用该配置后,Rspack 会使用 swc_emotion 插件对 emotion 代码进行转译。

你可以直接使用默认配置,直接将 rspackExperiments.emotion 设置为 true 即可。

rspack.config.js
module.exports = {
  module: {
    rules: [
      {
        use: 'builtin:swc-loader',
        options: {
          ...
          rspackExperiments: {
            emotion: true
          }
        }
      }
    ]
  }
};

各字段与 @emotion/babel-plugin 保持一致,详细解释(下列内容部分取自 @emotion/babel-plugin 官方文档):

autoLabel

  • 类型: 'never' | 'dev-only' | 'always'
  • 默认值: 'dev-only'

这个配置项用于:

  • 生成 label 值,这样由 css 或者 styled 生成的样式中会包含原来的名字,方便调试。
  • 注意样式名中非单词字符将被删除。比如 iconStyles$1 会变成 iconStyles1,因为 $ 不是合法的 CSS 类名选择器

不同的配置项会产生不同的产物代码:

  • 'dev-only':只在 Rspack 的 development 模式下开启,在 production 模式下关闭以减小存储占用。
  • 'always':无论什么模式下都开启该特效。
  • 'never':无论什么模式下都禁用该特性。

labelFormat

  • 类型: string
  • 默认值: '[local]'

此选项仅在 'autoLabel' 设置为 'dev-only''always' 时有效。允许你自定义添加的 label 的结构。通过字符串定义,其中可变部分用方括号 '[]' 括起来。例如对于标签:'my-classname——[local]',其中 '[local]' 将被替换为样式变量的名称。

允许的值:

  • '[local]'——CSS 或样式表达式所在的文件名称
  • '[filename]'——CSS 或样式表达式所在的文件名称(不带扩展名)。
  • '[dirname]'——包含 CSS 或样式表达式所在文件的目录名。

该配置只会影响表达式中的 label,这意味着 CSS 前缀和 hash 会自动被添加。

sourceMap

  • 类型: boolean

该配置决定是否注入 source maps。production 模式下默认关闭,development 模式下默认开启。

importMap

  • 类型:
export type ImportMap =
  | undefined
  | {
      [packageName: string]: {
        [exportName: string]: {
          canonicalImport?: [string, string];
        };
      };
    };
  • 默认值: undefined

此选项允许你告诉 Rspack 它应该查看哪些 import 语句,确定应该转换什么,因此如果你重导出 emotion 的方法,仍然可以转换。

options.rspackExperiments.styledComponents

Stability: Experimental
  • Type:
type StyledComponentsOptions = {
  displayName?: boolean;
  ssr?: boolean;
  fileName?: boolean;
  meaninglessFileNames?: string[];
  namespace?: string;
  topLevelImportPaths?: string[];
  transpileTemplateLiterals?: boolean;
  minify?: boolean;
  pure?: boolean;
  cssProps?: boolean;
};
  • Default: {}

配置对 styled-components 的编译时支持。SWC 对于 styled-components 的支持基本对齐了官方的 babel 插件,所以你可以访问 https://styled-components.com/docs/tooling#babel-plugin 了解更多信息。

通常你还需要启用 builtin:swc-loader 的 JSX 支持用来处理 React 组件,配置项内容可以参考:

/** @type {import('@rspack/core').Configuration}*/
module.exports = {
  module: {
    rules: [
      {
        test: /\.jsx?$/,
        loader: 'builtin:swc-loader',
        options: {
          ...
          rspackExperiments: {
            styledComponents: {
              displayName: true,
              ssr: true,
              fileName: true,
              meaninglessFileNames: ['index', 'styles'],
              namespace: 'rspack-test',
              topLevelImportPaths: [
                '@xstyled/styled-components',
                '@xstyled/styled-components/*',
              ],
              transpileTemplateLiterals: true,
              minify: true,
              pure: true,
              cssProps: true,
            },
          },
        },
      },
    ],
  },
};