エンジニアのソフトウェア的愛情

または私は如何にして心配するのを止めてプログラムを・愛する・ようになったか

file_system パッケージを使ってファイルの更新を監視する Phoenix app についての覚書

いまさらなのですが。

Phoenix app の開発時に、コードを更新したときに自動的に再読み込みをおこなうしくみを file_system というパッケージが担っているということを知りました。

ということなので。

file_system を使ってファイルの更新を監視し Phoenix LiveView を使ってリアルタイムにブラウザの表示に反映するというのをやります。 これはその覚書。


作成

アプリケーションを用意します。

Phoenix 1.5 以降であれば LiveView のためのオプション --live が追加されているので、それを指定します。 1.5 よりも前のバージョンを利用するばあいはドキュメントのインストール手順に従ってインストールしてください。

$ mix phx.new my_app --live

lib/my_app_web/live/page_live.ex

--live オプションで生成される LiveView のモジュールを次のように書き換えます。 手作業でインストールしたばあいは新たにファイルを作成します。

ここではモジュール FileSystem のプロセスにディレクト/tmp を監視させます。

また通知を受け取るためのハンドラ handle_info/2 を記述します。 受け取った通知は file_events という名前のリストに追加しています。

defmodule MyAppWeb.PageLive do
  use MyAppWeb, :live_view

  @impl true
  def mount(_params, _session, socket) do
    if connected?(socket) do
      {:ok, watcher_pid} = FileSystem.start_link(dirs: ["/tmp"])
      FileSystem.subscribe(watcher_pid)
    end

    {:ok, assign(socket, :file_events, [])}
  end

  def handle_info({:file_event, watcher_pid, {path, events}}, socket) do
    {:noreply, update(socket, :file_events, &[{path, events} | &1])}
  end
end

lib/my_app_web/live/page_live.html.leex

LiveView のテンプレートを書き換え(あるいは作成)します。

<ul>
  <%= for {path, events} <- @file_events do %>
    <li>
      <span><%= path %></span>
      <span><%= inspect(events) %></span>
    </li>
  <% end %>
</ul>

lib/my_app_web/router.ex

LiveView を手作業でインストールしモジュールを新規に追加したばあいは、LiveView を利用するようにルーティングも変更します。

  scope "/", MyAppWeb do
    pipe_through :browser

    live "/", PageLive, :index
  end

実行

Phoenix app を起動します。

$ iex -S mix phx.server

FileSystem のプロセスが監視するディレクトリを操作します。

$ echo hi > /tmp/hi.txt
$ echo hello > /tmp/hello.txt

操作と同時にブラウザ上の表示が更新されることが確認できます。

f:id:E_Mattsan:20200503100015p:plain