kubell Advent Calendar 2024 シリーズ 1の12/9の記事です。
こんにちはkubellのフロントエンド開発部の末竹(magcho)🐧です。
今日においてフロントエンドのUIにおけるカタログ・テスト基盤としてStorybookが採用されることがあるかと思います。 特に最近のStorybookではコンポーネントテスト・UIテスト・振る舞いテストとしての機能が充実しています。
Storybookは公式にReact, Vue, Angular, ...をサポートしており少しの設定でこれらのフレームワーク(テンプレートエンジン)で作られたコンポーネントを掲載できますがそれ以外のフレームワークで作られたものは利用ができません。
本記事では任意のフレームワーク(テンプレートエンジン)で書かれたマークアップをStorybookに掲載する方法について紹介します。
今回は以下のbuttonタグを10個表示するSmartyのマークアップを題材に扱っていきます。
{$lang = "smarty"} <div> {for $i=1 to 10} <button>{$i}</button> {/for} </div> <b>This is {$lang}</b>
今回はSmaryをJavaScriptでも扱えるようにjSmartというパッケージを利用しました。
まずばStorybookのセットアップです。frameworkは一旦HTMLとして初期化しておきましょう。このままではもちろんSmartyではなくHTMLしか掲載できません。
npm init -y && npx storybook@latest init
任意のテンプレートエンジンを簡単に掲載する方法としては CSFv3のrenderを使う方法があります。
import jSmart from 'jsmart' const smartyTempalte = ` {$lang = "smarty"} <div> {for $i=1 to 10} <button>{$i}</button> {/for} </div> <b>This is {$lang}</b> `; const smartyRenderer = (template) => { const compiled = new jSmart(template); return compiled.fetch() }; export default { title: "Smarty/Page", render: () => smartyRenderer(smartyTempalte), }; export const Sample = {};
CSFv3のrenderに対してHTMLを文字列で返す関数を渡すことで、任意のHTMLを利用できます。今回はjSmartを用いてSmartyテンプレートをHTML文字列に変換する処理を行い、HTML 文字列をStorybookに渡しています。
Storybookのargsから値を渡し、テンプレート中の表示のバリエーションを確認したいケースもあるかと思います。
CSFv3のrenderの型を確認すると以下のようになっており、第一引数にてargsが渡されそうであることが推測できます。
type ArgsStoryFn<TRenderer extends Renderer = Renderer, TArgs = Args> = (args: TArgs, context: StoryContext<TRenderer, TArgs>) => (TRenderer & { T: TArgs; })['storyResult'];
実際に以下のように記述することでStorybook側からテンプレートに値を渡すことができました。
import jSmart from "jsmart"; const smartyTempalte = ` <div> {for $i=1 to 10} <button>{$i}</button> {/for} </div> <b>I like {$food}</b> `; const smartyRenderer = (template, args) => { const compiled = new jSmart(template); return compiled.fetch(args); }; export default { title: "Smarty/Page", render: (args) => smartyRenderer(smartyTempalte, args), args: { food: "sushi", }, }; export const Sample = {};
さて、これでは肝心のテンプレートをJavaScriptの変数として持たなければなりません。Smartyは本来的PHPで利用するものであり*.tpl
拡張子のファイルで運用することが多いでしょう。
また、Storybookとしてはテンプレート(コンポーネント)とstoriesファイルを分離した方が管理しやすい側面もあります。
storiesファイル内でfsなどを利用してファイルを読み込ませようとするとエラーになります。これはstorybookのrender処理はブラウザ上で実行されるためです。
ブラウザで実行する前にテンプレートをバンドルすることで回避が可能です。これにはviteのraw saffix機能で簡単に解決ができます。import smartyTempalte from "./Sample.tpl?raw";
のように後ろにrawをつけるとviteはテキストファイルの場合はsmartyTempalteという変数に内容を文字列としてインライン展開してくれます。これを利用することで*.tpl
ファイルを分けた状態で利用ができました。
以上でStorybookにSmartyを掲載することができました。
今回はSmartyを利用しましたがブラウザ上にてHTML文字列が組み立てできれば他のテンプレートエンジンであっても同様の方法で解決ができます。公式に対応していないテンプレートエンジンをStorybookに載せたくてたまらない方は是非お試しください。