🥝

Pug使用の ただのnpm scriptタスクランナ環境でstorybookを使う

4 min read

やること

フレームワークを使用していない、ただのnpm scriptタスクランナー(CSS:Sass、HTML:Pug、Javascript:Typescript、...その他好きに用意しているタスク群)でstorybookを使うのをやってみる
コンポネはPugで書いて、コピーするコードもPugがいい
SPAではないので、もともとの開発環境にはドッキングさせず使いたい(依存を深くもたせず、すぐアップデートできる、または切り離せる状態にしておきたい)

最初のコマンド

npx -p @storybook/cli sb init -t html

追加されるディレクトリと更新ファイル

追加されたディレクトリ

.storybook/ ← storybook設定JS
stories/ ← storybookのコンポネ群

package.json のscript更新

"storybook": "start-storybook -s _サイトルートパス_ -p 6006 --no-manager-cache",
"build-storybook": "build-storybook -o _ビルド時のコンパイル先パス_"

サイトルートパスやビルド時のコンパイル先パスは追加で設定

Pugの設定

コードをPugで書く

storypug をいれる

main.js (storypug公式どおり)

module.exports = {
  addons: [
    {
      name: 'storypug',
      options: {babel: true, loaderOptions: {root: 'src/_devassets/_pug'}},
    },
  ],
};

./stories/component/Text.stories.ts

import startCase from 'lodash/startCase';
import { Meta, Story } from '@storybook/html';
import { renderer } from 'storypug';
const { render } = renderer({ startCase });
const Text = require('./Text.pug'); // pugファイルにして外出し

export default {
  title: 'Component/Text',
  argTypes: {
    size: {
      control: { type: 'radio', options: ['none', 'sm'] },
    },
    color: {
      control: { type: 'radio', options: ['none', 'black', 'blue', 'red', 'supple', 'auxil'] },
      defaultValue: 'none',
    },
  },
} as Meta;

const Template: Story = (args) => {
  const wrapper = render(Text, args);
  const div = document.createElement('div');
  div.append(wrapper.$root);
  return div.innerHTML; // 公式のまま(wrapper.$root;)だとDocsでエラーが出て変更
};

export const body = Template.bind({});
body.args = {
  size: 'none',
};

export const sm = Template.bind({});
sm.args = {
  size: 'sm',
};

./stories/component/Text.pug

mixin dom (args = {})
  - const props = Object.assign({}, args)
  - const classes = `${props.color !== 'none' ? ` c-color-${props.color}` : '' }`
  p.c-txt(class=`${classes}`) テキストテキストテキストテキスト

コピーするコードをPug変換する

この記事を参考に html2jade を噛ませて変換をかける

https://stackoverflow.com/questions/65096989/storybook-for-react-to-show-plain-html-source-code-with-preview-addon

./storybook/preview.js

import renderToHtml from './renderToHtml';
export const parameters = {
  docs: {
    transformSource: (src, storyContext) => renderToHtml(storyContext.storyFn),
  },
};

.storybook/renderToHtml.js

import { renderToStaticMarkup } from 'react-dom/server';
import { AllHtmlEntities } from 'html-entities';
const entities = new AllHtmlEntities();

export default (story) => {
  let html = entities.decode(renderToStaticMarkup(story()));
  const html2pug = require('html2jade');
  html2pug.convertHtml(html, { donotencode: true }, (err, pug) => {
    if (err) {
      throw new Error(err);
    } else {
      html = pug;
    }
  });
  return html;
};

そのほか遭遇したエラー

pug変換したらfsエラーがでる: Module not found: Error: Can't resolve 'fs' in

こちらで解消

https://github.com/storybookjs/storybook/issues/4082#issuecomment-417329791

@whitespace/storybook-addon-html を入れるとHTMLタブでエラーがでる: Cannot convert undefined or null to object

こちらで解消

https://github.com/storybookjs/storybook/issues/14631

サイトのスタティックなcommon.jsをプレビュー画面で実行させたい

DOMContentLoadedが効かないらしい...

https://bleepcoder.com/ja/storybook/421604152/storybook-html-5-0-1-can-t-run-scripts-on-story-load-aka

こちらのdecoratorで対応

https://zenn.dev/sa2knight/books/aca5d5e021dd10262bb9/viewer/958abe

MutationObserverを使うやり方もあるらしい

https://github.com/storybookjs/storybook/issues/6113#issuecomment-473965255

storybookのルーターイベント取得方法を調べ中

入れたアドオン一覧

@babel/core => 勝手にる
@storybook/html => 勝手に入る
@storybook/addon-essentials => storybookの標準便利機能を使うため入れる
@storybook/addon-links => 同上
storypug => コンポネをpugで書くために入れる
html2jade => 「copy code」でpug変換させるために入れる
@whitespace/storybook-addon-html => HTMLタブも欲しくて入れる
@storybook/react => プレビューエリアをカスタマイズしたくて入れる
html-to-react => プレビューエリアにdecoratorで変換を加えたくて入れる
@storybook/theming => storybook自体のテーマを変えたくて入れる

Discussion

ログインするとコメントできます