文件
Storybook 文件

框架

Storybook 的架構旨在支援各種 Web 框架,包括 React、Vue、Angular、Web Components、Svelte 和其他十幾個框架。本指南可協助您開始為 Storybook 新增框架支援。

建立新框架的骨架

首先要做的是在自己的儲存庫中建立框架支援的骨架。

我們建議採用與 Storybook 單一儲存庫相同的專案結構。該結構包含框架套件 (app/<框架>) 和範例應用程式 (examples/<框架>-kitchen-sink),以及其他相關的文件和設定 (如有需要)。

它看起來可能比必要的層級多一點。但由於此結構反映了 Storybook 單一儲存庫的結構方式,您可以重複使用 Storybook 的工具。如果稍後需要,也可以更輕鬆地將框架移至 Storybook 單一儲存庫中。

我們建議使用 @storybook/html 作為入門框架,因為它是最簡單的,而且不包含任何框架特定的特性。這裡有一個範本可以讓您開始 這裡

框架架構

在 Storybook 中支援新框架通常包含兩個主要層面

  1. 設定伺服器。在 Storybook 中,伺服器是在您執行 storybook devstorybook build 時執行的節點程序。設定伺服器通常表示以框架特定的方式設定 babel 和 webpack。

  2. 設定用戶端。用戶端是在瀏覽器中執行的程式碼,而設定用戶端表示提供一個框架特定的 story 渲染函式。

設定伺服器

Storybook 有 預設設定 的概念,這些設定通常是用於檔案載入的 babel/webpack 設定。如果您的框架有自己的檔案格式 (例如,「.vue」),您可能需要在載入時將它們轉換為 JavaScript 檔案。如果您假設您框架的每個使用者都需要這個功能,則應該將其新增至框架。到目前為止,已新增至 Storybook 的每個框架都已完成此動作,因為 Storybook 的核心設定極為精簡。

套件結構

在新增框架預設設定之前,先了解 Storybook 的套件結構會很有幫助。每個框架通常會在其 package.json 中公開兩個可執行檔

{
  "bin": {
    "storybook": "./bin/index.js",
    "build-storybook": "./bin/build.js"
  }
}

這些指令碼會將 options 物件傳遞至 @storybook/core/server,這是一個抽象化所有 Storybook 與框架無關的程式碼的程式庫。

例如,以下是使用 storybook dev 啟動開發伺服器的範本

your-framework/src/server/index.ts
import { buildDev } from '@storybook/core/server';
 
import options from './options';
 
buildDev(options);

因此,新增框架預設設定的精髓就是填寫該選項物件。

伺服器選項

如上所述,伺服器的 options 物件負責伺服器的主要配置工作。

讓我們來看看 @storybook/vue 的選項定義。

vue/src/server/options.ts
import { sync } from 'read-pkg-up';
 
export default {
  packageJson: sync({ cwd: __dirname }).packageJson,
  framework: 'vue',
  frameworkPresets: [require.resolve('./framework-preset-vue.js')],
};

framework 選項的值(即 'vue')會傳遞給 addons,讓它們可以執行與您的框架相關的特定任務。

此檔案的重點在於框架預設設定,這些是標準的 Storybook 預設設定 -- 您可以查看 Storybook monorepo 中的框架套件(例如 ReactVueWeb Components)以查看特定於框架的自訂範例。

在開發您自己、非 Storybook 維護的自訂框架時,您可以使用 frameworkPath 鍵指定位置檔案的路徑。

my-framework/src/server/options.ts
import { sync } from 'read-pkg-up';
 
export default {
  packageJson: sync({ cwd: __dirname }).packageJson,
  framework: 'my-framework',
  frameworkPath: '@my-framework/storybook',
  frameworkPresets: [require.resolve('./framework-preset-my-framework.js')],
};

您可以將相對路徑新增至 frameworkPath。別忘了,它們預設會從 Storybook 的設定目錄(即 .storybook)解析。

請確保 frameworkPath 最後指向您框架應用程式內的 dist/client/index.js 檔案。

設定客戶端

若要設定客戶端,您必須提供一個特定於框架的渲染函式。在深入探討細節之前,必須先了解使用者撰寫的 stories 與螢幕上呈現的內容之間的關聯。

可渲染物件

Storybook stories 是 ES6 物件,會傳回「可渲染物件」。

請考慮以下 React story

Button.stories.js|jsx
import { Button } from './Button';
 
export default {
  component: Button,
};
 
export const Sample = {
  render: () => <Button label="hello button" />,
};

在這種情況下,可渲染物件是 React 元素 <Button .../>

在大多數其他框架中,可渲染物件實際上是一個普通的 JavaScript 物件。

請考慮以下假設範例

Button.stories.ts|tsx
// Replace your-framework with the name of your framework
import type { Meta, StoryObj } from '@storybook/your-framework';
 
import { Button } from './Button';
 
const meta: Meta<typeof Button> = {
  component: Button,
};
 
export default meta;
type Story = StoryObj<typeof Button>;
 
export const Sample: Story = {
  render: () => ({
    template: '<button :label=label />',
    data: {
      label: 'hello button',
    },
  }),
};

這種「可渲染物件」的設計是特定於框架的,理想情況下應符合該框架的慣用語。

渲染函式

框架的渲染函式負責將可渲染物件轉換為 DOM 節點。它通常具有以下形式

your-framework/src/client/preview/render.ts
const rootElement = document.getElementById('root');
 
export default function renderMain({ storyFn }: RenderMainArgs) {
  const storyObj = storyFn();
  const html = fn(storyObj);
  rootElement.innerHTML = html;
}

套件結構

在客戶端,關鍵檔案是 src/client/preview.js

your-framework/src/client/preview/index.ts
import { start } from '@storybook/preview-api';
 
import './globals';
 
import render from './render';
 
const api = start(render);
 
// the boilerplate code

全域檔案通常會設定一個全域變數,以便客戶端程式碼(例如附加元件提供的裝飾器)在需要時可以參考,以了解它在哪個框架中執行。

vue/src/client/preview/globals.ts
import { global } from '@storybook/global';
 
const { window: globalWindow } = global;
 
globalWindow.STORYBOOK_ENV = 'vue';

start 函式抽象化了所有 Storybook 獨立於框架的客戶端(瀏覽器)程式碼,並且它會採用我們在上方定義的渲染函式。如需渲染函式的範例,請參閱 Storybook monorepo 中的 ReactVueAngularWeb Components