Storybook 全局 Parameters 配置详解:在 .storybook/preview 中定义项目级参数
本篇围绕 Storybook 仓库中的官方代码片段 parameters-in-preview.md 展开,讲解如何在 .storybook/preview 文件中通过 parameters 导出为所有 story 配置全局元数据。读完本文,你将掌握全局参数的 CSF 3 与 CSF Next(definePreview)两种写法、各框架下的配置差异,并能结合 @storybook/core 源码理解参数在 project、meta、story 三层之间的深合并规则。
什么是全局 Parameters
Parameters 是附在 story 上的一组静态命名元数据,通常用于控制 Storybook 功能与 addon 的行为。它们可以在三个层级指定:
- Story 级:定义在 story(具名导出)的
parameters属性上,只对该 story 生效; - Meta(组件)级:定义在 CSF 文件默认导出(
defineMeta/meta)的parameters上,对该文件内所有 story 生效; - Project(全局)级:即本文主题,定义在
.storybook/preview.ts|tsx文件的默认导出中,作用于项目中每一个 story。
本文引用的官方文档上下文见 Parameters 指南 的 “Global parameters” 小节与 Parameters API 参考 的 “Project parameters” 小节,两者都内嵌了同一个代码片段。官方指南指出:“设置全局参数是配置 addon 的常见方式。以 backgrounds 为例,它决定了每个 story 可渲染的背景列表。”
配置方式一:CSF 3 写法
CSF 3 下,全局参数通过 preview 文件的默认导出直接声明。原始片段提供了 JS 与 TS 两种版本。
JavaScript(.storybook/preview.js 或 .storybook/preview.jsx):
export default {
parameters: {
backgrounds: {
options: {
light: { name: 'Light', value: '#fff' },
dark: { name: 'Dark', value: '#333' },
},
},
},
};
TypeScript(.storybook/preview.ts 或 .storybook/preview.tsx):
// 将 your-framework 替换为你实际使用的框架,如 react-vite、nextjs、vue3-vite 等
import type { Preview } from '@storybook/your-framework';
const preview: Preview = {
parameters: {
backgrounds: {
options: {
light: { name: 'Light', value: '#fff' },
dark: { name: 'Dark', value: '#333' },
},
},
},
};
export default preview;
TS 版本的关键点在于用对应框架 renderer 包导出的 Preview 类型对 preview 对象做类型标注,这样 parameters 下的键(如 backgrounds)能获得来自 essentials 与已安装 addon 的类型提示。backgrounds.options 中每个条目是一个 { name, value } 对象,name 显示在背景工具栏中,value 是实际应用于画布背景的颜色值或 CSS 选择器。
配置方式二:CSF Next 写法(definePreview)
片段中带有 “CSF Next 🧪” 标签的示例展示的是较新的 definePreview 配置形态,其结构相同,只是把默认导出包装成了 definePreview(...) 调用,可获得更完整的类型推导。片段为四种框架 renderer 分别给出了写法:
React(通用模板,your-framework 替换为 react-vite、nextjs、nextjs-vite 等):
// 将 your-framework 替换为你实际使用的框架(如 react-vite、nextjs、nextjs-vite)
import { definePreview } from '@storybook/your-framework';
export default definePreview({
parameters: {
backgrounds: {
options: {
light: { name: 'Light', value: '#fff' },
dark: { name: 'Dark', value: '#333' },
},
},
},
});
在仓库中,框架包确实按此约定导出 definePreview。以 react-vite 的入口 为例,其实现是一行再导出:
export { __definePreview as definePreview } from '@storybook/react';
即各框架包(@storybook/react-vite、@storybook/vue3-vite 等)统一把核心 @storybook/react 等包中的 __definePreview 以 definePreview 名义暴露给用户。
Vue 3(@storybook/vue3-vite)、Angular(@storybook/angular)、Web Components(@storybook/web-components-vite)的写法与上面完全同构,仅导入来源不同:
import { definePreview } from '@storybook/vue3-vite';
export default definePreview({
parameters: {
backgrounds: {
options: {
light: { name: 'Light', value: '#fff' },
dark: { name: 'Dark', value: '#333' },
},
},
},
});
片段中还保留了与每种 TS 写法一一对应的 JS 版本(.storybook/preview.js),源码中的注释说明了原因:“在同时提供 CSF 3 与 Next 两种示例期间,JS 片段仍然需要保留”,即文档站会为 JS/TS 用户提供可切换的标签页。
全局参数如何被解析:源码视角
全局参数写入 preview 文件后,会在预览端经历两步归一化,均可在 @storybook/core 源码中查证。
第一步:收集 preview 文件导出的字段。 在 composeConfigs 中,所有 annotations 模块(preview 文件、加载的 preset 等)的导出被逐字段合成,其中项目级参数正是调用 combineParameters 完成:
// composeConfigs.ts(L51)
parameters: combineParameters(...getField(moduleExportList, 'parameters')),
第二步:按 “项目 → 组件 → story” 顺序逐 story 合并。 在 prepareStory 中,每个 story 的最终参数由三级 parameters 依次合并得出:
const parameters: Parameters = combineParameters(
projectAnnotations.parameters, // 第 1 层:.storybook/preview 中的全局参数
componentAnnotations.parameters, // 第 2 层:CSF 默认导出(meta)
storyAnnotations?.parameters // 第 3 层:story 具名导出
);
可见本文讲解的 preview 级参数处于合并链的最底层,为整个项目提供默认值,之后被 meta 级、story 级参数逐层覆盖。
合并语义:objects 深合并、arrays 整体覆盖
combineParameters 的具体实现在 parameters.ts。其算法可以概括为:
- 后传入的参数集按键逐项覆盖先前的值,除非新值与旧值都是纯对象(plain object)——此时该键被标记为“需深合并”,最后递归调用自身合并;
- 数组被视为标量,直接整体替换,不做拼接;
undefined的新值不参与覆盖(“ignores undefined additions”)。
这四条语义与其单元测试 parameters.test.ts 完全一致:
// 同键标量:后者胜出
combineParameters({ a: 'b', c: 'd' }, { e: 'f', a: 'g' }) // => { a: 'g', c: 'd', e: 'f' }
// 子键深合并
combineParameters({ ns: { a: 'b', c: 'd' } }, { ns: { e: 'f', a: 'g' } })
// => { ns: { a: 'g', c: 'd', e: 'f' } }
// 数组按标量处理:整体替换
combineParameters({ ns: { array: [1, 2, 3] } }, { ns: { array: [3, 4, 5] } })
// => { ns: { array: [3, 4, 5] } }
// undefined 不覆盖已有值
combineParameters({ a: 1 }, { a: 2 }, { a: undefined }) // => { a: 2 }
这带来两个实战结论:
- 局部微调全局配置是安全的。例如全局定义了
backgrounds.options,某个 story 只重写backgrounds.grid,options会原样保留——这正是官方指南强调的“参数是合并的,键只会被覆盖、不会被丢弃”,也是开发依赖 parameters 的 addon 时必须考虑的行为; - 数组类参数(如
options.order这类列表)在覆盖层是全量替换而非追加,若想在 story 级“追加”数组项,需要在更具体的层级显式写出完整数组。
同样的合并函数还被 argTypes、controls 推断(inferControls.ts)、CSF 工厂(csf-factories.ts)等模块复用,说明“后者优先的对象深合并”是 Storybook 全项目统一的元数据合并契约,parameters 只是其中最常用的一条。
适用前提与注意事项
- 本写法适用于当前仓库对应的 Storybook 版本(CSF 3 与 CSF Next 并存期):
preview文件支持js|jsx|ts|tsx后缀;CSF Next 的definePreview示例在片段中带有实验标签(🧪),意味着它面向“CSF Next”新故事格式,迁移前建议在自己的项目上验证; - 各框架包的导入路径不同(
@storybook/react-vite、@storybook/vue3-vite、@storybook/angular、@storybook/web-components-vite等),示例中的your-framework占位符需按实际安装框架替换; - 全局参数中也有例外项:如
options参数(storySort等)按 API 参考 的说明只能在项目级(preview 文件)生效,这恰好印证了 preview 级 parameters 是“整个 Storybook 行为的最终兜底配置位”。
小结
docs/_snippets/parameters-in-preview.md 所承载的官方示例,本质上教的是 Storybook 参数继承链的“最底层”——在 .storybook/preview 中导出 parameters,为全部 story 提供 addon 默认配置(示例以 backgrounds.options 的 Light/Dark 两个背景项为例)。CSF 3 下直接默认导出并(TS 中)标注 Preview 类型即可,CSF Next 下则改用各框架包导出的 definePreview 包装。理解 prepareStory.ts 中的三级 combineParameters 调用与 parameters.ts 的“对象深合并、数组整体覆盖、undefined 不覆盖”规则后,你就能准确预测任意层级参数声明的最终生效值,并据此设计自己的 addon 参数接口。
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