Storybook: 當一個快樂說書人

來聽碼農講故事

Posted by Lil Toby on Saturday, July 13, 2019

TOC

簡介

官方教學

  • 響應式 UI 開發及測試環境
  • 可有效提高組件的可重用性、可測試性和開發速度
  • 可以快速構建,而無需擔心應用程序特定的依賴

目錄結構

.
├── .storybook
│   ├── config.js                   # storybook 進入點
│   └── webpack.config.js           # 客製化 webpack 打包 for storybook
├── stories                         # 各種想說的故事
│   ├── comp-a
│   ├── ...
│   └── comp-z
├── storybook-static                # storybook gen 出來的 dist 資料夾
├── db.json                         # mock api 設定
├── routes.json                     # restful 路由處理
└── package.json                    # 新增 storybook 的 script

運作流程

其實 storybook 等於是另外打包同專案成另一個 APP 介面

  • storybook 啟動時會先以 .storybook/config.js 為進入點
  • 執行 loadStories() 依照設定批次載入故事腳本
  • 進行 storybook 自身的 wepback 打包
    • 如有額外需求需在 .storybook 資料夾下新增 webpack.config.js
  • 以 server 形式啟動 dashboard

安裝建置

已導入既有專案為例

  • 初始化安裝

    npx -p @storybook/cli sb init --type html
    
    
  • 安裝 storybook 相依工具 (babel 是為了 storybook 打包而裝的)

    yarn add -D @storybook/html babel-loader @babel/core
    
  • 加入下列指令至 package.json 的 scripts 欄位底下

    {
    "storybook": "start-storybook -p 6006",
    "build-storybook": "build-storybook",
    }
    
    
    • storybook 的 config 檔
    
    import { configure } from '@storybook/html';
    import '../src/scss/main.scss';
    
    function loadStories() {
    
    const myDOM = document.createElement('div');
    myDOM.className = 'bg';
    myDOM.style.cssText = 'margin-top: 200px; display: flex; justify-content: center; align-items: center;';
    
    require(`../stories/a.js`);
    require(`../stories/b.js`);
    require(`../stories/c.js`);
    }
    
    configure(loadStories, module);
    
    
  • storybook 的 webpack.config.js

    
    const path = require('path');
    
    module.exports = async ({ config, mode }) => {
    
    config.module.rules.push({
        test: /\.scss$/,
        use: ['style-loader', 'css-loader', 'sass-loader'],
        include: path.resolve(__dirname, '../'),
    });
    
    return config;
    };
    
    
    • mock 一個 json-server
    • 為了要模擬 API 藉以避免頁面壞掉
    • 開一個 db.json 在專案目錄下
    • 開一個 routes.json 指定 restful 路徑

    說故事

    已新增一個 推播泡泡 為例

    • 可看得出來 createDOM 負責把基本 dom 搭建出來
    • 需要用 setTimeout 克服非同步問題
    • 由以下 js 可見可以為一個元件設置不同狀態
    import { storiesOf } from '@storybook/html';
    import { createDOM } from './init.js';
    import Toast from '../src/js/component/Toast.js';
    
    const showToast = ({ text, num }) => {
    
    window.setTimeout(( () => {
        const Toast = new Toast();
        Toast.render(
            Toast.setVal( text, num )
        );
    }), 0);
    };
    
    
    storiesOf('Toast', module)
    .add('普通版', () => {
    
        const initDOM = createDOM();
        showToast({
            text: "歡迎回來",
            num: 1
        });
    
        return initDOM;
    })
    .add('浮誇版', () => {
        const initDOM = createDOM();
        showToast({
            text: "哇嗚~~ 大大您回來啦 LA LA LA~~~",
            num: 1
        });
    
        return initDOM;
    });
    
    

注意事項

  • div.insertAdjacentHTML( 'beforeend', str );

    • 可以把 html text 注入到指定 div
  • storybook 吃的 webpack 設定是在 .storybook 底下

    • 在此資料夾外怎麼設定都是沒用的喔

遇到問題

  • ERROR in ./.storybook/config.js Module build failed (from ./node_modules/babel-loader/lib/index.js): Error: [BABEL] /pathto/.storybook/config.js: You gave us a visitor for the node type PrivateName but it's not a valid type (While processing: "pathto/plugin-proposal-class-properties/lib/index.js")

    • 原因
      • babel 版本太舊
      • "@babel/core": "^7.0.0-beta.42",
    • 解法
      • 升到 “@babel/core”: “^7.0.0-beta.47”,
  • Uncaught (in promise) TypeError: Cannot read property 'insertAdjacentHTML' of null

    • 要用 setTimeout 往後延遲

參考連結

- 請 Toby 喝珍奶,你請我就喝 -

Lil Toby Blog

YA~大杯還小杯~看你誠意 ❤ ️

使用手機掃描 QRCODE 完成 pay 下去就對