はじめに
phx_live_storybookを試すことを楽しんでみます。
Hey there, we just released 0.4.0 of phx_live_storybook 🔥
— Christian Blavier (@cblavier) September 29, 2022
A lot of work was involved in shipping new features, fixing bugs, refactoring code, and integrating feedback from both @josevalim & @chris_mccord https://t.co/IGCjNaDyxC#MyElixirStatus
Elixirの作者José Valimさん、Phoenixの作者Chris McCordさんの両御大がフィードバックをくれているそうです。
What is phx_live_storybook ?
御両所も注目のphx_live_storybookとは、そもそも一体何でしょうか。
説明を読んでみます。
PhxLiveStorybook provides a storybook-like UI interface for your Phoenix LiveView components.
JSの世界に、Storybookというものが存在するそうです。
Storybook is a frontend workshop for building UI components and pages in isolation. Thousands of teams use it for UI development, testing, and documentation. It’s open source and free.
Storybookをよく知っている方はこの時点でピンとこられたこととおもいます。
私はこの世界を知らないので文章の説明だけでは、私はわかりませんでした。
それでとりあえずわからないものは触ってみるということで触ってみました。
そのことを書いておきます。
あとでわかることですが、自分で作成したUI componentをいろいろと試すことができるようです。
デモ
phx_live_storybook
作者の方がデモサイトを立ち上げてくださっています。
こちらを触ってみるのが一番わかりやすいとおもいます。
使用したElixirとErlang、Phoenixのバージョン
- Phoenix v1.6.13
- elixir 1.14.0-otp-2
- erlang 25.0.3
おことわり
Phoenix 1.7(未リリース)と組み合わせるほうがよさそうです。
理由は後述します。
とりあえず今日時点で動かした手順を書いておきます。
mix phx.new
mix phx.new hello_storybook
cd hello_storybook
mix setup
依存Hexを追加
defp deps do
{:phoenix_live_view, "~> 0.18.1"}, # change
{:phoenix_live_dashboard, "~> 0.6", override: true}, # change
...
{:phx_live_storybook, "~> 0.4.0"}, # add
{:tailwind, "~> 0.1", runtime: Mix.env() == :dev}, # add
{:heroicons, "~> 0.5.0"} # add
end
phx_live_storybook
0.4.0は、phoenix_live_view
0.18以上が必要です。
それで、mix phx.new
でもともと書かれていた、phoenix_live_view
とphoenix_live_dashboard
の指定を変更しています。
tailwind
はのちほどの手順でmix phx.gen.storybook
ということを行うのですが、そのときにTailwindの設定を書き換えるように指示されるのでインストールしました。
Tailwindは、
の手順に従って設定を進めてください。
heroicons
は、mix phx.gen.storybook
にてIconコンポーネントのサンプルが作られます。そのサンプルが依存するのでここでインストールしています。
mix deps.get
phoenix_live_view
とphoenix_live_dashboard
の指定を変更しないと以下のエラーでコケます。
Resolving Hex dependencies...
Failed to use "phoenix_live_view" (version 0.17.12) because
phoenix_live_dashboard (version 0.6.5) requires ~> 0.17.7
phx_live_storybook (versions 0.4.0 and 0.4.1) requires ~> 0.18
mix.lock specifies 0.17.12
** (Mix) Hex dependency resolution failed, change the version requirements of your dependencies or unlock them (by using mix deps.update or mix deps.unlock). If you are unable to resolve the conflicts you can try overriding with {:dependency, "~> 1.0", override: true}
mix phx.gen.storybook
mix phx.gen.storybook
というインストールコマンドが使えるようになるので、実行します。
以下のファイルが作られます。
- assets/css/storybook.css
- assets/js/storybook.js
- lib/hello_storybook_web/storybook.ex
- storybook/components/icon.story.exs
- storybook/my_page.story.exs
またインストールの途中で手動で実行すべき作業が示されます。
その通りに手動で変更をします。
* manual setup instructions:
Add the following to your router.ex:
use HelloStorybookWeb, :router
import PhxLiveStorybook.Router
scope "/" do
storybook_assets()
end
scope "/", HelloStorybookWeb do
pipe_through(:browser)
live_storybook "/storybook", backend_module: HelloStorybookWeb.Storybook
end
[Y to continue] [Yn] Y
* manual setup instructions:
Add js/storybook.js as a new entry point to your esbuild args in config/config.exs:
config :esbuild,
default: [
args:
~w(js/app.js js/storybook.js --bundle --target=es2017 --outdir=../priv/static/assets ...),
...
]
[Y to continue] [Yn] Y
* manual setup instructions:
Add a new Tailwind build profile for css/storybook.css in config/config.exs:
config :tailwind,
...
default: [
...
],
storybook: [
args: ~w(
--config=tailwind.config.js
--input=css/storybook.css
--output=../priv/static/assets/storybook.css
),
cd: Path.expand("../assets", __DIR__)
]
[Y to continue] [Yn] Y
* manual setup instructions:
Add a new endpoint watcher for your new Tailwind build profile in config/dev.exs:
config :hello_storybook_web, HelloStorybookWeb.Endpoint,
...
watchers: [
...
storybook_tailwind: {Tailwind, :install_and_run, [:storybook, ~w(--watch)]}
]
[Y to continue] [Yn] Y
* manual setup instructions:
Add a new live_reload pattern to your endpoint in config/dev.exs:
config :hello_storybook_web, HelloStorybookWeb.Endpoint,
live_reload: [
patterns: [
...
~r"storybook/.*(exs)$"
]
]
[Y to continue] [Yn] Y
You are all set! 🚀
mix phx.server
mix phx.server
立ち上がりません。エラー内容は、
== Compilation error in file lib/hello_storybook_web/views/layout_view.ex ==
** (CompileError) lib/hello_storybook_web/templates/layout/live.html.heex:4: undefined function live_flash/2 (expected HelloStorybookWeb.LayoutView to define such a function or for it to be imported, but none are available)
「Phoenix 1.7(未リリース)と組み合わせるほうがよさそうです」の理由です。
mix.exs
のバージョン指定を変えたことで、Phoenix.Component.live_flash/2が使えなくなっています。
ドキュメントは
と書いてあります。
Phoenix 1.7を待ったほうがよさそうです。
Phoenix.Flash
モジュールは探しましたが見当たりません。
とりあえず先へ進みたい
phx_live_storybookを楽しむという目的にとっては、大勢には影響がなさそうな箇所なので、lib/hello_storybook_web/templates/layout/live.html.heex
からPhoenix.Component.live_flash/2の呼び出しを消しちゃいます。
<main class="container">
<p class="alert alert-info" role="alert"
phx-click="lv:clear-flash"
- phx-value-key="info"><%= live_flash(@flash, :info) %></p>
+ phx-value-key="info"></p>
<p class="alert alert-danger" role="alert"
phx-click="lv:clear-flash"
- phx-value-key="error"><%= live_flash(@flash, :error) %></p>
+ phx-value-key="error"></p>
再度 mix phx.server
今度は立ち上がりました
Visit: http://localhost:4000/storybook
2 componentsのサンプルがあります。
自作コンポーネントを追加してみたい
まず自作のコンポーネントを作ります。
defmodule HelloStorybookWeb.Components.Button do
use HelloStorybookWeb, :component
attr :label, :string, required: true, doc: "Button label"
attr :theme, :atom
def button(assigns) do
assigns
|> assign_new(:theme, fn -> :not_set end)
|> assign_new(:label, fn -> "" end)
|> assign_new(:"bg-color", fn -> "bg-indigo-600" end)
|> assign_new(:"hover-bg-color", fn -> "hover:bg-indigo-700" end)
|> assign_new(:"text-color", fn -> "text-white" end)
|> render()
end
defp render(assigns) do
~H"""
<button phx-click="boom" type="button" theme={@theme} class={"inline-flex items-center px-2.5 py-1.5 border border-transparent text-xs font-medium rounded shadow-sm #{assigns[:"text-color"]} #{assigns[:"bg-color"]} #{assigns[:"hover-bg-color"]} focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"}>
<%= @label %>
</button>
"""
end
end
https://github.com/phenixdigital/phx_live_storybook_sample/blob/8178df34662b28bf0496b11b953b1a7145e5278f/lib/phx_live_storybook_sample/components/buttons/button.ex
を参考にしました。
(モジュール名を一部変えただけのコピペです)
続いて、storybookに表示されるようにします。
defmodule Storybook.Components.Button do
alias HelloStorybookWeb.Components.Button
use PhxLiveStorybook.Story, :component
def function, do: &Button.button/1
def description, do: "A simple button. If you click, I'll log a message!"
def variations do
[
%Variation{
id: :default,
description: "Default button",
attributes: %{
label: "Boom!"
}
},
%Variation{
id: :custom_colors,
description: "A button with custom colors",
attributes: %{
:label => "A button",
:"bg-color" => "bg-green-600",
:"hover-bg-color" => "bg-green-700"
}
}
]
end
end
これもhttps://github.com/phenixdigital/phx_live_storybook_sample/blob/8178df34662b28bf0496b11b953b1a7145e5278f/storybook/components/buttons/button.story.exs
を参考にしました。
(モジュール名を一部変えただけのコピペです)
この2つのファイルを用意すると、storybookにメニューが追加されます。
おわりに
phx_live_storybookを試すことを楽しんでみました。
私は、Phoenixのアプリケーションでcomponentをちゃんと作ったことがあまりありませんし、JSのStorybookのことは今日はじめて知りました。
わからないことが複数重なっているので、私にはその有り難みがまだよくわかっていません。
ただ、それは私がものを知らないだけです。
冒頭に紹介した通り、José Valimさん、Chris McCordさんの両御大がフィードバックをされているそうで、今後お世話になる機会はたくさん増えそうです。
phx_live_storybookが一人だけPhoenix 1.7+の世界を先取りしている感じが良いです
注目のHexです。