Frameworks
Storybook 的架構設計旨在支援多樣化的網頁框架,包括 React、Vue、Angular、Web Components、Svelte 以及其他十多種框架。本指南將協助您開始為 Storybook 新增框架支援。
建立新框架的基礎結構
首先要做的是在您自己的儲存庫中建立框架支援的基礎結構。
我們建議採用與 Storybook monorepo 相同的專案結構。該結構包含框架套件 (app/<framework>
) 和範例應用程式 (examples/<framework>-kitchen-sink
),以及其他相關的文件和設定(如果需要)。
這種結構可能看起來比必要的更複雜一些。但因為此結構鏡像了 Storybook monorepo 的結構方式,您可以重複使用 Storybook 的工具。如果之後希望將框架移至 Storybook monorepo,也會更容易。
我們建議使用 @storybook/html
作為入門框架,因為它是最簡單的,且不包含特定於框架的特性。這裡有一個樣板可以幫助您開始:here。
框架架構
在 Storybook 中支援新框架通常包含兩個主要方面
-
設定伺服器。在 Storybook 中,伺服器是當您執行
storybook dev
或storybook build
時運行的 node 程序。設定伺服器通常意味著以框架特定的方式設定 babel 和 webpack。 -
設定用戶端。用戶端是在瀏覽器中運行的程式碼,而設定它意味著提供一個框架特定的 story 渲染函數。
設定伺服器
Storybook 具有 預設配置 (presets) 的概念,它們通常是用於檔案載入的 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
啟動開發伺服器的樣板
import { buildDev } from '@storybook/core/server';
import options from './options';
buildDev(options);
因此,新增框架預設配置的本質就是填寫該 options 物件。
伺服器選項
如上所述,伺服器 options
物件負責設定伺服器的繁重工作。
讓我們看一下 @storybook/vue
的 options 定義
import { sync } from 'read-pkg-up';
export default {
packageJson: sync({ cwd: __dirname }).packageJson,
framework: 'vue',
frameworkPresets: [require.resolve('./framework-preset-vue.js')],
};
framework
選項(即 'vue')的值會傳遞給擴充功能,並允許它們執行與您的框架相關的特定任務。
此檔案的本質是框架預設配置,這些是標準的 Storybook 預設配置 -- 您可以查看 Storybook monorepo 中的框架套件(例如 React、Vue、Web Components)以查看框架特定自訂的範例。
在開發您自己的自訂框架(非由 Storybook 維護)時,您可以使用 frameworkPath
鍵指定位置檔案的路徑
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
import { Button } from './Button';
export default {
component: Button,
};
export const Sample = {
render: () => <Button label="hello button" />,
};
在此案例中,可渲染物件是 React 元素 <Button .../>
。
在大多數其他框架中,可渲染物件實際上是一個純 JavaScript 物件。
考慮以下假設範例
// 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 節點。它通常採用以下形式
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
import { start } from '@storybook/preview-api';
import './globals';
import render from './render';
const api = start(render);
// the boilerplate code
globals 檔案通常會設定一個全域變數,如果需要了解它正在哪個框架中運行,用戶端程式碼(例如擴充功能提供的 decorators)可以參考該變數
import { global } from '@storybook/global';
const { window: globalWindow } = global;
globalWindow.STORYBOOK_ENV = 'vue';
start
函數抽象了 Storybook 所有框架獨立的用戶端(瀏覽器)程式碼,並且它採用了我們上面定義的渲染函數。有關渲染函數的範例,請參閱 Storybook monorepo 中的 React、Vue、Angular 和 Web Components。