Skip to content

Commit 3401d13

Browse files
committed
docs(blog): add media guidance and capture scripts for ArgsTable blog posts
1 parent f656ee8 commit 3401d13

5 files changed

Lines changed: 396 additions & 0 deletions

File tree

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
---
2+
title: 修复 Storybook MDX 中 “does not provide an export named 'ArgsTable'” 的实战
3+
description: "在 Storybook 的 blocks 打包入口显式重导出 ArgsTable,从而修复 Vite 预打包导致的 MDX 运行时导出缺失问题。"
4+
tags: [Storybook, Vite, MDX, debugging, frontend]
5+
juejin_tags: [前端, Storybook, Vite, MDX, Debug]
6+
date: 2026-01-29
7+
author: "wkylin"
8+
cover: /docs/static/images/storybook-argstable-cover.png
9+
og_image: /docs/static/images/storybook-argstable-cover.png
10+
canonical: "https://your-domain.example/blog/fix-storybook-argstable-cn"
11+
---
12+
13+
# 修复 Storybook MDX 中 “does not provide an export named 'ArgsTable'” 的实战 🐛➜✅
14+
15+
TL;DR: 在 Storybook 的 `blocks` 打包入口里显式重导出 `ArgsTable``export { ArgsTable } from './.../ArgsTable'`),并追加单元测试与兼容性说明,快速恢复 MDX 文档在 Vite 下的运行时兼容性;补丁已提交为 PR:https://github.com/storybookjs/storybook/pull/33702。
16+
17+
---
18+
19+
## 背景
20+
21+
在一个使用 Vite 与 Storybook 的组件库中(MDX 文档广泛使用 `ArgsTable`),运行 Storybook 时出现了如下运行时错误:
22+
23+
> The requested module '.../blocks.js' does not provide an export named 'ArgsTable'
24+
25+
这导致载入 MDX 的文档页面失败,Args 表格无法渲染。
26+
27+
## 问题定位(快速说明)
28+
29+
- 现象:MDX 导入 `ArgsTable` 报错,且只在开启 Vite 优化(optimizeDeps)或预打包后的环境中出现。
30+
- 检查 `.vite-cache` 下预打包产物后,发现 `blocks` 模块导出里存在 `PureArgsTable`,但缺少命名导出 `ArgsTable`
31+
- 推断原因:构建/预打包步骤(或导出重命名)将内部实现以 `PureArgsTable` 暴露,导致依赖 `ArgsTable` 的代码在运行时找不到对应命名导出。
32+
33+
> 小结:Vite pre-bundling 可能改变导出符号,导致 MDX 代码期待的命名导出不存在。
34+
35+
## 解决方案(我做了什么)
36+
37+
思路是做一个小而不侵入的兼容性修复:在 `blocks` 的入口处显式导出 `ArgsTable`,并添加一条针对性单元测试。
38+
39+
关键变更如下:
40+
41+
```diff
42+
*** Update File: code/addons/docs/src/blocks.ts
43+
@@
44+
-export { ArgsTable as PureArgsTable } from './blocks/components/ArgsTable/ArgsTable';
45+
+export { ArgsTable as PureArgsTable } from './blocks/components/ArgsTable/ArgsTable';
46+
+// Compatibility re-export so external imports of `ArgsTable` keep working.
47+
+export { ArgsTable } from './blocks/components/ArgsTable/ArgsTable';
48+
```
49+
50+
并新增测试:
51+
52+
```ts
53+
// code/addons/docs/src/__tests__/blocks.test.ts
54+
import * as blocks from '../blocks';
55+
56+
describe('blocks module compatibility exports', () => {
57+
test('exports ArgsTable', () => {
58+
expect(blocks.ArgsTable).toBeDefined();
59+
});
60+
61+
test('ArgsTable equals PureArgsTable', () => {
62+
expect(blocks.ArgsTable).toBe(blocks.PureArgsTable);
63+
});
64+
});
65+
```
66+
67+
这是一种最小改动(non-breaking)的补丁,便于快速 review 和回滚。
68+
69+
## 本地验证步骤(可复现)
70+
71+
1. 运行针对性测试:
72+
73+
```bash
74+
npm run test:jest -- code/addons/docs/src/__tests__/blocks.test.ts
75+
```
76+
77+
2. 启动 Storybook 并检查 MDX 页面:
78+
79+
```bash
80+
npm run storybook
81+
# 打开 http://localhost:6006/ 并打开含 ArgsTable 的 MDX 页面
82+
```
83+
84+
3. 备用临时方案(不改 upstream):
85+
- 在项目内添加一个 `ArgsTableFallback` shim,然后在 MDX 中使用显式的表格数据;
86+
-`.storybook/main.ts` 中把 `@storybook/addon-docs` 加入 `optimizeDeps.exclude`,并删除 .vite-cache 以避开预打包改名问题。
87+
88+
## PR 与 Issue
89+
90+
- Issue: https://github.com/storybookjs/storybook/issues/33691
91+
- PR: https://github.com/storybookjs/storybook/pull/33702
92+
93+
我已在 PR 中包含补丁、测试与 Changelog 说明,等待 upstream maintainer 审核。
94+
95+
## 后记与建议 ✅
96+
97+
- 这类问题表明:当你的开发环境(如 Vite)会进行依赖预打包或导出变换时,库的公共导出契约(named exports)很重要。保持显式导出可以减少消费端因编译器/打包器变化导致的问题。
98+
- 我建议:库方接纳这个最小兼容补丁以快速恢复用户体验;若维护者更倾向于调整 package exports 或 build pipeline,也可以用该方向做进一步改进。
99+
100+
---
101+
102+
## 截图 & GIF(建议与占位) 🖼️🎞️
103+
104+
我建议准备以下素材并放在仓库:
105+
106+
- 封面图(掘金建议尺寸:900×500px;Medium 建议 1200×630px),放置在 `docs/static/images/storybook-argstable-cover.png`
107+
- 页面截图:`docs/static/images/storybook-argstable-screenshot.png`(完整页面或关键区域)。
108+
- 录屏 GIF(短片,3-5 秒): `docs/static/images/storybook-argstable.gif`
109+
110+
我在仓库中添加了占位说明文件(`docs/static/images/README.md`)以及一个小脚本用于自动截图与录制(使用 Playwright),详情见下文。
111+
112+
## 更详细的复现步骤(逐步) 🧭
113+
114+
1. 清理 Storybook 的预打包缓存(确保复现预打包问题):
115+
```bash
116+
rm -rf .vite-cache/storybook
117+
```
118+
2. 添加一个简单的 MDX 文档(示例):
119+
```md
120+
---
121+
name: ArgsTable demo
122+
---
123+
124+
import { ArgsTable } from '@storybook/addon-docs/blocks'
125+
126+
# Demo
127+
128+
<ArgsTable of={SomeComponent} />
129+
```
130+
3. 启动 Storybook 并观察控制台错误:
131+
```bash
132+
npm run storybook
133+
```
134+
你应当在浏览器控制台或终端中看到类似错误:
135+
> The requested module '.../blocks.js' does not provide an export named 'ArgsTable'
136+
137+
4. 检查预打包产物以确认导出情况:
138+
```bash
139+
# Unix like
140+
grep -n "PureArgsTable\|ArgsTable" .vite-cache/storybook/deps/* || true
141+
```
142+
143+
5. 运行新增的单元测试验证修复:
144+
```bash
145+
npm run test:jest -- code/addons/docs/src/__tests__/blocks.test.ts
146+
```
147+
148+
## 如何自动截屏 / 生成 GIF(脚本说明) 🛠️
149+
150+
仓库已包含一个辅助脚本:`scripts/capture-storybook.js`(基于 Playwright),会:
151+
- 启动浏览器并访问 Storybook 页面的指定 path;
152+
- 保存截图到 `docs/static/images/storybook-argstable-screenshot.png`
153+
- 录制短视频(webm)到 `docs/static/images/video/`(可使用 ffmpeg 转换为 GIF)。
154+
155+
快速使用:
156+
157+
```bash
158+
# 启动 storybook
159+
npm run storybook
160+
# 在另一个终端运行脚本(设置要捕获的 story 路径)
161+
STORYBOOK_URL=http://localhost:6006 STORY_PATH='/?path=/story/your--story' node scripts/capture-storybook.js
162+
# 若想转换 webm 到 gif(需要 ffmpeg)
163+
./scripts/convert-webm-to-gif.sh docs/static/images/video/latest.webm docs/static/images/storybook-argstable.gif
164+
```
165+
166+
脚本详情请参见:`scripts/capture-storybook.js``scripts/convert-webm-to-gif.sh`
167+
168+
---
169+
170+
**需要我把封面、截图与 GIF 帮你生成并放到仓库吗?** 我可以替你运行脚本并提交生成的图片(需要你授权我启动 Storybook 并在你的环境运行脚本)。
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
---
2+
title: Fixing Storybook MDX runtime: “does not provide an export named 'ArgsTable'”
3+
description: "A minimal compatibility re-export in Storybook's blocks entry fixes an MDX runtime error caused by Vite pre-bundling renaming exports."
4+
tags: [Storybook, Vite, MDX, debugging, frontend]
5+
medium_tags: [Storybook, Vite, MDX, debugging, frontend]
6+
date: 2026-01-29
7+
author: "wkylin"
8+
cover: /docs/static/images/storybook-argstable-cover-en.png
9+
og_image: /docs/static/images/storybook-argstable-cover-en.png
10+
canonical: "https://your-domain.example/blog/fix-storybook-argstable-en"
11+
---
12+
13+
# Fixing Storybook MDX runtime: “does not provide an export named 'ArgsTable'” — diagnosis, tests, and PR 🐞➡️✅
14+
15+
TL;DR: Vite pre-bundling can rename or remap named exports (e.g., `ArgsTable``PureArgsTable`) causing MDX imports to fail at runtime. I implemented a minimal compatibility re-export in the `blocks` entry and added tests; PR: https://github.com/storybookjs/storybook/pull/33702.
16+
17+
---
18+
19+
## Background
20+
21+
A Storybook MDX file importing `ArgsTable` from `@storybook/addon-docs/blocks` started failing at runtime with:
22+
23+
> The requested module '.../blocks.js' does not provide an export named 'ArgsTable'
24+
25+
This error appeared in environments where Vite had pre-bundled dependencies (optimizeDeps), and the generated `blocks` module exposed `PureArgsTable` but not the named `ArgsTable`.
26+
27+
## Investigation
28+
29+
- Reproduced the runtime error locally while running Storybook with Vite.
30+
- Inspected the pre-bundled artifact in `.vite-cache/storybook/deps/` and confirmed `ArgsTable` missing and `PureArgsTable` present.
31+
- Considered two mitigation approaches:
32+
1. Local shim + `optimizeDeps.exclude` workaround (short-term, used in our repo);
33+
2. Upstream fix: ensure `blocks` exports the named symbol `ArgsTable`.
34+
35+
## Implemented fix
36+
37+
Minimal, non-breaking change to `code/addons/docs/src/blocks.ts`:
38+
39+
```diff
40+
-export { ArgsTable as PureArgsTable } from './blocks/components/ArgsTable/ArgsTable';
41+
+export { ArgsTable as PureArgsTable } from './blocks/components/ArgsTable/ArgsTable';
42+
+// Compatibility re-export so `ArgsTable` remains available as a named export
43+
+export { ArgsTable } from './blocks/components/ArgsTable/ArgsTable';
44+
```
45+
46+
Plus unit test at `code/addons/docs/src/__tests__/blocks.test.ts`:
47+
48+
```ts
49+
import * as blocks from '../blocks';
50+
51+
describe('blocks module compatibility exports', () => {
52+
test('exports ArgsTable', () => expect(blocks.ArgsTable).toBeDefined());
53+
test('ArgsTable equals PureArgsTable', () => expect(blocks.ArgsTable).toBe(blocks.PureArgsTable));
54+
});
55+
```
56+
57+
## How to verify locally
58+
59+
- Run the added test:
60+
61+
```bash
62+
npm run test:jest -- code/addons/docs/src/__tests__/blocks.test.ts
63+
```
64+
65+
- Start Storybook and verify MDX pages load normally:
66+
67+
```bash
68+
npm run storybook
69+
# open http://localhost:6006
70+
```
71+
72+
## Alternatives & notes
73+
74+
- Short-term: local `ArgsTable` shim that renders explicit rows and adding `@storybook/addon-docs` to `optimizeDeps.exclude` to avoid the pre-bundling changes.
75+
- Long-term: adjust package `exports` map or build pipeline to guarantee stable named exports.
76+
77+
## Links
78+
79+
- Issue: https://github.com/storybookjs/storybook/issues/33691
80+
- PR: https://github.com/storybookjs/storybook/pull/33702
81+
82+
---
83+
84+
## Screenshots & GIFs (suggestions and placeholders) 🖼️🎞️
85+
86+
Suggested assets to include in the post:
87+
88+
- Cover image (Medium: recommended 1200×630px; Juejin: 900×500px), place as `docs/static/images/storybook-argstable-cover-en.png`.
89+
- Page screenshot: `docs/static/images/storybook-argstable-screenshot.png` (full page or key area).
90+
- Short GIF: `docs/static/images/storybook-argstable.gif` (3-5s clip).
91+
92+
A `docs/static/images/README.md` is included with guidance and a small Playwright script to capture screenshots/videos automatically.
93+
94+
## Detailed reproduction steps (step-by-step) 🧭
95+
96+
1. Remove Storybook Vite pre-bundle cache (to reproduce the pre-bundling behavior):
97+
98+
```bash
99+
rm -rf .vite-cache/storybook
100+
```
101+
102+
2. Add a minimal MDX file that imports `ArgsTable`:
103+
104+
```md
105+
---
106+
name: ArgsTable demo
107+
---
108+
109+
import { ArgsTable } from '@storybook/addon-docs/blocks'
110+
111+
# Demo
112+
113+
<ArgsTable of={SomeComponent} />
114+
```
115+
116+
3. Start Storybook and observe the runtime error:
117+
118+
```bash
119+
npm run storybook
120+
```
121+
122+
You should see an error similar to:
123+
124+
> The requested module '.../blocks.js' does not provide an export named 'ArgsTable'
125+
126+
4. Inspect the pre-bundled artifact to confirm the presence of `PureArgsTable` and absence of `ArgsTable`:
127+
128+
```bash
129+
grep -n "PureArgsTable\|ArgsTable" .vite-cache/storybook/deps/* || true
130+
```
131+
132+
5. Run the added unit test to verify the fix:
133+
134+
```bash
135+
npm run test:jest -- code/addons/docs/src/__tests__/blocks.test.ts
136+
```
137+
138+
## How to capture screenshots / generate GIFs (scripted) 🛠️
139+
140+
Use the included `scripts/capture-storybook.js` (Playwright) to:
141+
142+
- navigate to a Storybook page and save `docs/static/images/storybook-argstable-screenshot.png`;
143+
- record a short webm to `docs/static/images/video/` (convert to GIF with ffmpeg if desired).
144+
145+
Quick commands:
146+
147+
```bash
148+
npm run storybook
149+
STORYBOOK_URL=http://localhost:6006 STORY_PATH='/?path=/story/your--story' node scripts/capture-storybook.js
150+
./scripts/convert-webm-to-gif.sh docs/static/images/video/latest.webm docs/static/images/storybook-argstable.gif
151+
```
152+
153+
---
154+
155+
If you'd like, I can run the capture script locally and commit the images to the repo (I will need permission to run Storybook in your environment).

