文档
Storybook Docs

Angular 的 Storybook

Angular 的 Storybook 是一个 框架,可方便地为 Angular 应用程序独立开发和测试 UI 组件。它包含

  • 🧱 使用 Angular 构建器
  • 🎛️ 集成 Compodoc
  • 💫 等等!

要求

  • Angular ≥ 18.0 < 21.0
  • Webpack ≥ 5.0

入门

在没有 Storybook 的项目中

在 Angular 项目的根目录中运行此命令后,请按照提示进行操作

npm create storybook@latest

更多关于 Storybook 入门的信息。

在已有 Storybook 的项目中

此框架旨在与 Storybook 7+ 配合使用。如果您尚未升级到 v7,请使用此命令进行升级。

npx storybook@latest upgrade

自动迁移

运行上述 upgrade 命令时,您应该会收到一个提示,询问您是否迁移到 @storybook/angular,它应该会为您处理所有事情。如果自动迁移不适用于您的项目,请参考下面的手动迁移。

手动迁移

首先,安装框架。

npm install --save-dev @storybook/angular

然后,更新您的 .storybook/main.js|ts 以更改框架属性。

.storybook/main.ts
import { StorybookConfig } from '@storybook/angular';
 
const config: StorybookConfig = {
  // ...
  framework: '@storybook/angular', // 👈 Add this
};
 
export default config;

最后,更新您的 angular.json 以包含 Storybook 构建器

angular.json
{
  "projects": {
    "your-project": {
      "architect": {
        "storybook": {
          "builder": "@storybook/angular:start-storybook",
          "options": {
            // The path to the storybook config directory
            "configDir": ".storybook",
            // The build target of your project
            "browserTarget": "your-project:build",
            // The port you want to start Storybook on
            "port": 6006
            // More options available, documented here:
            // https://github.com/storybookjs/storybook/tree/next/code/frameworks/angular/src/builders/start-storybook/schema.json
          }
        },
        "build-storybook": {
          "builder": "@storybook/angular:build-storybook",
          "options": {
            "configDir": ".storybook",
            "browserTarget": "your-project:build",
            "outputDir": "dist/storybook/your-project"
            // More options available, documented here:
            // https://github.com/storybookjs/storybook/tree/next/code/frameworks/angular/src/builders/build-storybook/schema.json
          }
        }
      }
    }
  }
}

运行 Storybook

要为特定项目运行 Storybook,请运行以下命令

ng run <your-project>:storybook

要构建 Storybook,请运行

ng run <your-project>:build-storybook

输出将在配置的 outputDir(默认为 dist/storybook/<your-project>)中找到。

设置 Compodoc

您可以在组件、指令和其他 Angular 代码部分上方包含 JSDoc 注释,以包含这些元素的文档。Compodoc 使用这些注释来 生成应用程序的文档。在 Storybook 中,在 @Inputs@Outputs 上方添加解释性注释很有用,因为这些是 Storybook 在其用户界面中显示的主要元素。@Inputs@Outputs 是您可以在 Storybook 中交互的元素,例如 控件

自动设置

通过 npx storybook@latest init 安装 Storybook 时,您可以自动设置 Compodoc。

手动设置

如果您已经安装了 Storybook,则可以手动设置 Compodoc。

安装以下依赖项

npm install --save-dev @compodoc/compodoc

将以下选项添加到您的 Storybook 构建器

angular.json
{
  "projects": {
    "your-project": {
      "architect": {
        "storybook": {
          "builder": "@storybook/angular:start-storybook",
          "options": {
            // 👇 Add these
            "compodoc": true,
            "compodocArgs": [
              "-e",
              "json",
              "-d",
              // Where to store the generated documentation. It's usually the root of your Angular project. It's not necessarily the root of your Angular Workspace!
              "."
            ],
          }
        },
        "build-storybook": {
          "builder": "@storybook/angular:build-storybook",
          "options": {
            // 👇 Add these
            "compodoc": true,
            "compodocArgs": [
              "-e",
              "json",
              "-d",
              "."
            ],
          }
        }
      }
    }
  }
}

转到您的 .storybook/preview.ts 并添加以下内容

.storybook/preview.ts
import type { Preview } from '@storybook/angular';
 
