目前這個系列已挑選ChatGPT、前端&React相關章節出版成書!
感謝大家的閱讀與支持!
《用 ChatGPT 詠唱來點亮 React & 前端技能樹》
歷經重新整理、校正、編排、與修改後,讓章節內容之間的銜接更平順,除了補充上更多的解說之外,甚至有部分章節為重新撰寫的內容,讓理解變得更輕鬆!
目前已在天瓏書局、博客來、金石堂等通路都買得到了! 也有電子書的選擇!
歡迎各位點擊連結選購,謝謝大家~
接下來要討論的套件,是針對Component進行文件化與測試的Storybook
和Jest、Cypress一樣,這個Storybook套件 也是有被Nx框架所整合
起始設定一樣會分成「從頭安裝」以及「倚賴Nx框架」兩種方式處理
不過Storybook的安裝與設定我個人覺得非常友善!相當簡易
(不想再經歷Cypress安裝的惡夢了)
沒問題我們就Go Go!
當然可以!首先,讓我來為你詳細介紹一下 Storybook。
Storybook 介紹
Storybook 是一個用於開發用戶界面(UI)元件的工具,它允許你在獨立的環境中建立、展示以及測試元件。這對於前端工程師來說是一個非常有用的工具,尤其是在開發較大型專案或跟團隊協作時。
以下是 Storybook 提供的一些主要功能:
1. 獨立展示元件
Storybook 允許你將每個元件獨立地展示在一個隔離的環境中。這意味著你可以輕鬆地檢視、測試及驗證元件的外觀和功能,而無需依賴於整個應用程式。
2. 多種視角
你可以為每個元件創建多個 Story,這些 Story 可以展示不同的使用情境、狀態或屬性。這讓你可以全面測試元件在各種情況下的表現。
3. 支援多種框架和程式語言
Storybook 不僅支援 React,還支援許多其他前端框架,例如 Vue、Angular 等,這意味著你可以在不同的專案中保持一致的開發流程。
4. 易於擴展
你可以輕鬆地擴展 Storybook,添加新的插件或整合其他工具,以滿足你的專案需求。
5. 自動化測試
透過 Storybook,你可以自動化測試你的元件,確保它們在各種情況下都能正常運作。
Storybook 的安裝與使用
以下是一個簡單的安裝與使用步驟:
安裝 Storybook:
開啟你的專案目錄,使用指令安裝 Storybook:
npx sb init
建立 Story:
在你的專案目錄中,建立一個新的
.stories.js
檔案,並在其中定義你的元件 Story。// 例如:Button.stories.js import React from 'react'; import { Button } from './Button'; export default { title: 'Button', component: Button, }; export const Primary = () => <Button primary>Primary Button</Button>; export const Secondary = () => <Button secondary>Secondary Button</Button>;
啟動 Storybook:
使用以下指令啟動 Storybook 服務:
npm run storybook
這將會啟動一個本地伺服器,並在你的瀏覽器中打開 Storybook 介面。
現在你可以在 Storybook 中輕鬆地管理和測試你的元件了!
希望這份介紹對你有所幫助!如果你對任何部分有疑問,請隨時詢問。
照著做之後,在執行的第一步驟 npx sb init
指令結束時
就突然自動幫我們執行npm run storybook
,開啟了storybook的頁面
此外還有把必要的設置都處理完,以及內建一套範例檔案
若你在使用 Nx 框架,你可以透過以下步驟來開始使用 Storybook:
安裝 Nx Storybook 插件:
開啟你的專案目錄,使用以下指令來安裝 Nx Storybook 插件:
nx generate @nrwl/react:storybook-configuration <project-name>
請將
<project-name>
替換為你要添加 Storybook 的專案名稱。建立 Story:
在你的專案目錄中,建立一個新的
.stories.js
或.stories.tsx
檔案,並在其中定義你的元件 Story。// 例如:Button.stories.js import React from 'react'; import { Button } from './Button'; export default { title: 'Button', component: Button, }; export const Primary = () => <Button primary>Primary Button</Button>; export const Secondary = () => <Button secondary>Secondary Button</Button>;
啟動 Storybook:
使用以下指令啟動 Storybook 服務:
nx run <project-name>:storybook
請將
<project-name>
替換為你的專案名稱。這將會啟動一個本地伺服器,並在你的瀏覽器中打開 Storybook 介面。
現在你可以在 Storybook 中輕鬆地管理和測試你的元件了!
希望這份指南對你有所幫助!如果你有任何疑問,隨時向我詢問。
因為我的專案叫 my-app ,所以我下的指令是nx generate @nrwl/react:storybook-configuration my-app
下完指令之後,就會自動建立.storybook的資料夾,並自動建置相關檔案
另外預設main.ts
裡面有指定說,stories 會放在 components
這個資料夾下
所以我手動建立了這個資料夾,並把元件放進去、把stories放進去
呼叫nx run my-app:storybook
開啟,就可以看到localhost:4400 上有storybook的頁面了
在storybook的安裝上,我覺得單純安裝與依賴Nx的結果都差不多
不會有太大差異
在版本更新方面上,ChatGPT所知道的資料版本到6.4.0為止
而我們測試時的最新版本是7.4.6
接下來我們直接用安裝時附贈的程式碼範例,請ChatGPT邊講解邊教學
// Button.stories.ts
import type { Meta, StoryObj } from '@storybook/react';
import { Button } from './Button';
// More on how to set up stories at: https://storybook.js.org/docs/react/writing-stories/introduction#default-export
const meta = {
title: 'Example/Button',
component: Button,
parameters: {
// Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/react/configure/story-layout
layout: 'centered',
},
// This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/react/writing-docs/autodocs
tags: ['autodocs'],
// More on argTypes: https://storybook.js.org/docs/react/api/argtypes
argTypes: {
backgroundColor: { control: 'color' },
},
} satisfies Meta<typeof Button>;
export default meta;
type Story = StoryObj<typeof meta>;
// More on writing stories with args: https://storybook.js.org/docs/react/writing-stories/args
export const Primary: Story = {
args: {
primary: true,
label: 'Button',
},
};
export const Secondary: Story = {
args: {
label: 'Button',
},
};
export const Large: Story = {
args: {
size: 'large',
label: 'Button',
},
};
export const Small: Story = {
args: {
size: 'small',
label: 'Button',
},
};
// Button.tsx
import React from 'react';
import './button.css';
export interface ButtonProps {
/**
* Is this the principal call to action on the page?
*/
primary?: boolean;
/**
* What background color to use
*/
backgroundColor?: string;
/**
* How large should the button be?
*/
size?: 'small' | 'medium' | 'large';
/**
* Button contents
*/
label: string;
/**
* Optional click handler
*/
onClick?: () => void;
}
/**
* Primary UI component for user interaction
*/
export const Button = ({
primary = false,
size = 'medium',
backgroundColor,
label,
...props
}: ButtonProps) => {
const mode = primary ? 'storybook-button--primary' : 'storybook-button--secondary';
return (
<button
type="button"
className={['storybook-button', `storybook-button--${size}`, mode].join(' ')}
{...props}
>
{label}
<style jsx>{`
button {
background-color: ${backgroundColor};
}
`}</style>
</button>
);
};
// button.css
.storybook-button {
font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
font-weight: 700;
border: 0;
border-radius: 3em;
cursor: pointer;
display: inline-block;
line-height: 1;
}
.storybook-button--primary {
color: white;
background-color: #1ea7fd;
}
.storybook-button--secondary {
color: #333;
background-color: transparent;
box-shadow: rgba(0, 0, 0, 0.15) 0px 0px 0px 1px inset;
}
.storybook-button--small {
font-size: 12px;
padding: 10px 16px;
}
.storybook-button--medium {
font-size: 14px;
padding: 11px 20px;
}
.storybook-button--large {
font-size: 16px;
padding: 12px 24px;
}
主要是這個範例看起來已經很完整了,提供的介面操作也很完善
所我們請ChatGPT來講解這個程式碼,藉此了解Storybook是怎麼運作的
把只有stories的部分貼給ChatGPT
這份範例程式碼是一個使用 Storybook 建立的元件故事(stories)。讓我依序針對程式碼中的每個部分進行說明與教學:
1.
import
與type
聲明import type { Meta, StoryObj } from '@storybook/react'; import { Button } from './Button';
import type { Meta, StoryObj } from '@storybook/react';
:這行程式碼是用來引入 Storybook 所提供的型別定義。Meta
是用來描述 story 的物件,StoryObj
則描述 story 的類型。import { Button } from './Button';
:這行引入了一個名為Button
的元件。2.
meta
物件const meta = { title: 'Example/Button', component: Button, parameters: { layout: 'centered', }, tags: ['autodocs'], argTypes: { backgroundColor: { control: 'color' }, }, } satisfies Meta<typeof Button>;
title: 'Example/Button'
:這是 story 的標題,將會顯示在 Storybook 的側邊欄中。component: Button
:這是這個 story 所使用的元件,這裡是引入的Button
元件。parameters: { layout: 'centered' }
:這個部分設置了 story 的參數,這裡是設置了layout
為centered
,表示元件會在 Canvas 中置中顯示。tags: ['autodocs']
:這個部分是為 story 加上標籤,這裡是加上了一個autodocs
的標籤,用來指示 Storybook 生成自動文檔。argTypes: { backgroundColor: { control: 'color' } }
:這個部分是設置 story 的參數(args)的類型,這裡是設置了一個backgroundColor
參數,並指定其控制項為一個顏色選擇器。3.
Story
型別定義export default meta; type Story = StoryObj<typeof meta>;
export default meta;
:這行程式碼將meta
物件作為默認導出,這將允許 Storybook 使用這個物件來顯示相應的 story。type Story = StoryObj<typeof meta>;
:這行程式碼定義了一個Story
型別,其基於StoryObj
且使用了meta
作為參數。4. Story 的定義
export const Primary: Story = { args: { primary: true, label: 'Button', }, }; export const Secondary: Story = { args: { label: 'Button', }, }; export const Large: Story = { args: { size: 'large', label: 'Button', }, }; export const Small: Story = { args: { size: 'small', label: 'Button', }, };
這部分定義了幾個不同的 stories:
Primary
:這是一個主要的按鈕,設置了primary
參數為true
,並指定了label
為'Button'
。Secondary
:這是一個次要的按鈕,僅指定了label
為'Button'
。Large
:這是一個大型的按鈕,設置了size
為'large'
,並指定了label
為'Button'
。Small
:這是一個小型的按鈕,設置了size
為'small'
,並指定了label
為'Button'
。教學總結:
這份範例程式碼演示了如何使用 Storybook 建立元件的 stories。通過定義不同的 stories,你可以輕鬆地測試你的元件在不同情況下的表現。
如果你對這份教學還有任何疑問,請隨時向我詢問!
從上面的資料來看,stories是由「meta
物件」、「Story
型別定義」、「Story 的定義」這三個部分組成
那我們就個別來詢問、了解這三個部分的語法
在 Storybook 中,
meta
物件是用來描述一個 story 的元資訊。它包含了許多屬性,用來定義 story 的特性、標題、所使用的元件等等。以下是
meta
物件中可能包含的屬性以及它們的功能:1.
title
(必要)
- 功能:
title
屬性用於定義 story 的標題,將會顯示在 Storybook 的側邊欄中。- 範例:
title: 'Example/Button'
2.
component
(必要)
- 功能:
component
屬性用於指定這個 story 所使用的元件。- 範例:
component: Button
3.
parameters
- 功能:
parameters
用於設置 story 的參數,例如畫布的排版方式等。- 範例:
parameters: { layout: 'centered' }
- 可選項目:
layout
: 控制 story 在 Canvas 中的排版方式,可以設置為'fullscreen'
(滿屏顯示)或'centered'
(置中顯示)等。4.
tags
- 功能:
tags
用來為 story 加上標籤,可以用來進行分類或者指示 Storybook 執行相應的動作。- 範例:
tags: ['autodocs']
5.
argTypes
- 功能:
argTypes
用來設置 story 中的參數(args)的類型,以及它們的控制方式。- 範例:
argTypes: { backgroundColor: { control: 'color' } }
- 可選項目:
control
: 指定控制項的類型,例如'text'
(文字輸入框),'color'
(顏色選擇器)等。6.
decorators
功能:
decorators
用來在 story 的呈現過程中進行裝飾,例如添加外框、風格等。範例:
decorators: [ (Story) => <div style={{ margin: '3em' }}><Story /></div> ]
7.
excludeStories
功能:
excludeStories
用來排除特定的 stories,使其不會顯示在 Storybook 中。範例:
excludeStories: ['Large', 'Small']
8.
includeStories
功能:
includeStories
用來指定要包含的 stories,其他未列出的 stories 將不會顯示在 Storybook 中。範例:
includeStories: ['Primary', 'Secondary']
9.
subcomponents
功能:
subcomponents
用來定義元件中的次要元件(subcomponents),以便在 story 中進行測試。範例:
subcomponents: { 'SubcomponentName': Subcomponent }
這些就是
meta
物件中可能包含的屬性以及它們的功能。請根據你的需求來使用這些屬性,以便準確描述和呈現你的 story。如果你有任何進一步的問題,請隨時向我詢問!
Story
型別定義是為了明確地描述一個 story 的結構和類型,這樣在使用 Storybook 時可以提供更好的開發體驗和類型安全。讓我來針對
Story
型別定義進行詳細介紹:1. Story 的定義
type Story = StoryObj<typeof meta>;
type Story = ...
:這行程式碼定義了一個型別Story
,它是基於StoryObj
型別,並以meta
為參數。2. StoryObj
StoryObj
是 Storybook 提供的一個泛型型別,它用於描述一個 story 的結構。在這裡,StoryObj
的泛型參數被設置為typeof meta
,這表示它的結構和meta
物件相符。為什麼要進行 Story 型別定義?
- 提供開發者友好的提示和文檔:通過定義
Story
型別,開發者可以清楚地知道一個 story 的結構,這在開發過程中提供了更好的提示和文檔。- 類型安全:使用 TypeScript 進行開發時,定義
Story
型別可以提供類型安全的保障,確保你在 story 中傳遞的參數和屬性符合預期的類型。- 代碼自動完成功能:IDE(整合開發環境)可以根據
Story
型別提供更準確的自動完成功能,這有助於加快開發速度。- 易於維護和修改:當你需要修改或者擴展一個 story 時,通過
Story
型別定義,你可以快速地理解 story 的結構,這使得維護和修改變得更加容易。總的來說,Story 型別定義提供了更好的代碼結構和開發體驗,尤其在大型專案或者團隊協作中,這對於保持代碼的清晰性和可讀性非常重要。
如果你還有任何問題或需要進一步的說明,請隨時告訴我!
當然,讓我針對 Story 的定義進行詳細介紹與教學。
在 Storybook 中,
Story
是一個物件,它描述了一個特定場景下元件的呈現方式。每個 Story 包含了一個或多個故事(stories),用於測試和展示你的元件。讓我分步進行說明:
1. Story 的定義
export const Primary: Story = { args: { primary: true, label: 'Button', }, };
export const Primary: Story = {...}
:這表示定義了一個名為Primary
的 Story。這裡的Primary
是 story 的名稱,你可以自由命名。2. Story 物件屬性
在上述的 Story 定義中,有一個
args
屬性:
args
:這是一個物件,其中包含了 story 中所需的參數(args)以及它們的值。在這個例子中,primary
被設置為true
,label
被設置為'Button'
。教學總結:
這個 Story 的定義告訴了 Storybook 如何呈現名為
Primary
的 story。它將primary
設置為true
,並將label
設置為'Button'
。為什麼要定義 Story?這是因為通過定義不同的 stories,你可以在 Storybook 中測試你的元件在不同情況下的表現,並且可以在開發過程中輕鬆地檢視和驗證元件的外觀和功能。
如果你有任何進一步的問題,或者需要更多的說明,請隨時告訴我!
在單一 Story 物件中,可以填寫的主要屬性包括
name
、args
、argTypes
、parameters
、decorators
等。讓我針對這些屬性進行解釋:
name
:Story 的名稱
- 功能:指定 Story 的名稱,用來識別和展示這個 Story。
- 範例:
name: 'Primary Button'
args
:Story 中的參數(args)
功能:
args
是一個物件,它包含了 Story 中所需的參數以及它們的值。這允許你在 Story 中設置元件的不同屬性,以測試不同的場景。範例:
args: { primary: true, label: 'Button', }
argTypes
:Story 中參數的類型定義
功能:
argTypes
允許你定義 Story 中參數(args)的類型,以及它們的控制方式。這有助於 Storybook 生成相應的控制項。範例:
argTypes: { primary: { control: 'boolean' }, label: { control: 'text' }, }
parameters
:Story 的參數
功能:
parameters
允許你設置 Story 的參數,例如畫布的排版方式、自動生成文檔等。範例:
parameters: { layout: 'fullscreen', docs: { description: { story: 'A primary button', }, }, }
decorators
:Story 的裝飾器
功能:
decorators
允許你在 Story 的呈現過程中進行裝飾,例如添加外框、風格等。範例:
decorators: [ (Story) => <div style={{ margin: '3em' }}><Story /></div> ]
這些屬性允許你配置和自訂 Story 的各個方面,以確保 Storybook 可以準確展示和測試你的元件。你可以根據你的需求在 Story 物件中填寫這些屬性,以達到你的測試和展示目標。
如果你需要進一步的解釋或有其他問題,請隨時告訴我!
綜合以上,可以知道Storybook就是針對component
展示該component所傳入的props不同,而有不同變化的樣子
不但是元件的使用示範,也測試了在各種參數下的樣貌是否符合預期
展示這件事情,在多人團隊合作時,如果有共用的元件庫,就能更友好地達到共用
透過Storybook達到寫component文件的效果
以我下方的例子來說,首先要先安裝react-bootstrap
npm install react-bootstrap
然後我對bootstrap的tooltip進行了包裝,變成以下的元件
import 'bootstrap/dist/css/bootstrap.min.css'
import React, { CSSProperties } from "react"
import { Button, OverlayTrigger, Tooltip } from "react-bootstrap";
import { OverlayTriggerType } from "react-bootstrap/esm/OverlayTrigger";
import { Placement } from "react-bootstrap/esm/types";
export interface TooltipButtonProps {
placement?: Placement;
tooltipText: string;
style?: CSSProperties;
buttonStyle?: CSSProperties;
onClick?(event: React.MouseEvent): void;
id: string;
buttonText: string | JSX.Element;
variant?: string;
disabled? : boolean,
trigger?: OverlayTriggerType | OverlayTriggerType[],
show?: boolean
}
export function TooltipButton(props:TooltipButtonProps): JSX.Element {
const defaultStyle: CSSProperties = {
cursor: 'pointer',
display: 'inline-block',
background: 'transparent',
border: 'none'
}
return (
<OverlayTrigger
trigger={props.trigger || ['focus','hover']}
placement={props.placement}
overlay={
<Tooltip id={props.id}>
{props.tooltipText}
</Tooltip>
}
show={props.show}
>
{(props.variant)?
<Button
variant={props.variant}
style={props.buttonStyle}
disabled={props.disabled}
onClick={props.onClick}
>
{props.buttonText}
</Button> :
<button
style={{...defaultStyle,...props.buttonStyle}}
disabled={props.disabled}
onClick={props.onClick}
>
{props.buttonText}
</button>
}
</OverlayTrigger>
)
}
以下是根據你提供的元件程式碼撰寫的 Storybook Story,並包含了
tags: ['autodocs']
和StoryObj
的寫法。這個 Story 允許你測試TooltipButton
元件的不同場景。import React from "react"; import { Meta, StoryObj } from '@storybook/react'; import { TooltipButton, TooltipButtonProps } from './TooltipButton'; const meta: Meta = { title: 'Example/TooltipButton', component: TooltipButton, parameters: { layout: 'centered', }, tags: ['autodocs'], }; export default meta; type Story = StoryObj<typeof meta>; export const Default: Story = { args: { tooltipText: 'This is a tooltip', buttonText: 'Button', id: 'example-tooltip', }, }; export const WithVariant: Story = { args: { tooltipText: 'This is a tooltip', buttonText: 'Primary Button', id: 'example-tooltip', variant: 'primary', }, }; export const Disabled: Story = { args: { tooltipText: 'This button is disabled', buttonText: 'Disabled Button', id: 'example-tooltip', disabled: true, }, }; export const CustomStyle: Story = { args: { tooltipText: 'Custom style for the button', buttonText: 'Styled Button', id: 'example-tooltip', buttonStyle: { background: 'red', color: 'white', }, }, };
這個 Story 定義了幾個不同的場景:
Default
:使用預設參數呈現TooltipButton
。WithVariant
:使用variant
參數設置為'primary'
。Disabled
:使用disabled
參數設置為true
。CustomStyle
:使用自訂的buttonStyle
。這些 Story 可以用來測試和展示你的
TooltipButton
元件在不同情況下的表現。希望這對你有所幫助!如果你有任何其他問題或需要進一步的說明,請隨時告訴我。
優雅,真是太優雅了 (X)
好的,讓我綜合以上的內容,為你列出 Storybook 中撰寫 Story 的重點:
- Story 的基本結構:
- Story 是一個描述元件在特定場景下呈現方式的物件。
- 每個 Story 包含了一個或多個故事,用於測試和展示你的元件。
- Story 的定義:
- Story 是以一個物件形式存在的,其中包含了多個屬性,如
name
、args
、argTypes
、parameters
、decorators
等。- 常用屬性的解釋:
name
:指定 Story 的名稱,用來識別和展示這個 Story。args
:包含了 Story 中所需的參數以及它們的值,用於測試不同場景。argTypes
:定義 Story 中參數(args)的類型以及它們的控制方式,有助於 Storybook 生成相應的控制項。parameters
:用於設置 Story 的參數,如畫布的排版方式、自動生成文檔等。decorators
:允許你在 Story 的呈現過程中進行裝飾,如添加外框、風格等。- Story 的型別定義:
- Storybook 中使用
StoryObj
進行 Story 的型別定義,以提供更好的開發體驗和類型安全。結語:
撰寫 Story 是開發元件時的重要一環,它讓你可以輕鬆地測試和展示你的元件在不同場景下的表現。透過合理利用 Story 的屬性,你可以更有效地進行元件的開發和測試工作,並且在團隊協作時提供清晰的文檔和範例。
希望以上的資訊對你有所幫助,如果你有任何進一步的問題,請隨時向我詢問!
OK這個就是請ChatGPT講解Storybook的樣子
說實在接連的請ChatGPT進行Cypress或是Storybook的語法講解
都有感受到版本差異,套件類型的東西更新的太快了,不是很適合讓ChatGPT來教學
但Storybook的範例提供、安裝難易度都讓上手本身就簡單很多
我這邊實驗過,如果單純請ChatGPT提供Storybook 範例程式碼
會用到比較舊的語法,導致跑起來可能有一點問題,像這樣
所以只好有一點偷吃步的,拿官方的範例請ChatGPT按照這份範例來講解並提供新的程式碼
和ChatGPT的對話記錄在這邊:
https://chat.openai.com/share/c91901d8-528b-4c4d-88fd-2ae6a8748bbe
測試相關的內容就先到這邊!
下一篇終於要往後端語言跨了!NodeJS!
後續主要要處理資料庫連接、或是搭配nestJS進行開發的部分
從JS跨NodeJS基本上很多語法都很相似,在語法上銜接起來個人認為是相當無痛的
我是用Stroybook來做元件文件的前端工程師一宵三筵,我們明天見!