docs/static/images/README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
Images for the "Fixing Storybook ArgsTable" blog posts
2+
3+
Place images here and commit them when ready.
4+
5+
- Cover (CN): storybook-argstable-cover.png (recommended Juejin size: 900x500)
6+
- Cover (EN): storybook-argstable-cover-en.png (Medium recommended: 1200x630)
7+
- Screenshot: storybook-argstable-screenshot.png (full page or focused area)
8+
- GIF: storybook-argstable.gif (3-5 seconds, under 5MB recommended)
9+
10+
You can use the helper script `scripts/capture-storybook.js` to capture a screenshot and record a short webm video. Convert webm to gif using `scripts/convert-webm-to-gif.sh` (requires ffmpeg).

scripts/capture-storybook.js

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
#!/usr/bin/env node
2+
// Simple Playwright-based script to capture a screenshot and record a short video of a Storybook page.
3+
// Usage: STORYBOOK_URL=http://localhost:6006 STORY_PATH='/?path=/story/your--story' OUT_DIR=docs/static/images node scripts/capture-storybook.js
4+
5+
const { chromium } = require('playwright');
6+
const fs = require('fs');
7+
8+
(async () => {
9+
const url = process.env.STORYBOOK_URL || 'http://localhost:6006';
10+
const path = process.env.STORY_PATH || '/';
11+
const out = process.env.OUT_DIR || 'docs/static/images';
12+
fs.mkdirSync(out, { recursive: true });
13+
const videoDir = `${out}/video`;
14+
fs.mkdirSync(videoDir, { recursive: true });
15+
16+
const browser = await chromium.launch();
17+
const context = await browser.newContext({ recordVideo: { dir: videoDir, size: { width: 1280, height: 720 } } });
18+
const page = await context.newPage();
19+
20+
console.log('Going to', url + path);
21+
await page.goto(url + path, { waitUntil: 'load', timeout: 60000 });
22+
// allow animations / lazy-loaded content
23+
await page.waitForTimeout(1500);
24+
25+
const screenshotPath = `${out}/storybook-argstable-screenshot.png`;
26+
await page.screenshot({ path: screenshotPath, fullPage: true });
27+
console.log('Saved screenshot:', screenshotPath);
28+
29+
// keep the video recording for a short time
30+
await page.waitForTimeout(2500);
31+
await context.close(); // this finalizes the video file
32+
await browser.close();
33+
34+
// find the newest file in the video directory
35+
const files = fs.readdirSync(videoDir).map(f => ({ f, t: fs.statSync(`${videoDir}/${f}`).mtimeMs })).sort((a,b)=>b.t-a.t);
36+
if (files.length) {
37+
const latest = `${videoDir}/${files[0].f}`;
38+
console.log('Saved video (webm):', latest);
39+
} else {
40+
console.log('No video file found in', videoDir);
41+
}
42+
43+
console.log('Done. Convert the webm to gif using ffmpeg if you need GIFs.');
44+
process.exit(0);
45+
})().catch(e => { console.error(e); process.exit(1); });

0 commit comments

Comments
 (0)