// 👇 Add these
import { setCompodocJson } from '@storybook/addon-docs/angular';
import docJson from '../documentation.json';
setCompodocJson(docJson);
 
const preview: Preview = {};
export default preview;

applicationConfig 装饰器

如果您的组件依赖于应用程序范围的提供者,例如由 BrowserAnimationsModule 或其他使用 forRoot 模式提供 ModuleWithProviders 的模块定义的提供者,您可以将 applicationConfig 装饰器 应用于该组件的所有故事。这将为它们提供 bootstrapApplication 函数,该函数用于在 Storybook 中引导组件。

ChipsModule.stories.ts
import { Meta, applicationConfig, StoryObj } from '@storybook/angular';
 
import { BrowserAnimationsModule, provideAnimations } from '@angular/platform-browser/animations';
import { importProvidersFrom } from '@angular/core';
 
import { ChipsModule } from './angular-src/chips.module';
 
const meta: Meta<ChipsModule> = {
  component: ChipsModule,
  decorators: [
    // Apply application config to all stories
    applicationConfig({
      // List of providers and environment providers that should be available to the root component and all its children.
      providers: [
        ...
        // Import application-wide providers from a module
        importProvidersFrom(BrowserAnimationsModule)
        // Or use provide-style functions if available instead, e.g.
        provideAnimations()
      ],
    }),
  ],
};
 
export default meta;
type Story = StoryObj<ChipsModule>;
 
export const WithCustomApplicationProvider: Story = {
  render: () => ({
    // Apply application config to a specific story
    applicationConfig: {
      // The providers will be merged with the ones defined in the applicationConfig decorator's providers array of the global meta object
      providers: [...],
    }
  })
}

moduleMetadata 装饰器

如果您的组件依赖于其他 Angular 指令和模块,可以使用 moduleMetadata 装饰器 为组件的所有故事或单个故事提供这些依赖项。

YourComponent.stories.ts
import { Meta, moduleMetadata, StoryObj } from '@storybook/angular';
 
import { YourComponent } from './your.component';
 
const meta: Meta<YourComponent> = {
  component: YourComponent,
  decorators: [
    // Apply metadata to all stories
    moduleMetadata({
      // import necessary ngModules or standalone components
      imports: [...],
      // declare components that are used in the template
      declarations: [...],
      // List of providers that should be available to the root component and all its children.
      providers: [...],
    }),
  ],
};
export default meta;
type Story = StoryObj<YourComponent>;
 
export const Base: Story = {};
 
export const WithCustomProvider: Story = {
  decorators: [
    // Apply metadata to a specific story
    moduleMetadata({
      imports: [...],
      declarations: [...],
      providers: [...],
    }),
  ],
};

常见问题解答

如何迁移到 Angular Storybook 构建器?

Storybook 的 Angular 构建器 是在 Angular 工作区中运行 Storybook 的一种方式。它是直接运行 storybook devstorybook build 的即插即用替代品。

您可以运行 npx storybook@latest automigrate 来尝试让 Storybook 检测并自动修复您的配置。否则,您可以按照以下步骤手动调整您的配置。

您的工作区中只有一个 Angular 项目吗?

首先,转到您的 angular.json,并在您项目的 architect 部分添加 storybookbuild-storybook 条目,如上文所示。

其次,调整您的 package.json 脚本部分。通常,它看起来像这样

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

现在,您可以使用 ng run <your-project>:storybook 运行 Storybook,并使用 ng run <your-project>:build-storybook 构建它。相应地调整您的 package.json 中的脚本。

package.json
{
  "scripts": {
    "storybook": "ng run <project-name>:storybook",
    "build-storybook": "ng run <project-name>:build-storybook"
  }
}

此外,compodoc 现在已内置到 @storybook/angular 中;您不必显式调用它。如果我们像这样在您的 package.json 脚本中运行 compodoc

package.json
{
  "scripts": {
    "docs:json": "compodoc -p tsconfig.json -e json -d ./documentation",
    "storybook": "npm run docs:json && start-storybook -p 6006",
    "build-storybook": "npm run docs:json && build-storybook"
  }
}

更改为

