ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Storybook 中生成 MSW Service Worker:为组件 Stories 接入网络请求 Mock 的完整配置指南

Storybook 中生成 MSW Service Worker:为组件 Stories 接入网络请求 Mock 的完整配置指南 Storybook 中生成 MSW Service Worker为组件 Stories 接入网络请求 Mock 的完整配置指南本指南聚焦 Storybook 文档中Mocking network requests模拟网络请求一节的核心前置步骤——通过msw init生成 Mock Service WorkerMSW所需的 Service Worker 文件并结合staticDirs、项目级 loader 与beforeEach({ msw })完成 REST/GraphQL 请求的 Story 级拦截。读完本文你将能在自己的 Storybook 工作区中一键产出可用的mockServiceWorker.js并让 MSW 插件接管组件运行期间发出的真实网络请求。相关配套文档见 mocking-network-requests.mdx本次讲解的命令原文出自 msw-generate-service-worker.md。为什么 Stories 需要先生成一个 Service WorkerMSW 是一套基于 Service Worker 的 API 拦截方案它在浏览器预览环境中注册一个 Service Worker 脚本来捕获 fetch/XHR 请求并返回由请求处理器handler准备的假数据。对于会发起真实网络请求的组件例如从 REST 或 GraphQL API 拉取数据的页面Storybook 里渲染这些组件时既不应该真的打到后端也不应该让故事因网络不可用而失败因此官方文档建议使用 MSW 插件msw-storybook-addon把 Mock 能力带进 Stories。而生成 Service Worker 文件正是这条链路的物质基础只有在项目静态目录中先放置 MSW 运行时脚本浏览器才有可注册的 Worker 去接管后续请求。该文件并非手写而是由 MSW 官方 CLI 的命令msw init 目录一次性产出。也就是说生成 Worker 这一步不是可选项而是使用 MSW 插件在 Storybook 中拦截请求的前置条件。完整接入流程总览围绕本主题官方文档给出了一个可复制的四步流水线安装msw与msw-storybook-addon安装命令见 msw-addon-install.md以 devDependency 形式写入运行msw init生成 Service Worker 文件本文核心命令见 msw-generate-service-worker.md在 Storybook 配置中通过staticDirs把 Worker 所在目录设为静态资源目录配置示例见 main-config-static-dirs.md初始化插件并将其注册到所有 StoriesCSF 3 使用项目级loaders: [mswLoader()]CSF Next 则在definePreview中通过addons: [addonMsw()]注册示例见 msw-addon-initialize.md。后续在编写 Story 时再通过beforeEach({ msw })注入当前 Story 专属的请求处理器。下面按此顺序逐层展开重点是第 2、3 步与命令背后的参数含义。一条命令生成 Service Worker三种包管理器的等价写法原文档针对不同包管理器给出了三份等价命令正文均为npmnpx msw init ./public --saveyarnyarn dlx msw init ./public --savepnpmpnpm dlx msw init ./public --save三者通过不同的包管理器临时执行mswCLI效果一致可根据团队实际使用的包管理器任选其一执行。命令逐段拆解如下参数含义说明initMSW CLI 的子命令用于在指定目录中初始化/生成 Service Worker 脚本./publicWorker 文件的输出目录默认放在项目的public目录最终产出./public/mockServiceWorker.js--save记录配置让 CLI 记住 Worker 输出目录便于后续维护时无需重复指定完整参数执行成功后会生成mockServiceWorker.js——一个体积小、自包含的浏览器端运行时脚本负责在页面与网络之间充当拦截代理。注意该文件不应手工改动它需要与所安装的msw版本保持严格一致当升级msw依赖后通常需要重新执行一次生成命令以更新 Worker 脚本。Angular 项目的目录差异官方特别提醒官方文档在原命令后附加了一条框架相关的提醒Angular 项目很可能需要调整目录参数把 Worker 保存到不同于默认值的位置例如保存到src目录。原因在于 Angular 项目的构建与静态资源组织方式与其他前端脚手架不同Worker 必须放在能被浏览器按预期 URL 访问到的位置。因此 Angular 用户应把命令改写为类似npx msw init ./src --save的形式并同步调整下一步staticDirs的指向。用 staticDirs 把 Worker 暴露给 Storybook 预览仅生成文件还不够。Storybook 的预览运行在一个 iframe 环境中浏览器要能请求到mockServiceWorker.js就必须让该文件所在的目录成为 Storybook 可服务的静态目录。这正是staticDirs的作用。配置位于.storybook/main.js或对应的main.ts中。官方给出的通用配置示例main-config-static-dirs.md默认已将../public纳入静态目录export default { framework: storybook/your-framework, stories: [../src/**/*.mdx, ../src/**/*.stories.(js|jsx|mjs|ts|tsx)], staticDirs: [../public, ../static], };若你生成的 Worker 在默认的public目录默认项目脚手架恰好把它配置为静态目录则无需改动但若像 Angular 那样把 Worker 放到了src就必须把对应目录补进staticDirs并保证这里的相对路径从.storybook/出发能正确解析到 Worker 文件否则插件在注册阶段将无法拉取到 Worker 脚本。初始化插件让所有 Stories 都能访问 Mock 上下文Worker 就位后需要让 Storybook 在渲染每个 Story 前启动 MSW 拦截环境。官方文档给出了两种写法见 msw-addon-initialize.md。CSF 3 时代在.storybook/preview.js或preview.ts中注册项目级 loaderimport { mswLoader } from msw-storybook-addon/csf3; export default { loaders: [mswLoader()], };使用 CSF Next实验性时则在definePreview中把插件声明为 addonimport { definePreview } from storybook/your-framework; import addonMsw from msw-storybook-addon; export default definePreview({ addons: [addonMsw()], });loader 被注册在项目级意味着对项目中所有 Stories 生效每个 Story 渲染前都会准备好msw上下文供我们在 Story 定义中使用见下节。这是把网络 Mock 无缝接入每个组件故事的总开关缺少该步骤则后续beforeEach({ msw })拿不到可用实例。在 Stories 中按需拦截 REST 与 GraphQL 请求完成上述基础设施后即可编写真正拦截网络请求的 Stories。官方文档以 DocumentScreen 为例给出成功与失败两条 Story本文摘录其 REST 版本核心形态完整示例见 msw-addon-configure-handlers-http.mdimport { http, HttpResponse, delay } from msw; import type { Meta, StoryObj } from storybook/your-framework; import { DocumentScreen } from ./YourPage; const meta { component: DocumentScreen, } satisfies Metatypeof DocumentScreen; export default meta; type Story StoryObjtypeof meta; export const MockedSuccess: Story { beforeEach({ msw }) { msw.use( http.get(https://your-restful-endpoint/, () { return HttpResponse.json(TestData); }), ); }, }; export const MockedError: Story { beforeEach({ msw }) { msw.use( http.get(https://your-restful-endpoint, async () { await delay(800); return new HttpResponse(null, { status: 403 }); }), ); }, };要点解读beforeEach({ msw })在每个 Story 渲染前执行msw.use(...)用于追加或覆盖当前请求处理器http.get来自msw核心库HttpResponse.json用于快速返回 JSON Mock 数据delay(800)可模拟真实网络延迟配合new HttpResponse(null, { status: 403 })即可构造加载中—失败的交互时序同一份数据在成功与失败两个 Story 间切换就足以驱动组件把加载态、成功态、错误态三种 UI 完整展示出来这正是组件测试与文档展示中最常用的手法。GraphQL 场景思路一致只是把http.get换成graphql.query(AllInfoQuery, ...)并以{ data: { ... } }或{ errors: [...] }结构返回响应官方同样提供了查询成功与访问被拒两个 Story 的对照写法见 msw-addon-configure-handlers-graphql.md并配套展示了 ReactApollo Client、SvelteURQL、Vue3、Angular 等不同框架下如何为组件提供 Mock 客户端包裹层。处理器的作用域Story 级 / 组件级 / 项目级从官方示例可以观察到一个重要的可伸缩规律beforeEach不只可以写在单个 Story 上还可以提升到不同层级Story 级仅在某个 Story 渲染前注册适合成功/失败这类单点对照组件meta级把beforeEach写在组件导出的meta上该文件内的所有 Stories 共享同一组处理器项目级把注册动作放进preview.js/ts对整个项目的全部 Stories 生效适合全局性的默认 Mock。若使用 CSF 3还可以通过msw参数在 Story/组件/项目三个维度声明处理器官方文档建议参考该页面对应旧版本的内容了解msw参数的具体写法。层级化的注册方式让 Mock 逻辑能够跟随组件规模自然演进避免在大型项目中重复堆叠处理器。版本注意事项面向 MSW addon v3官方文档特别指出上文涉及的命令与代码片段面向MSW 插件 v3。若项目仍在使用 v2其接入方式与 API 有差异需要查阅历史版本页面进行对照。升级到 v3 后可使用社区提供的 codemod 一键迁移配置与 Storiesnpx msw-storybook-migrate该迁移命令的作用是把 v2 时代的旧式写法自动改写为 v3 语法如msw参数迁移为beforeEach({ msw })风格降低升级摩擦。从仓库证据看Storybook 官方文档树以该命令配合 Callout 警告框的方式明确了 v2/v3 的行为边界见 mocking-network-requests.mdx。验证与常见排错路径完成上述配置后可通过以下清单确认链路是否打通文件存在性确认生成命令在预期目录产出了mockServiceWorker.js默认public/下Angular 通常在src/下且未手工改动内容版本一致性升级msw依赖后重新执行一次生成命令避免 Worker 脚本与库版本错配导致静默失效静态目录核对.storybook/main.js中staticDirs确实包含了 Worker 所在目录且路径从.storybook/出发可正确解析全局注册确认.storybook/preview.js里已有loaders: [mswLoader()]CSF 3或definePreview中注册了addonMsw()CSF Next否则 Story 中的msw上下文不可用作用域正确确认目标beforeEach挂在正确的层级Story/meta/project避免出现处理器注册了却未生效的错觉。至此从生成 Service Worker 到 Story 级 REST/GraphQL 拦截的完整闭环已经建立msw init提供拦截运行时staticDirs保证它可被访问mswLoader/addonMsw把 Mock 能力注入每个 Story而beforeEach({ msw })则让你为不同故事精准编排各自的成功、失败与延迟场景。创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表