Storybook `swc` 主配置完整指南:在 `main.js|ts` 中深度定制 SWC 编译
Storybook 的 main.js|ts 主配置文件中包含一个名为 swc 的顶层属性,用于定制基于 Webpack 的项目在启用编译器插件 @storybook/addon-webpack5-compiler-swc 后的 SWC 转译行为。本指南以 Storybook 官方 API 文档 及其配套代码片段 main-config-swc.md 为主体,结合本仓库源码中的默认预设实现,系统讲解该配置项的函数签名、适用前提、TypeScript 类型写法,以及从"切换 JSX 运行时"到"微调编译目标"的真实定制手段。读完你可以在自己的 Storybook 项目中安全地覆写 SWC 选项,并理解这些改动在编译链路中的实际作用位置。
适用范围与适用前提:什么情况下 swc 才会生效
swc 顶层配置并不是一个对所有 Storybook 项目都起作用的通用开关,它有明确的启用条件。根据 main-config-swc.mdx 的说明,该属性定制的是 Storybook 面向 Webpack 系项目的 SWC 转译设置,前提是项目已经通过 @storybook/addon-webpack5-compiler-swc 插件启用了 SWC 作为编译器。该插件覆盖绝大多数受支持的 Webpack 框架,但明确排除以下四类:
- Angular(自带编译器体系)
- Create React App(CRA)
- Ember.js
- Next.js
从仓库源码也能印证这一"卫星插件"定位:@storybook/addon-webpack5-compiler-swc 与 @storybook/addon-webpack5-compiler-babel 一起被记录在 satellite-addons.ts 中,注释表明它们是"Storybook 维护、但不在本 monorepo 内的包"。换句话说,你可以通过 npm 正常安装它,但它不会出现在本仓库的 code/addons 目录中。另从文件结构看,Next.js 框架自带独立的 SWC loader 适配(例如 next-swc-loader-patch.ts),因此也被排除在上述插件的作用范围之外。
如果你的项目走的是 Babel 编译路线(即安装了 @storybook/addon-webpack5-compiler-babel),则不应使用 swc 属性,而应使用同级的 babel 主配置。两者的适用关系都可以在 主配置总览 与 编译器相关文档 中进一步查阅。
配置签名:函数式覆写,支持同步与异步
swc 在 StorybookConfigRaw 主配置类型 中被定义为"修改或返回 swc 配置"的入口。按官方文档,其完整类型签名为:
(config: swc.Options, options: Options) => swc.Options | Promise<swc.Options>
- 第一个参数
config是当前生效的 SWC 配置(类型来自@swc/core的Options),Storybook 与编译器插件会先为你组装出一份基线配置,再传入你的函数。 - 返回值将被作为新的最终配置使用,因此你必须显式
return,并且通常通过{ ...config, ...你的改动 }展开合并,避免丢失原有配置。 - 返回类型允许是
Promise<swc.Options>,这意味着你可以在回调里执行异步逻辑(例如按需读取外部文件、判断构建模式后再决定编译参数),再返回处理后的配置。 - 第二个参数
options的类型为{ configType?: 'DEVELOPMENT' | 'PRODUCTION' },用于区分当前是storybook dev开发态还是storybook build生产构建,方便你对两种模式差异化处理。文档同时注明该对象还有其他难以在此一一列出的字段,需要以实际的类型定义为准进行自省(例如通过 IDE 跳转到Options类型查看)。
在 Storybook 内部,swc 属于预设(preset)扩展体系的一员:Presets.apply() 提供了专门的 apply(extension: 'swc', ...) 重载,见 core-common.ts 的 Presets 接口。也就是说,你在 main.js|ts 里写的 swc 函数本质上是被当作一个预设值注入编译链路的。
基线默认值:Webpack5 构建器预设了什么
要理解你覆写的对象从何而来,可以看本仓库中 Webpack5 构建器的默认 swc 预设实现 custom-webpack-preset.ts。它展示了 Storybook 在传给用户回调之前会准备的默认环境目标:
const newConfig = {
...config,
env: {
...(config?.env ?? {}),
targets: config?.env?.targets ?? {
chrome: 100,
safari: 15,
firefox: 91,
},
},
};
// 将破碎语法转译为最接近的非破碎现代语法。
// 例如:不会转译 Safari 中的参数解构——那会破坏
// play 函数中 mount 上下文属性是否被使用的检测逻辑。
if (!shouldRemoveBugfixes) {
newConfig.env.bugfixes = config?.env?.bugfixes ?? true;
}
这段源码揭示了两条重要事实:
- 默认编译目标:当你在
swc回调中不做任何设置时,基线配置会面向chrome 100 / safari 15 / firefox 91等现代浏览器做转译,并且只在env.targets未被自定义时填充默认值。 - 默认开启
bugfixes:只要main.js中没有开启features.babelRemoveBugfixes特性(源码中通过options.features.babelRemoveBugfixes判断),就会默认启用 SWC 的bugfixes。注释中解释了原因——它只做"最小的必要语法修复",例如不对 Safari 中的参数解构做多余转译,从而保证 Storybook 检测play函数中mount上下文使用情况的代码逻辑不被破坏。这是一个在覆写swc时需要刻意保留的默认行为。
所以你的 swc 回调中 config 的第一行展开结果,通常就是带有上述 env 目标的基线配置。
完整配置模板:JS 与 TS、CSF3 与 CSF Next 四种写法
swc 属性需要书写在项目根目录下的 .storybook/main.js 或 .storybook/main.ts 中。这里完整给出官方代码片段 main-config-swc.md 的全部写法,覆盖 JavaScript/TypeScript 与 CSF3/CSF Next 两代配置 API:
1. JavaScript + CSF3
export default {
framework: {
name: '@storybook/your-framework',
options: {},
},
swc: (config, options) => {
return {
...config,
// Apply your custom SWC configuration
};
},
};
2. TypeScript + CSF3
import type { Options } from '@swc/core';
// Replace your-framework with the webpack-based framework you are using (e.g., react-webpack5)
import type { StorybookConfig } from '@storybook/your-framework';
const config: StorybookConfig = {
framework: {
name: '@storybook/your-framework',
options: {},
},
swc: (config: Options, options): Options => {
return {
...config,
// Apply your custom SWC configuration
};
},
};
export default config;
3. TypeScript + CSF Next(实验性)
import type { Options } from '@swc/core';
// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)
import { defineMain } from '@storybook/your-framework/node';
export default defineMain({
framework: {
name: '@storybook/your-framework',
options: {},
},
swc: (config: Options, options): Options => {
return {
...config,
// Apply your custom SWC configuration
};
},
});
4. JavaScript + CSF Next(实验性)
// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)
import { defineMain } from '@storybook/your-framework/node';
export default defineMain({
framework: {
name: '@storybook/your-framework',
options: {},
},
swc: (config, options) => {
return {
...config,
// Apply your custom SWC configuration
};
},
});
四种写法的差异要点:
framework.name占位符:CSF3 的 TypeScript 示例中,注释明确提示应替换为你实际使用的基于 Webpack 的框架包(例如@storybook/react-webpack5);CSF Next 的示例则提示可替换为react-vite、nextjs、nextjs-vite等框架。占位符一律形如@storybook/your-framework,直接照抄会导致配置无法解析。- CSF Next 的
defineMain:这是新一代类型安全配置 API 的入口,从@storybook/<framework>/node子路径导入,取代手写const config: StorybookConfig+export default config的模式,代码片段中defineMain已用🧪标注为实验性能力。 - TypeScript 版本的类型来源:
Options类型从@swc/core导入,保证回调参数与 SWC 官方类型严格对齐。 - 必须返回新对象:四个示例都强调"扩展后返回",即用
{ ...config }展开原配置再叠加自定义项,确保不破坏基线(包括上述默认编译目标与 bugfixes)。
实战示例:覆写 React JSX 转换配置
配置片段 main-config-swc-jsx-transform.md 给出了一个真实且简短的定制场景——控制 React JSX 的转换运行时。例如希望 Storybook 编译 React 时强制使用 automatic 运行时(不再需要显式 import React,而是让编译器自动注入 jsx 运行时导入):
export default {
framework: {
name: '@storybook/your-framework',
options: {},
},
swc: (config, options) => ({
jsc: {
transform: {
react: {
runtime: 'automatic',
},
},
},
}),
};
注意这里刻意没有展开 ...config——示例本身展示的是"整份替换"的语义:swc 回调的返回值就是最终配置。对于只想微调一两个字段、保留基线 env 目标与 bugfixes 的场景,上一节中的展开合并写法才是推荐做法;而当你希望完全接管编译行为、自行声明全部 SWC 选项(例如完整指定 jsc、env、module 等)时,直接返回整份配置同样是合法的。两种用法 API 文档均未禁止,取舍取决于你是否信任并需要 Storybook 注入的默认环境目标。
jsc.transform.react.runtime 只是 swc.Options 庞大选项空间的一角。SWC 的 Options 通常围绕以下几个顶层字段组织,你在覆写时均可按需设置:
| 顶层字段 | 作用 | 本场景中的相关子项 |
|---|---|---|
jsc |
JavaScript 解析与转换的核心配置 | jsc.transform.react.runtime(classic/automatic)、jsc.parser(syntax、tsx、decorators)、jsc.target |
env |
面向运行环境的转译目标 | env.targets(浏览器列表)、env.bugfixes、env.mode |
module |
模块输出格式 | module.type(如 es6/commonjs) |
minify |
是否启用压缩 | 布尔值或压缩配置对象 |
由于相关选项数量庞大且随 @swc/core 版本演进,官方文档的建议是:以项目实际安装的 @swc/core 类型定义为最终权威,在编辑器中对 Options 类型做自省,即可获得当前版本支持的完整字段清单与注释。
使用要点与注意事项
综合官方 API 文档、代码片段与源码实现,以下几点是使用 swc 主配置时必须注意的:
- 必须先启用对应编译器插件:
@storybook/addon-webpack5-compiler-swc是swc属性产生实际效果的先决条件。若未安装该插件,swc回调中的改动不会参与编译;若使用的是 Babel 编译器插件,则请转向babel主配置。 - 框架适用范围有边界:仅对 Webpack 系且受支持的框架生效,Angular、CRA、Ember.js、Next.js 四类项目不适用,详见前文与 main-config-swc.mdx。
.storybook/main.js|ts必须为合法 ESM:这是 主配置总览 中强调的硬性要求——文件内只能使用import而不能使用require,同时__dirname、__filename均不可用。- 默认环境目标会被继承:若你采用
{ ...config, ... }的合并写法,Webpack5 构建器预设的chrome 100 / safari 15 / firefox 91与bugfixes: true基线会继续生效;若你整份替换,则这些默认值将由你的配置自行决定。 - 配置入口位于主配置对象顶层:
swc与framework、stories、addons、babel、webpackFinal等同级,是主配置对象(config)的属性之一,而非嵌套在framework.options或addons内部。 - 必要时可区分开发/生产:通过
options.configType('DEVELOPMENT' | 'PRODUCTION')可在同一回调内对storybook dev与storybook build输出差异化的 SWC 配置。
参考资料
本文内容对应的仓库资料集中整理如下,便于深入研读:
- 官方 API 文档:main-config-swc.mdx(属性签名与适用前提)
- 官方代码片段(本文主体):main-config-swc.md、main-config-swc-jsx-transform.md
- 主配置总览(属性清单与 ESM 要求):main-config.mdx
swc预设扩展与配置类型声明:core-common.ts- Webpack5 构建器默认
swc基线(env targets + bugfixes):custom-webpack-preset.ts - 编译器插件的卫星维护声明:satellite-addons.ts
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0627
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00