Storybook

Storybook 是一种在隔离环境中构建 UI 组件的常用方法。通过将 Storybook 放入 Turborepo,你可以轻松地与应用一起开发设计系统。

¥Storybook is a popular way to build UI components in an isolated environment. By putting Storybook into your Turborepo, you can easily develop your design system right alongside your applications.

快速入门

¥Quickstart

如果你希望使用模板,本指南将介绍如何在 Vercel 上构建 这个 Storybook/Turborepo 模板

¥If you'd rather use a template, this guide is walking through how to build this Storybook/Turborepo template on Vercel.

Terminal
pnpm dlx create-turbo@latest -e design-system

指南

¥Guide

创建 monorepo

¥Create a monorepo

如果你没有现有项目,请使用 create-turbo 创建一个新的 monorepo:

¥If you don't have an existing project, use create-turbo to create a new monorepo:

Terminal
pnpm dlx create-turbo@latest

为应用创建目录

¥Create a directory for the app

你需要一个用于 Storybook 应用的目录:

¥You'll need a directory for the Storybook application:

Terminal
mkdir apps/storybook
cd apps/storybook

添加 Storybook 应用

¥Add the Storybook application

apps/storybook 目录中,初始化一个新的 Storybook 应用:

¥In the apps/storybook directory, initialize a new Storybook application:

Terminal
pnpm create storybook@latest

按照提示创建应用。在本指南的其余部分,我们将假设使用 React 和 TypeScript。

¥Follow the prompts to create an application. For the rest of this guide, we'll assume React and TypeScript.

Good to know: 

完成 Storybook 的入门后,你就可以使用 卸载 onboarding 插件 了。

¥After going through Storybook's onboarding, you can uninstall the onboarding addon.

将你的 UI 工具包添加到 Storybook

¥Add your UI kit to Storybook

现在,将你的 UI 包安装到 Storybook 中。

¥Now, install your UI package into Storybook.

Terminal
pnpm add @repo/ui --filter=storybook

为 Button 组件设置故事

¥Set up a story for your Button component

删除在 src/stories 目录中由 Storybook 脚手架工具创建的故事和组件。你将创建自己的 Dockerfile。

¥Delete the stories and components found in src/stories that were created by the Storybook scaffolding tool. You will be making your own.

例如,这是 @repo/ui/buttonButton 组件的故事。

¥As an example, here is a story for the Button component from @repo/ui/button.

./apps/storybook/src/stories/Button.stories.tsx
import type { Meta, StoryObj } from '@storybook/react';
import { Button } from '@repo/ui/button';
 
const meta = {
  title: 'Example/Button',
  component: Button,
  tags: ['autodocs'],
} satisfies Meta<typeof Button>;
 
export default meta;
type Story = StoryObj<typeof meta>;
 
export const Primary: Story = {
  args: {
    appName: 'Button',
    children: 'I am a primary button.',
  },
};

将脚本与你的任务

¥Align scripts to your tasks

最后,将新的 Storybook 应用集成到你的 Turborepo 中:

¥Last, integrate the new Storybook application into your Turborepo:

apps/storybook/package.json
{
  "scripts": {
    "dev": "storybook dev -p 6006",
    "build": "storybook build"
  }
}

这些脚本现在将与你的 turbo.json 中的 turbo devturbo build 任务一起运行。

¥These scripts will now run with the turbo dev and turbo build tasks in your turbo.json.

为确保在运行 build 时文件输出被缓存,请将 storybook-static 添加到 turbo.json 构建任务的输出中:

¥To ensure file outputs are cached when you run build, add storybook-static to the outputs of your turbo.json build task:

Turborepo logo
turbo.json
{
  "tasks": {
    "build": {
      "outputs": [
        ".next/**",
        "!.next/cache/**"
+       "storybook-static/**"
      ]
    }
  }
}

将 Storybook 构建输出添加到 .gitignore

¥Add Storybook build outputs to .gitignore

确保 Storybook 的构建输出未提交到源代码管理

¥Ensure that the build outputs for Storybook are not committed to source control

.gitignore
+ storybook-static

验证配置

¥Verify your configuration

运行 turbo build 以构建 Storybook 应用以及其他应用。

¥Run turbo build to build the Storybook application alongside the rest of your applications.

你还可以再次运行 turbo build 来查看构建的缓存命中情况。

¥You can also run turbo build again to see cache hits for your builds.

更多提示

¥More tips

共置故事

¥Co-locating stories

如果你希望将故事与其源代码放在一起(而不是将它们放在 Storybook 应用中),则需要进行一些额外的配置。

¥If you'd prefer to co-locate your stories to their source code (rather than having them in the Storybook application), you'll need some extra configuration.

重新配置 Storybook 源

¥Re-configure Storybook sources

.storybook/main.ts 中,将 config 中的 stories 路径更改为你想要捕获的目录。例如,如果你想在 UI 包中编写故事:

¥In .storybook/main.ts, change the stories paths in config to the directories you'd like to capture. For instance, if you'd like to write stories in the UI package:

./apps/storybook/.storybook/main.ts
 
