29
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Livebook で Web アプリを実装してデプロイまでしてしまう

Last updated at Posted at 2023-03-26

はじめに

Livebook 0.9.0 がリリースされました

その中の目玉機能 Deploy を紹介します

なんと、 Livebook でそのまま Web アプリが実装できて、デプロイ、つまり実行環境への配置までできてしまうのです

論よりRun!

やってみましょう

チュートリアルの起動

まず Livebook 0.9.0 を起動しましょう

Docker から起動する方は以下の記事を参照

Livebook のトップ画面は以下のようになっています

スクリーンショット 2023-03-27 0.05.59.png

ここで右側を見ると、「Deploy a chat app with Kino」という文言があります

ここがチュートリアルになっているので、クリックして開きます

スクリーンショット 2023-03-27 0.13.34.png

このチュートリアル用ノートブックを実行していけばチャットアプリを公開することができます

簡単に解説していきます

セットアップ

まず依存モジュールとして Kino の 0.9.0 以上をインストールします

Mix.install([
  {:kino, "~> 0.9.0"}
])

ボタンイベントの受信

最初は Kino.Control で出来ることを紹介しています

以下のようなコードで Livebook 上に「Click me!」と書かれたボタンを作ることができます

click_me = Kino.Control.button("Click me!")

スクリーンショット 2023-03-27 0.17.38.png

ただし、この時点ではクリックしても何も起きません

以下のようにボタンをサブスクライブ(購読)することで、 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!」ボタンをクリックすると、ボタンをクリックするたびにイベントを受け取って内容を表示できます

button_events.gif

Kino.Frame とアニメーション

Kino.Frame.new() で空っぽのフレーム(枠)を作ります

frame = Kino.Frame.new()

スクリーンショット 2023-03-27 0.31.30.png

以下のコードを実行すると、上で実行結果に作られた空のフレームに 1 から 100 の範囲からランダムな数字が表示されます

Kino.Frame.render(frame, "Got: #{Enum.random(1..100)}")

スクリーンショット 2023-03-27 0.34.05.png

Kino.Frame.render を再度実行すると、結果は上書きされます

Kino.Frame.render だったところを Kino.Frame.append に変更すると、上書きではなく追記になります

Kino.Frame.append(frame, "Got: #{Enum.random(1..100)}")

スクリーンショット 2023-03-27 0.36.01.png

以下のように書くと、100ミリ秒毎に数字をカウントして表示します

Kino.animate(100, fn i ->
  Kino.Markdown.new("**Iteration: `#{i}`**")
end)

animate_md.gif

以下のようにボタンを作ってから 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)

button_animate.gif

入力フォームのイベント受信

ここまでやってみたことを組み合わせてみます

まず空のフレームを用意します

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])

スクリーンショット 2023-03-27 0.45.50.png

この時点では入力しても何も起こりません

このフォームのイベントを 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」ボタンをクリックすると、フレームにメッセージが追加されていきます

form_animate.gif

このように、 Kino を使うと Livebook 上で Web の入力フォームと、その結果表示が実装できます

デプロイ(実行環境への配置)

いよいよ実装した Web 画面をデプロイしましょう

Livebook 左メニューのロケットアイコンをクリックします

スクリーンショット 2023-03-27 0.57.41.png

するとデプロイ用のメニューが出てくるので、 Slug (URL の末尾の部分) を入れて、「Deploy」ボタンをクリックします

スクリーンショット 2023-03-27 1.00.19.png

すると、下にデプロイ状況が表示されますが、いつまで経っても「Booting」のまま進みません

スクリーンショット 2023-03-27 1.02.11.png

これは現在のノートブックに無限ループが含まれているためです

一旦、デプロイ状況の右下ゴミ箱アイコンをクリックしてデプロイを削除します

無限ループを含んでいる「Enumerating controls」のセクションを全部消してから再度デプロイします

すると、デプロイ状況が「Running」になります

スクリーンショット 2023-03-27 1.06.36.png

表示されている URL をクリックしてデプロイした画面を開いてみましょう

スクリーンショット 2023-03-27 1.08.48.png

実装した画面が表示されました

チャットもそのまま動きます

chat_solo.gif

別のブラウザやシークレットウィンドウなどで同じ URL を開いてみましょう

パスワード保護をかけていたので、パスワード入力を求められます

スクリーンショット 2023-03-27 1.12.31.png

「Password-protected」テキスト入力右端のアイコンをクリックし、パスワードを表示します

スクリーンショット 2023-03-27 1.13.44.png

表示されたパスワードをコピーして入力し「Authenticate」をクリックすると、別ブラウザでも同じ画面を開くことができます

それぞれの入出力は当然同期して動きます

ping_pong.gif

ローカルホストで動かした Livebook を ngrok を使って公開すれば、チャットも外部に公開可能です

また、そもそも Livebook を Fly.io で動かしていればそのまま共有できます

まとめ

とうとう Livebook もここまできたか、という感じです

まさか Web アプリ開発を対話的にやってしまうとは、、、

チュートリアルではチャットを作りましたが、 Livebook で出来るものならなんでもデプロイ可能なので、あんなことやこんなことまで出来そうですね

29
8
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
29
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?