はじめに
Livebook 0.9.0 がリリースされました
その中の目玉機能 Deploy を紹介します
なんと、 Livebook でそのまま Web アプリが実装できて、デプロイ、つまり実行環境への配置までできてしまうのです
論よりRun!
やってみましょう
チュートリアルの起動
まず Livebook 0.9.0 を起動しましょう
Docker から起動する方は以下の記事を参照
Livebook のトップ画面は以下のようになっています
ここで右側を見ると、「Deploy a chat app with Kino」という文言があります
ここがチュートリアルになっているので、クリックして開きます
このチュートリアル用ノートブックを実行していけばチャットアプリを公開することができます
簡単に解説していきます
セットアップ
まず依存モジュールとして Kino の 0.9.0 以上をインストールします
Mix.install([
{:kino, "~> 0.9.0"}
])
ボタンイベントの受信
最初は Kino.Control で出来ることを紹介しています
以下のようなコードで Livebook 上に「Click me!」と書かれたボタンを作ることができます
click_me = Kino.Control.button("Click me!")
ただし、この時点ではクリックしても何も起きません
以下のようにボタンをサブスクライブ(購読)することで、 Livebook 上でボタンをクリックイベントを受け取ることができるようになります
Kino.Control.subscribe(click_me, :click_me)
以下のコードを実行すると、現在の Livebook で受け取ったメッセージを表示できます
Process.info(self(), :messages)
最初の実行結果は以下のようになります
{:messages, []}
「Click me!」ボタンを一度クリックし、 Process.info
のセルを再度実行すると以下のようになります
{:messages, [click_me: %{origin: "lg2skzimyf23jho3shol2xwgrnbcujwd", type: :click}]}
ボタンをさらにクリックしてから再実行すれば、クリックした数だけメッセージを受け取ったことがわかります
{:messages,
[
click_me: %{origin: "lg2skzimyf23jho3shol2xwgrnbcujwd", type: :click},
click_me: %{origin: "lg2skzimyf23jho3shol2xwgrnbcujwd", type: :click},
click_me: %{origin: "lg2skzimyf23jho3shol2xwgrnbcujwd", type: :click},
click_me: %{origin: "lg2skzimyf23jho3shol2xwgrnbcujwd", type: :click},
click_me: %{origin: "lg2skzimyf23jho3shol2xwgrnbcujwd", type: :click}
]}
ボタンイベントの列挙
次に「Click me again!」ボタンを作ります
click_me_again = Kino.Control.button("Click me again!")
続いてこのボタンを for に渡してみます
for event <- click_me_again do
IO.inspect(event)
end
すると、セルが実行状態のままになります(無限ループになります)
この状態で「Click me again!」ボタンをクリックすると、ボタンをクリックするたびにイベントを受け取って内容を表示できます
Kino.Frame とアニメーション
Kino.Frame.new()
で空っぽのフレーム(枠)を作ります
frame = Kino.Frame.new()
以下のコードを実行すると、上で実行結果に作られた空のフレームに 1 から 100 の範囲からランダムな数字が表示されます
Kino.Frame.render(frame, "Got: #{Enum.random(1..100)}")
Kino.Frame.render
を再度実行すると、結果は上書きされます
Kino.Frame.render
だったところを Kino.Frame.append
に変更すると、上書きではなく追記になります
Kino.Frame.append(frame, "Got: #{Enum.random(1..100)}")
以下のように書くと、100ミリ秒毎に数字をカウントして表示します
Kino.animate(100, fn i ->
Kino.Markdown.new("**Iteration: `#{i}`**")
end)
以下のようにボタンを作ってから Kino.animate
に渡すと、ボタンのクリックイベントの度にカウントして表示します
button = Kino.Control.button("Click") |> Kino.render()
Kino.animate(button, 0, fn _event, counter ->
new_counter = counter + 1
md = Kino.Markdown.new("**Clicks: `#{new_counter}`**")
{:cont, md, new_counter}
end)
入力フォームのイベント受信
ここまでやってみたことを組み合わせてみます
まず空のフレームを用意します
frame = Kino.Frame.new()
Kino.Input.text
でテキスト入力を作り、それらをまとめて Kino.Control.form
に渡すことで入力フォームを作ります
inputs = [
name: Kino.Input.text("Name"),
message: Kino.Input.text("Message")
]
form = Kino.Control.form(inputs, submit: "Send", reset_on_submit: [:message])
この時点では入力しても何も起こりません
このフォームのイベントを Kino.listen
でサブスクライブし、結果をフレームに表示します
名前とメッセージは必須入力とし、空の場合はエラーメッセージを表示します
Kino.listen(form, fn %{data: %{name: name, message: message}, origin: origin} ->
if name != "" and message != "" do
content = Kino.Markdown.new("**#{name}**: #{message}")
Kino.Frame.append(frame, content)
else
content = Kino.Markdown.new("_ERROR! You need a name and message to submit..._")
Kino.Frame.append(frame, content, to: origin)
end
end)
この状態で入力フォームにテキストを入れて「Send」ボタンをクリックすると、フレームにメッセージが追加されていきます
このように、 Kino を使うと Livebook 上で Web の入力フォームと、その結果表示が実装できます
デプロイ(実行環境への配置)
いよいよ実装した Web 画面をデプロイしましょう
Livebook 左メニューのロケットアイコンをクリックします
するとデプロイ用のメニューが出てくるので、 Slug (URL の末尾の部分) を入れて、「Deploy」ボタンをクリックします
すると、下にデプロイ状況が表示されますが、いつまで経っても「Booting」のまま進みません
これは現在のノートブックに無限ループが含まれているためです
一旦、デプロイ状況の右下ゴミ箱アイコンをクリックしてデプロイを削除します
無限ループを含んでいる「Enumerating controls」のセクションを全部消してから再度デプロイします
すると、デプロイ状況が「Running」になります
表示されている URL をクリックしてデプロイした画面を開いてみましょう
実装した画面が表示されました
チャットもそのまま動きます
別のブラウザやシークレットウィンドウなどで同じ URL を開いてみましょう
パスワード保護をかけていたので、パスワード入力を求められます
「Password-protected」テキスト入力右端のアイコンをクリックし、パスワードを表示します
表示されたパスワードをコピーして入力し「Authenticate」をクリックすると、別ブラウザでも同じ画面を開くことができます
それぞれの入出力は当然同期して動きます
ローカルホストで動かした Livebook を ngrok を使って公開すれば、チャットも外部に公開可能です
また、そもそも Livebook を Fly.io で動かしていればそのまま共有できます
まとめ
とうとう Livebook もここまできたか、という感じです
まさか Web アプリ開発を対話的にやってしまうとは、、、
チュートリアルではチャットを作りましたが、 Livebook で出来るものならなんでもデプロイ可能なので、あんなことやこんなことまで出来そうですね