Storybook 切换 framework 到 @storybook/nextjs-vite:从配置原理到迁移实战的完整指南
【免费下载链接】storybookStorybook is the industry standard workshop for building, documenting, and testing UI components in isolation项目地址: https://gitcode.com/GitHub_Trending/st/storybook
本文聚焦 Storybook 仓库中 nextjs-vite-add-framework.md 所演示的核心操作:把.storybook/main.js|ts中的framework属性切换到@storybook/nextjs-vite,并同步更新配置入口的类型导入(CSF 3 的StorybookConfig与 CSF Next 的defineMain两种风格)。读完后,你将能够独立完成 Next.js 项目从 Webpack 系框架(如@storybook/react-webpack5、@storybook/nextjs)到 Vite 系框架的切换,并理解该配置项在 Storybook 内部到底驱动了哪些构建行为,以及切换后还需做哪些收尾工作。
一、这条配置改动到底在做什么
在 Next.js 项目的 Storybook 中,framework字段决定了“用什么框架预设来渲染组件、用什么构建器来打包”。切换到@storybook/nextjs-vite的完整改动如下(对应 nextjs-vite-add-framework.md 中的 diff 片段):
JavaScript 项目(.storybook/main.js,CSF 3):
export default { // ... - framework: '@storybook/react-webpack5', + framework: '@storybook/nextjs-vite', };TypeScript 项目(.storybook/main.ts,CSF 3)——注意导入的类型来源也要同步更换:
- import type { StorybookConfig } from '@storybook/your-previous-framework'; + import type { StorybookConfig } from '@storybook/nextjs-vite'; const config: StorybookConfig = { // ... - framework: '@storybook/react-webpack5', + framework: '@storybook/nextjs-vite', }; export default config;新配置风格(CSF Next 实验性写法,defineMain从框架包的/node入口导入):
- import { defineMain } from '@storybook/your-previous-framework/node'; + import { defineMain } from '@storybook/nextjs-vite/node'; export default defineMain({ // ... - framework: '@storybook/react-webpack5', + framework: '@storybook/nextjs-vite', });仓库源码可以佐证这两处导入的真实来源:
/node入口确实存在。package.json 的exports字段声明了"./node": { "code": "./src/node/index.ts", ... },而 node/index.ts 的内容非常简洁——它只导出一个defineMain(config)函数,原样返回带@storybook/nextjs-vite类型约束的StorybookConfig对象:import type { StorybookConfig } from '../types.ts'; export function defineMain(config: StorybookConfig) { return config; }因此把
defineMain的导入路径从旧框架换成@storybook/nextjs-vite/node,本质上是让main.ts里的framework与core.builder字段获得@storybook/nextjs-vite专属的类型约束。类型层面也做了框架绑定。types.ts 中定义了
FrameworkName = CompatibleString<'@storybook/nextjs-vite'>,StorybookConfig类型要求framework只能是'@storybook/nextjs-vite'或{ name, options }对象形式,且core.builder只能是@storybook/builder-vite。如果你把framework写错,TypeScript 会直接报错——这也是为什么 diff 里要求同步更换StorybookConfig的类型导入。
二、切换后的底层行为:preset 是如何工作的
仅改framework字段之所以能完成整个构建链的切换,是因为框架包通过 preset 预设接管了构建器与渲染器。查看 preset.ts 可以看到关键实现:
export const core: PresetProperty<'core'> = { builder: import.meta.resolve('@storybook/builder-vite'), renderer: import.meta.resolve('@storybook/react/preset'), };从源码结构看:
core.builder指向@storybook/builder-vite,core.renderer指向@storybook/reactpreset——也就是说,framework: '@storybook/nextjs-vite'一句配置,实际等价于“Vite 构建器 + React 渲染器”的组合,这正是它与@storybook/nextjs(Webpack 5 构建器)的核心区别;previewAnnotations会把@storybook/nextjs-vite/preview(以及 Next.js 16 以下的兼容版@storybook/nextjs-vite/config/preview)追加为 preview 注解,从而注入路由/导航桩、next/image与next/font支持、next/head装饰器等 preview 层能力,这些能力无需用户额外注册;viteFinal会先调用@storybook/react-vite/preset的viteFinal拿到基础 React Vite 配置,然后在此基础上:自动归一化 PostCSS 配置(normalizePostCssConfig,从而支持你项目里的 Tailwind/PostCSS 定制)、把styled-jsx及其style子模块写入resolve.alias(零配置支持 styled-jsx)、最后追加vitePluginStorybookNextjs插件来处理nextConfigPath/image等框架选项。
三、framework 的 options 参数:切换时的进阶配置
types.ts 中的FrameworkOptions定义了切换framework时可同时传入的选项,写作对象形式:
export type FrameworkOptions = { /** The path to the Next.js configuration file. */ nextConfigPath?: string; image?: { includeFiles?: string[]; excludeFiles?: string[]; }; builder?: BuilderOptions; };对应的.storybook/main.ts用法(取自 nextjs-vite.mdx 的 Options 一节):
import type { StorybookConfig } from '@storybook/nextjs-vite'; const config: StorybookConfig = { // ... framework: { name: '@storybook/nextjs-vite', options: { // 当 next.config.js 不在项目根目录时必须提供 nextConfigPath: '/path/to/your/next.config.js', }, }, }; export default config;各选项的作用(结合 preset.ts 中options.presets.apply<FrameworkOptions>('frameworkOptions')的消费逻辑):
nextConfigPath(string):next.config.js的绝对路径。preset 会取它的dirname作为dir传给 Next.js 的 Vite 插件,用于定位你的 Next.js 项目结构;image(object):与 Vite 插件交互的图片处理选项(含includeFiles/excludeFiles过滤规则),决定哪些文件走next/image风格的导入转换;builder(Record<string, any>):透传给@storybook/builder-vite的构建器选项,如test相关配置。
框架贡献的 stories 参数则在NextJsParameters中声明(同样见 types.ts):nextjs.appDirectory(boolean,默认false,next/navigation组件故事需置true)、nextjs.navigation(next/navigation上下文覆盖)与nextjs.router(next/router上下文覆盖),可按 story / meta / 项目三级 parameters 继承。这些参数在切换到该框架后即可直接使用,是它与旧 Webpack 框架相比新增的运行时能力。
四、切换前后的收尾工作
framework字段只是迁移的一部分。nextjs-vite.mdx 的 “Manual migration” 章节(本文关联 diff 片段的实际使用处)指出了切换后必须核对的两件事:
webpackFinal→viteFinal:如果旧配置里存在自定义 Webpack 操作(webpackFinal),需要手工改写成等价的 Vite 配置(viteFinal)。注意并非所有 Webpack 修改可以原样照搬,需结合 Vite 的插件与 resolve 机制重写;.md文件导入:Webpack 时代直接import content from './doc.md'得到的字符串行为,在 Vite 下需要显式加?raw后缀。
此外,若你之前用独立的插件(addon)来集成 Next.js 的路由/导航能力,切换到该框架后这些能力已由框架内置,相关插件可以移除。
更稳妥的做法:automigrate 工具
如果你的旧框架是@storybook/nextjs,仓库内置了自动迁移工具,等价于上面所有手工步骤:
npx storybook automigrate nextjs-to-nextjs-vite从 nextjs-to-nextjs-vite.ts 的源码可以确认它执行三步动作,与本文“Manual migration”完全对应:
- 更新所有
package.json:移除@storybook/nextjs,按当前 Storybook 版本添加@storybook/nextjs-vite(若项目未装 Vite,还会补装vite@^7.0.0,见源码中的VITE_DEFAULT_VERSION); - 改写
.storybook/main.js|ts,用负向先行断言正则/@storybook\/nextjs(?!-vite)/g精确替换框架名,避免误伤已经是-vite的引用; - 扫描 stories 与配置目录中的所有导入语句,把
@storybook/nextjs的导入批量重写为@storybook/nextjs-vite。
而本文关联文档覆盖的场景是从任意旧框架(示例中为@storybook/react-webpack5)切入@storybook/nextjs-vite,这类切换没有自动工具,需要按第一、二节的 diff 手工完成。
五、版本前提与验证清单
从 package.json 的peerDependencies可确认适用前提:next要求^14.1.0 || ^15.0.0 || ^16.0.0,vite要求^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0,React 支持 16.8+ 至 19.x。切换完成后建议按以下清单验证:
framework字段与StorybookConfig/defineMain的导入源已同步为@storybook/nextjs-vite(TypeScript 项目若不同步,类型检查会报错);- 旧的
webpackFinal已迁移为viteFinal,.md导入已加?raw; - 启动 dev server 后,
next/image、next/font、路由/导航桩与nextjs.*参数按预期工作(详见 nextjs-vite.mdx 各特性章节)。
参考路径
- docs/_snippets/nextjs-vite-add-framework.md —— 本文关联的 framework 切换 diff 片段
- docs/get-started/frameworks/nextjs-vite.mdx —— 该框架的完整文档(安装、配置、API、FAQ)
- code/frameworks/nextjs-vite/src/preset.ts ——
core/previewAnnotations/viteFinal预设实现 - code/frameworks/nextjs-vite/src/node/index.ts ——
defineMain入口 - code/frameworks/nextjs-vite/src/types.ts ——
StorybookConfig、FrameworkOptions、NextJsParameters类型定义 - code/lib/cli-storybook/src/automigrate/fixes/nextjs-to-nextjs-vite.ts —— 自动迁移工具实现
【免费下载链接】storybookStorybook is the industry standard workshop for building, documenting, and testing UI components in isolation项目地址: https://gitcode.com/GitHub_Trending/st/storybook
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考