package.json
{
  "scripts": {
    "storybook": "ng run <project-name>:storybook",
    "build-storybook": "ng run <project-name>:build-storybook"
  }
}

我的 Angular 工作区中有多个项目

在这种情况下,您必须按照上述说明为要使用 Storybook 的每个项目调整您的 angular.jsonpackage.json。请注意,每个项目都应有一个专用的 .storybook 文件夹,位于项目根目录下。

您可以依次为每个项目运行 npx storybook@latest init 来为每个项目设置 Storybook,以便自动创建 .storybook 文件夹并在您的 angular.json 中创建必要的配置。

然后,您可以使用 Storybook 组合 将多个 Storybook 合并在一起。

如何配置 Angular 的构建器以用于 Storybook?

以下是 Angular 构建器可能需要的一些常用选项

配置项描述
"browserTarget"要服务的构建目标,使用以下格式。
"example-project:builder:config"
"debugWebpack"调试 Webpack 配置
"debugWebpack": true
"tsConfig"相对于当前工作区的 TypeScript 配置文件位置。
"tsConfig": "./tsconfig.json".
"preserveSymlinks"解析模块时不要使用真实路径。如果为 true,则符号链接将被解析到它们的真实路径;否则,它们将被解析到它们的符号链接路径。
"preserveSymlinks": true
"port"Storybook 使用的端口。
"port": 6006
"host"为 Storybook 设置自定义主机。
"host": "http://my-custom-host"
"configDir"Storybook 配置目录位置。
"configDir": ".storybook"
"https"启用 HTTPS 启动 Storybook。
"https": true
需要自定义证书信息。
"sslCa"提供 SSL 证书颁发机构。
"sslCa": "your-custom-certificate-authority"
可选使用 "https"
"sslCert"提供 SSL 证书。
"sslCert": "your-custom-certificate"
需要 https
"sslKey"提供 SSL 密钥以服务 Storybook。
"sslKey": "your-ssl-key"
"smokeTest"成功启动后退出 Storybook。
"smokeTest": true
"ci"以 CI 模式启动 Storybook(跳过交互式提示,不打开浏览器窗口)。
"ci": true
"open"是否自动在浏览器中打开 Storybook。
"open": true
"quiet"过滤 Storybook 的详细构建输出。
"quiet": true
"enableProdMode"禁用 Angular 的开发模式,这会关闭框架中的断言和其他检查。
"enableProdMode": true
"docs"文档模式 启动 Storybook。
"docs": true
"compodoc"在此之前执行 compodoc。
"compodoc": true
"compodocArgs"Compodoc 选项。始终提供带有 tsconfig 路径的 -p 选项和带有工作区根目录的 -d 选项。
"compodocArgs": ["-e", "json"]
"styles"提供 应用程序样式 的位置,以与 Storybook 一起使用。
"styles": ["src/styles.css", "src/styles.scss"]
"stylePreprocessorOptions"为解析到工作区根目录的样式预处理器提供进一步的自定义。
"stylePreprocessorOptions": { "includePaths": ["src/styles"] }
"assets"静态应用程序资产列表。
"assets": ["src/assets"]
"initialPath"首次访问 Storybook 时要附加的 URL 路径。
"initialPath": "docs/configure-your-project--docs"
"webpackStatsJson"将 Webpack Stats JSON 写入磁盘。
"webpackStatsJson": true
"previewUrl"禁用默认的 storybook 预览,允许您使用自己的。
"previewUrl": "iframe.html"
"loglevel"控制构建期间的日志级别。可以是以下之一:[silly, verbose, info (默认), warn, error, silent]。
"loglevel": "info"
"sourceMap"配置 Source Maps
"sourceMap": true
"experimentalZoneless"配置 无区域检测更改
"experimentalZoneless": true

完整的选项列表可以在 Angular 构建器模式中找到

API

选项

如果需要,您可以传递一个选项对象进行其他配置

.storybook/main.ts
import type { StorybookConfig } from '@storybook/angular';
 
const config: StorybookConfig = {
  framework: {
    name: '@storybook/angular',
    options: {
      // ...
    },
  },
};

可用选项为

builder

类型:Record<string, any>

框架的构建器 配置选项。对于此框架,可以在 Webpack 构建器文档 中找到可用选项。