ElixirでWebサーバーといえば
Phoenixですが、既存のElixirアプリケーションにちょっとWebサーバーの機能を足すだけの場合にはちょっと大規模すぎたので、Phoenixよりもコンパクトな
Cowboyを使うことにしました。Phoenixのサーバーコア部分はCowboyなので、比してコンパクトという表現は実はちょっとおかしいですね。
ソースコードの
examples以下には、いくつもサンプルプロジェクトがあり、それをそのまま動かすのも、参考にして動かすのも簡単です。ドキュメントもErlangなのに十分にあり、必要なハンドラを定義して差し込むだけで動きの把握もしやすく、素晴らしいライブラリですね。
ただしひとつだけ罠があり、それはサンプルで用いられるファイル読み出し指定が priv_dir や priv_file であることです。例えば
static_worldのサンプルでは…
Dispatch = cowboy_router:compile([
{'_', [
{"/", cowboy_static, {priv_file, static_world, "index.html"}},
{"/[...]", cowboy_static, {priv_dir, static_world, "", 以下略
]}
]),
Elixirで書くとこんな感じ:
dispatch = :cowboy_router.compile([
{:_, [
{"/", :cowboy_static, {:priv_file, :static_world, "index.html"}},
{"/[...]", :cowboy_static, {:priv_dir, :static_world, ""}, 以下略}
]}
])
これをiexで走らせると動いて安心していたのですが、escriptにしたりアプリケーションとしてリリースしようとしたりすると全然動かない。index.htmlなどのファイルが見つからないときの挙動をする…。 どこに置いてもindex.htmlなどのファイルをアプリケーションが見つけてくれない。
同様に
priv方面ではまっている英語の記事があり、そちらではそのまま力技で解決していましたが、そんなに頑張らなくても、単にprivディレクトリを使う指定をやめればOKでした。
dispatch = :cowboy_router.compile([
{:_, [
{"/", :cowboy_static, {:file, "web/index.html"}},
{"/static/[...]", :cowboy_static, {:dir, "web/static"}}
]}
])
実コードから引っ張ってきたので若干パス指定が違いますが、要点は:priv_fileではなく:file、:priv_dirではなく:dirを使うこと。アプリケーションからの相対位置で無事読めました。privディレクトリがErlang的に特別なものらしいのです。ぐぐるとほとんど情報がないなかに、
ユーザーズガイド邦訳から以下の説明が見つかります。
アプリケーション固有のファイルの格納に使用されます。例えば、Cの実行ファイルがここに置かれます。code:priv_dir/1関数を使用すると、このディレクトリにアクセスすることができます。
単にprivという名前のディレクトリではないことはわかりました。Cの実行ファイルを格納するようなところに、Webのリソースを置くのはなんか違うんじゃないかなという感覚があるのですが…
# 2016/04/20追記
公式のMix.Tasks.Escript.Buildの項目に
Note: escripts do not support projects and dependencies that need to store or read artifacts from the priv directory.
とありました。