const config = {
  stories: [
-   "../src/**/*.mdx",
-   "../src/**/*.stories.@(js|jsx|mjs|ts|tsx)"],
+   "../../../packages/ui/src/**/*.stories.@(js|jsx|mjs|ts|tsx)",
};

将故事文件移动到 UI 包

¥Move story files to the UI package

按照 上一指南 的原则,将 ./apps/storybook/src/stories/Button.stories.tsx 文件移动到 ./packages/ui/src/Button.stories.tsx

¥Following along with the guide above, move the ./apps/storybook/src/stories/Button.stories.tsx file to ./packages/ui/src/Button.stories.tsx.

更新组件导入,使其引用现在位于同一位置的模块。例如,在故事的导入中:

¥Update components imports so that they reference the now co-located modules. For instance, in the story's imports:

./packages/ui/src/Button.stories.tsx
- import { Button } from "@repo/ui/button";
+ import { Button } from "./button";

Good to know: 

你可能还需要根据你的更改和使用情况更新 绝对值导入

¥You may also need to update absolute imports according to your changes and usage.

你还需要安装编写故事所需的所有 Storybook 包。例如,从上面移动故事需要你将 @storybook/react 安装到你的 @repo/ui 包中。

¥You'll also need to install any Storybook packages required for writing stories. For example, moving the story from above would require that you install @storybook/react into your @repo/ui package.

Terminal
pnpm add @storybook/react --filter=@repo/ui --save-dev

配置缓存

¥Configure caching

由于故事现在位于 UI 包中,因此对这些故事的更改可能会导致任何依赖于 UI 包的构建发生缓存未命中。但是,更改故事并不意味着你的生产应用应该丢失缓存。

¥Because stories are now in the UI package, changes to those stories can cause cache misses for any builds that depend on your UI package. However, changing a story doesn't mean your production applications should miss cache.

为防止这种情况,请在根 turbo.json 中将故事从 build 任务的输入中排除。你还需要创建一个 build:storybook 任务,稍后你将需要它:

¥To prevent this, exclude stories from the inputs to your build task in your root turbo.json. You'll also need to create a build:storybook task, which you'll need in a moment:

Turborepo logo
./turbo.json
{
  "tasks": {
    "build": {
      "dependsOn": ["^build"],
      "inputs": ["$TURBO_DEFAULT$", "!**/*.stories.{tsx,jsx,mdx}"],
      "outputs": [".next/**", "!.next/cache/**"]
    },
    "build:storybook": {} 
  }
}

此外,在 storybook 应用中创建一个 软件包配置,以便在构建 Storybook 应用时考虑故事,具体来说:

¥Additionally, create a Package Configuration in the storybook application so stories are accounted for in building the Storybook application, specifically:

Turborepo logo
./apps/storybook/turbo.json
{
  "extends": ["//"],
  "tasks": {
    "build:storybook": {
      "dependsOn": ["^build:storybook"],
      "outputs": ["storybook-static/**"]
    }
  }
}

Good to know: 

如果你正在使用 编译包模式,则可能还需要将 ^build 添加到你的 dependsOn 中。

¥If you are using the Compiled Package pattern, you may also need to add ^build to your dependsOn.

重命名构建脚本

¥Rename the build script

最后,确保你用于构建 Storybook 的脚本使用我们刚刚编写的配置,方法是将其重命名为任务名称:

¥Last, make sure your script to build Storybook uses the configuration we just wrote by renaming it to the name of the task:

apps/storybook/package.json
{
  "scripts": {
    "dev": "storybook dev -p 6006",
    "build:storybook": "storybook build"
  }
}

曾经是 "build" 的脚本现在变为 "build:storybook",以确保故事包含在哈希表中以便缓存。

¥The script that was once "build" is now "build:storybook" to ensure the stories are included in hashes for caching.

验证配置

¥Verify your configuration

为确保你的设置正确:

¥To ensure your setup is correct:

  1. 运行 turbo build:storybook build。你应该看到缓存未命中。

    ¥Run turbo build:storybook build. You should see cache misses.

  2. 再次运行 turbo build:storybook build。你应该看到所有缓存命中。

    ¥Run turbo build:storybook build again. You should see all cache hits.

  3. 对你的 @repo/ui 软件包中的故事进行代码更改。

    ¥Make a code change to a story in your @repo/ui package.

  4. 再次运行 turbo build:storybook build。你应该只会看到 Storybook 应用的缓存未命中。所有其他变量都应该命中缓存。

    ¥Run turbo build:storybook build again. You should only see a cache miss for the Storybook application. All others should hit cache.

添加 CSS

¥Adding CSS

如果你的 UI 包导出了其自身的 CSS,则需要将其添加到 Storybook 应用的渲染中,类似于将其添加到应用中的方式。Storybook 文档 建议你将其添加到 .storybook/preview.ts 文件中。

¥If your UI package exports its own CSS, you'll need to add it to the renders in the Storybook app, similar to how you would add it to your applications. The Storybook documentation recommends you add it to the .storybook/preview.ts file.