Railsで愉快な言語Elmを使う

Rails 5.1 でwebpackerが同梱されるようになりました。

この機会に新しいJSフレームワークに挑戦したいが、React・Vue・Angularのどれに挑戦するか迷っている、という人は多いでしょう。

しかーし！実はWebpackerには、**もう一つのJSフレームワーク**があるのです！

# Elm って何だっけ？

詳しくは、[公式ページ](http://elm-lang.org/) や [薄い本](https://giisyu.gitbooks.io/elm_usui_book/content/) などをご覧ください。

大雑把には、こんな特徴がある言語です。

1. ElmはWEBページを、Haskellベースの言語で実装できる（ReactやVueのようなライブラリではない）
2. Elmは予めブラウザが読める形式にコンパイルする（CoffeeScriptやTypeScriptのように）
3. ElmはJavaScriptだけでなくHTMLやCSSも直接操作できる
4. Elmはモジュールなどの機能も含んでいる

ReactのJSXやES6が現実的にWEBを進歩させているのに対し、Elmは未来を行っていると言えるかもしれません。

# Elm をインストールする

実はWebpackerがこっそりサポートしており特に難しいことはありません。ReactやVueと同じです。https://github.com/rails/webpacker#elm

アプリ作成時に `--webpack=elm`  をつけるだけです[^1]

[^1]: なぜか `rails new --help`の説明文には`--webpack` に `elm` を渡せるという説明がありません。Elmはまだ実験的サポートだということでしょうか。

```
$ rails new myapp --webpack=elm
```

railsとwebpackのサーバーを起動します。
```
$ bin/rails server
$ bin/webpack-dev-server # 別コンソールなどで開く
```

ただし、初期状態ではWebpack側のJSをRails側が読み込んでいない（そもそもページが一つも無い）ので、適当なページを作り、Viewに`javascript_pack_tag` を仕込みます。

```
# app/views/examples/show.html.erb
<h1>Example</h1>
<%= javascript_pack_tag "hello_elm" %>
```

```
# config/routes.rb
Rails.application.routes.draw do
  resource 'example', only: [:show]
end
```

```
# app/controllers/examples_controller.rb
class ExamplesController < ApplicationController
  def show
  end
end
```

http://localhost:3000/example にアクセスすると、面白みのないサンプル画面が表示できます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/179154/13439ddb-1e96-0b5d-d031-5c3d6f7f95d9.png)

ただし、右下に黒い操作履歴ウィジェットが表示されるのが、Elmの他と違うところです（後述）。


# Elmの他のサンプルを使ってみる

Elm公式ページにある、多少複雑なSPAのサンプル動かしてみましょう。

Elmのソースは単にコピーするだけです。

```
$ git clone git@github.com:rtfeldman/elm-spa-example.git
$ cp -R elm-spa-example/src/* myapp/app/javascript/packs/
$ cp elm-spa-example/elm-package.json myapp/
```

elm-package.json のパスは、Webpackのものに書き換えます。

```diff
    "source-directories": [
-        "src"
+        "app/javascript/packs/"
    ],
```

また、elm-spa-exampleは外部のCSSも読み込んでいたので、`application.html.erb` にCSSを追加します。

```erb
<!DOCTYPE html>
<html>
  <head>
    <title>Myapp</title>
    <%= csrf_meta_tags %>
    <%= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track': 'reload' %>
    <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>

    <!-- Import Ionicon icons & Google Fonts our Bootstrap theme relies on -->
    <link href="//code.ionicframework.com/ionicons/2.0.1/css/ionicons.min.css" rel="stylesheet" type="text/css">
    <link href="//fonts.googleapis.com/css?family=Titillium+Web:700|Source+Serif+Pro:400,700|Merriweather+Sans:400,700|Source+Sans+Pro:400,300,600,700,300italic,400italic,600italic,700italic" rel="stylesheet" type="text/css">
    <!-- Import the custom Bootstrap 4 theme from our hosted CDN -->
    <link rel="stylesheet" href="//demo.productionready.io/main.css">
    <style>/* Loading spinner courtesy of loader.io */
    .sk-three-bounce { margin-right: 10px; } .sk-three-bounce .sk-child { width: 14px; height: 14px; background-color: #333; border-radius: 100%; display: inline-block; -webkit-animation: sk-three-bounce 1.4s ease-in-out 0s infinite both; animation: sk-three-bounce 1.4s ease-in-out 0s infinite both; } .sk-three-bounce .sk-bounce1 { -webkit-animation-delay: 0.28s; animation-delay: 0.28s; } .sk-three-bounce .sk-bounce2 { -webkit-animation-delay: 0.44s; animation-delay: 0.44s; } .sk-three-bounce .sk-bounce3 { -webkit-animation-delay: 0.6s; animation-delay: 0.6s; } @-webkit-keyframes sk-three-bounce { 0%, 80%, 100% { -webkit-transform: scale(0); transform: scale(0); } 40% { -webkit-transform: scale(1); transform: scale(1); } } @keyframes sk-three-bounce { 0%, 80%, 100% { -webkit-transform: scale(0); transform: scale(0); } 40% { -webkit-transform: scale(1); transform: scale(1); } }
    </style>
  </head>

  <body>
    <%= yield %>
  </body>
</html>
```

ジャジャーン！ Railsアプリの中で、Elmアプリが動くようになりました！

![image.png](https://qiita-image-store.s3.amazonaws.com/0/179154/9089fcbc-e0fd-1cdf-616e-5cfac1d93d25.png)

また、右下の黒いウィジェットをクリックしてみましょう。

Elmは言語機能によって、状態をロジックと完全に分離しているので、**アプリ側は何もしなくても** 現在の内部状態を閲覧したりできます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/179154/592a84b9-d59c-86bb-5ecc-626558e48e6a.png)

# ハマりところ・残念だったところ

Elm は最新バージョンが v0.18 であり、まだ v1.0 が出ていません。そのため、言語仕様がしばしば変更されます。サンプルが動かない時は、elm-package.json のバージョンを調べてみてください。

また、webpacker では Native module （ElmのモジュールをJSで書ける機能）が、まだうまく動かないようなのが残念でした。

# 全体的な感想

ElmはFRPなど、先進的な機能が満載なので、大変勉強になるのですが、反面「実験的」「オモチャ」「実務では使えない」という印象が強いのが難点でした。

Railsアプリに埋め込めるということになれば、

- インタラクティブ性が必要な部分はElmで書く
- Elmで書きにくい部分はRailsに逃げる

と、使い分けられるようになったので、そろそろ実務で使い出してもいいんじゃないかな？と思いました。