---
sidebar_position: 5
---

# 使用 Storybook

首先如果没有看过以下内容的话，可以先花几分钟先了解一下：

- [使用微生成器开启 Storybook 调试](/guide/basic/use-micro-generator#storybook-调试)
- [`modern dev`](/guide/basic/command-preview#modern-dev)

[Storybook](https://storybook.js.org/) 是一个专门用于组件调试的工具，它围绕着组件开发提供了：

- 丰富多样的调试能力
- 可与一些测试工具结合使用
- 可重复使用的文档内容
- 可分享能力
- 工作流程自动化

因此 Storybook 是一个复杂且功能强大的工具。

Module Tools 集成了 Storybook，因此你几乎可以按照 Storybook 官方文档的内容进行使用。不过依然有一些地方需要注意，接下来讲解一下。

## 调试代码

在调试代码过程中需要引入项目代码，目前可以通过两种方式引入项目代码：

- 引用项目产物
- 引用项目源码

我们推荐使用第一种“**引用项目产物**”的方式。因为它更接近真实的使用场景，不仅可以对组件功能进行调试，同时也对构建产物的正确性进行了验证。不过我们也可以在测试项目功能的时候引用源码，在验证项目产物的时候引用项目的包名。

接下来我们分别讲一下这两种方式具体如何使用。

### 引用组件产物

假如存在 TypeScript 项目 `foo`：

<CH.Spotlight>

```json package.json
{
  "name": "foo",
  "main": "./dist/index.js",
  "types": "./dist/types/index.d.ts"
}
```

---

确保 `package.json` 的 `main` 和 `types`
的值为正确的产物路径。

```json package.json
{
  "name": "foo",
  "main": "./dist/index.js",
  "types": "./dist/types/index.d.ts"
}
```

---

`foo` 项目的源码。

```ts src/index.ts
export const content = 'hello world';
```

---

确保在 `stories/tsconfig.json` 中设置了指向项目根目录的 `paths` 配置。
`paths` 的 `key` 与项目名称相同，这样在编译过程中以及在代码中不会出现问题。

```json stories/tsconfig.json focus=5:7
{
  "extends": "../tsconfig.json",
  "compilerOptions": {
    "baseUrl": "../",
    "paths": {
      "foo": ["."],
      "foo/*": ["./*"]
    }
  },
  "include": [
    "**/*"
  ]
}
```

---

在 Story 代码中直接以项目名称的方式引用。

```tsx stories/index.stories.tsx focus=1:1
import { content } from 'foo';

const Component = () => <div>this is a Story Component {content}</div>;

export const YourStory = () => <Component />;

export default {
  title: 'Your Stories',
};
```

---

最后在执行命令的时候，先启动监听模式的源码构建，然后启动 Storybook 调试。

<CH.Code>

``` bash terminal-1
## 源码构建
modern build --watch
```

---

``` bash terminal-2
## Storybook 调试
modern dev storybook
```

</CH.Code>

</CH.Spotlight>

:::info
在开发过程中，可能会遇到无法实时获得类型定义的情况。因为只有当保存代码后，产物目录下的类型文件才会更新。此时：

对于 `pnpm` 的项目，可以按照下面的内容对 `package.json` 进行修改：

```ts focus=4:7
{
    "name": "foo",
    "main": "./dist/index.js",
    "types": "./src/index.ts",
    "publishConfig": {
      "types": "./dist/index.d.ts",
    }
}
```

> 关于 pnpm 的 `publishConfig` 的使用，可以阅读下面这个[链接](https://pnpm.io/package_json#publishconfig)。

而对于 npm 和 Yarn 的项目，则只能通过手动的方式在**开发阶段**和**发布阶段**对 `package.json` 的 `types` 的值进行修改。
:::

那么为什么可以直接引用产物呢？

1. 在执行 `modern dev storybook` 命令之前，执行 `modern build --watch` 命令，保证项目构建产物的存在。
2. 在 Storybook 内部增加了根据 `tsconfig.json` 文件的 `compilerOptions.paths` 配置或者（在 JS 项目中）直接以项目名称作为别名的处理逻辑，保证能够**根据 `package.json` 解析出项目的产物路径**。

### 引用组件源码

引用组件的源码可以通过相对路径的方式：

```ts ./stories/index.tsx
import { content } from '../src';

const Component = () => <div>this is a Story Component {content}</div>;

export const YourStory = () => <Component />;

export default {
  title: 'Your Stories',
};
```


:::tip 为什么不推荐使用源码的方式?
不仅仅是因为使用组件源码无法验证组件产物是否正确，**同时模块工程对于构建产物支持的一些配置无法完全转换为 Storybook
内部的配置**。如果某些配置无法进行相互转换的话，就会在 Storybook 调试过程中出现不符合预期的结果。

Module Tools 是基于 esbuild 实现的，而 Storybook 是基于 Webpack 实现的。esbuild 的配置无法与 Webpack 完全兼容。
:::

## 配置 Storybook

Storybook 官方通过一个名为 `.storybook` 的文件夹来进行项目配置，其中包含各种配置文件。**在模块工程方案中，可以在项目的 `config/storybook` 目录下增加 Storybook 配置文件。**

关于 Storybook 各种配置文件的使用方式，可以查看下面的链接：

- [Configure Storybook](https://storybook.js.org/docs/react/configure/overview)

**不过在模块项目里进行 Storybook 存在一些限制**：

- 目前不能修改 Story 文件存放的位置，即无法在 `main.js` 文件里修改 `stories` 配置。
- 目前不能修改 Webpack 和 Babel 相关的配置，即无法在 `main.js` 文件里修改 `webpackFinal` 和 `babel` 配置。

在未来我们会考虑这些配置是否可以允许修改，不过目前为了减少不可预知的问题暂时限制使用这些配置。


## 构建 Storybook 产物

除了可以对组件或者普通的模块进行 Storybook 调试，还可以通过下面的命令来执行 Storybook 的构建任务。

```bash
modern build --platform storybook
```

关于 `modern build --platform` 命令可以查看：

- [`modern build`](/guide/basic/command-preview#modern-build)

构建完成后，可以在 `dist/storybook-static` 目录看到构建产物文件。
