ElmのバックエンドとしてPhoenixを使う

追記：最新版のphoenix1.3とElmについてはこちらの方を参照してください。
[ElmからPhoenix v1.3のRest APIを叩いてみる - Qiita](https://qiita.com/sand/items/e040e8769dc5d4aedbe1)



　Elmのバックエンドとして、Phoenixを使いたいと思いました。そのためにElixirやPhoenixを少し勉強しました。今回はその出発点になる知識をメモっておきたいと思います。以下のサイトを参考にしました。
[Phoenix and Elm, a real use case (pt. 1) - Code, Love & Boards](http://codeloveandboards.com/blog/2017/02/02/phoenix-and-elm-a-real-use-case-pt-1/)
[Setting up Elm with Phoenix – Brandon Richey – Medium](https://medium.com/@diamondgfx/setting-up-elm-with-phoenix-be3a9f55bac2)


　今回は単にPhoenixのフロントエンドとしてelmの単純な画面を表示するだけのプログラムを作ります。まず以下の手順でElmとElixir、Phoenixのインストールを行っていると仮定します。
[Elm開発環境について - Qiita](https://qiita.com/sand/items/9afaef65c6f1ebf453da)
[CentOS7にErlangとElixir、Phoenixをインストールしてみる - Qiita](https://qiita.com/sand/items/e98c9e98351b816c7e69)




　Phoenixでは、Brunchを使って、静的なアセットをビルドしています。Elmコードはbrunchに従ってコンパイルされ、ロードされます。幸いなことに、ElmコードをコンパイルするためのBrunch pluginであるelm-brunchが利用できます。さっそくプロジェクトを構築していきましょう。

　Phoenixのプロジェクトを作成します

```sh:
mix phoenix.new phoenix_elm_test
```



　elm-brunchをインストールします

```sh:
cd phoenix_elm_test
npm install --save-dev elm-brunch
```



　brunch-config.jsを編集します。2か所の追加が必要です（追加1と追加2）。

```brunch-config.js
exports.config = {
  // See http://brunch.io/#documentation for docs.
  files: {
    javascripts: {
      joinTo: "js/app.js"
    },
    stylesheets: {
      joinTo: "css/app.css",
      order: {
        after: ["web/static/css/app.css"] // concat app.css last
      }
    },
    templates: {
      joinTo: "js/app.js"
    }
  },

  conventions: {
    assets: /^(web\/static\/assets)/
  },

  // Phoenix paths configuration
  paths: {
    // Dependencies and current project directories to watch
    watched: [
      "web/static",
      "test/static",
//-------------追加１
      "web/elm"
//-------------
    ],
    // Where to compile files to
    public: "priv/static"
  },

  // Configure your plugins
  plugins: {
//-------------追加２
    elmBrunch: {
      elmFolder: "web/elm",
      mainModules: ["Main.elm"],
      outputFolder: "../static/vendor"
    },
//-------------
    babel: {
      // Do not use ES6 compiler in vendor code
      ignore: [/web\/static\/vendor/]
    }
  },

  modules: {
    autoRequire: {
      "js/app.js": ["web/static/js/app"]
    }
  },

  npm: {
    enabled: true
  }
};
```

　特に追加２のoutputFolderに注目してください。一般的にvendorフォルダはBrunchによってこれ以上変換（コンパイル）されないファイルの置き場所で、そこのファイルは全て、appプログラムの前にロードされ、連結されるという決まりのようです。以下で見るようにjs/app.jsからVendor/Main.js（Elmのコンパイル結果）を参照していますが、特にNotFoundエラーも出さずに、Elm.Mainモジュールを利用できます。
http://brunch.io/docs/config
http://brunch.io/docs/concepts




　次にweb/elmディレクトリを作成しcdして、Elmコードに必要なパッケージをインストールします。今回のElmコードにはelm-lang/htmlだけでokです。

```sh:
mkdir web/elm
cd web/elm
elm-package install elm-lang/html
# elm-package install elm-lang/http
# elm-package install simonh1000/elm-jwt
```

次にweb/elm/Main.elmを作成します。

```elm:Main.elm
module Main exposing (..)
 
import Html exposing (Html, text)
 
main : Html msg
main =
  text "こんちわ、Elmさん!"
```

　次にweb/templates/page/index.html.eexを編集して、先頭に以下の行を追加します。

```html
<div id="elm-container"></div>
```

　最後にweb/static/js/app.jsを編集して、末尾に以下の2行を追加します。Elm.Mainは当然 web/static/vendor/Main.jsを参照していますが、前述の通り、特に明示的なimportなどは必要ないようです。

```js
const elmDiv = document.querySelector("#elm-container")
const elmApp = Elm.Main.embed(elmDiv)
```

　編集が終了したので、プロジェクトのトップに戻り、以下のコマンドを打ちプロジェクトを立ち上げます。

```sh:
mix ecto.create
mix phx.server
```

　Phoenix起動時にElmコードがコンパイルされた旨のメッセージが確認できます。

```sh:
[info] Running PhoenixElmTest.Endpoint with Cowboy using http://0.0.0.0:4000
Elm compile: Main.elm, in web/elm, to ../static/vendor/main.js
10:16:47 - info: compiling
10:16:50 - info: compiled 66 files into 2 files, copied 3 in 10.3 sec
```

　ブラウザからアクセスするとElmコードの出力が確認できます。

```
http://www.xxxx.jp:4000/
```

　以下は画面キャプチャーです。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/61915/d8f7de88-a525-a90c-38ef-bda2f84aca35.png)


　これで、Phoenixプロジェクトの中でElmが使えるようになりました。Webアプリの骨格を成すものができた感じで、うれしいです。