ジンジャー研究室

長めのつぶやき。難しいことは書きません。

Elm を既存の JavaScript と併せて使う N の方法

今月、社外向けに1回、社内向けに1回 Elm の紹介をしたところ、両方とも好評で「ぜひ使ってみたい」という声が多く、良かったと思う一方で、ここは補足すべきだったなーという点があったので書きます。

両者に共通して頻出だったのが、

  • 既存プロジェクトの一部に導入するにはどうすればいいか
  • JavaScript のライブラリは使えるのか

という質問。 Elm の紹介としてはメインの話題じゃないんだけど、まぁ実際に導入しようと思ったら確かにそこ一番気になると思う。

Elm の初期化方法

まず、Elm の仕組みから見ていくと、例えば Main モジュールをエントリポイントとした場合、JavaScript 側で最も簡単に初期化する方法は次の通り。

<script src="/assets/elm.js">
<script>
Elm.Main.fullscreen();
</script>

fullscreen() を使うと、Elm で書いた画面がウインドウいっぱいに表示される。さらに、Elm の main 関数はフラグ(引数)を受け取ることができるので、設定の類を最初に突っ込むと良い。

<script>
Elm.Main.fullscreen({
  apiHost: 'https://hogehogeapi.com'
});
</script>

次に、画面の一部に Elm の画面を埋め込むには、次の例のように embed() を使う。

<div id="target"></div>
<script>
var elemenet = document.getElementById('target');
Elm.Main.embed(elemenet);
</script>

ちなみに、ここまでの例では HTML に直接ロジックを書いているが、最近のフロントエンド開発では Node.js で開発することが多い。Elm が吐き出すコードはそのまま Node.js のモジュールとして読み込める

var Elm = require('./elm.js');

Elm.Main.fullscreen();

さらに、 React コンポーネントとして Elm を利用することもできる。公式サポートではないが数十行のコードでそういう仕組みが作れる。具体的な話は公式記事の How to Use Elm at Work に書かれている。

JavaScript のライブラリを使いたい

Elm から JavaScript を呼ぶ(あるいはその逆)をするために Port という仕組みがある。これを使うと、JavaScript の世界と Elm の世界はお互いにデータを通信し合うことができる。

ここで注意すべき点は、 JavaScript は Elm の下位レイヤーではなく外部サービスになる ということ。Elm の世界から見た JavaScript の世界はサーバーだと思えばいい。これを公式ドキュメントではJavaScript as a Service」と呼んでいる。

例えば、 JavaScript 側にスペルチェックのロジックが実装されていて、 Elm 側からそれを使いたいとする。その場合、Elm 側から「スペルチェックをしてくれ」というリクエストを投げる。すると JavaScript は処理結果を Elm 側に返す。コードにするとこう。

var app = Elm.Spelling.fullscreen();

app.ports.check.subscribe(function(word) {// Elm 側からデータを受け取る
   var suggestions = spellCheck(word);
   app.ports.suggestions.send(suggestions);// Elm 側に結果を返す
});

制約としては、Elm 側のコードは非同期処理の書き方になる。この辺りは無理してハックするよりも、そういうものだと受け入れてそれ前提で設計を組むのが良いと思う。クラウドの画像処理エンジンを利用するのと同じ。テキストエディタとか(まだ Elm のライブラリがない)も無理せずに JavaScript のライブラリを使って Port でやりとりする。

Elm の世界と JavaScript の世界は隔離されていて、 Port 以外の方法でやりとりすることはできない。言い換えると、Elm が JavaScript のライブラリを「ラップ」することは出来ない。もし、ラップが可能であるとすると Elm の特徴である「実行時例外が発生しない」という保証を守ることができない。ユーザーからしたら見た目 Elm の関数だから、実は中で JavaScript がモリモリ使われていてクラッシュするという話だと疑心暗鬼になってしまう。だからそれは出来ないようになっている。(Elm の外側で起きたらそれは知らない、500エラーのようなもの)

同様に、Elm のエコシステム(外部ライブラリ)も JavaScript ライブラリをラップしているものは一切なく、全て Elm で書かれている。JavaScript をラップしたライブラリを公開することはシステムに禁止されている。だからインストールして使ってみたらクラッシュするという心配はない。

CSS はどうするの?

Elm 固有の特別な仕組みはない。普通に class をつけて 外部の CSS ファイルでスタイリングすれば良いと思う。

他の方法として、このブログでは一度 CSS in Elm (CSS in JS の Elm 版、要はインラインスタイル)という方法を紹介していてモジュール化の観点からは良いのだが、開発ツールとか色々考えていくと総合的なバランスは悪いので、一般的用途にはあまりおすすめできない。elm-css という有名なライブラリもあるのだが個人的にはちょっとやり過ぎ感を感じていて保留中。あとは CSS Modules の Elm 版を作る動きもあったが、今どうなってるか知らない。

とまあ、高度なことをしようとすると色々事情はあるものの、普通の CSS を普通に書くぶんには何も困らない。

失敗しない Elm の導入方法

良いツールがあったとしても、上手くいくかどうかは最終的にチームワークとか組織論とかに行き着いてしまう。社内向けには「ハイリスク・ハイリターン」と表現した。JavaScript に比べたら全然情報がないので、スタート地点でリスク高いのは否定できない事実で、そこからどう工夫してリスクを下げていくかが戦略になる。

その辺の話も公式記事の How to Use Elm at Work に書かれている。この記事にかかれているのは、 Elm を導入して成功した事例の共通点をまとめたものだ。短い記事だから興味のある人は全部読んでほしいのだが、まとめるとこう。

  • 小さい部分から実験しながら徐々に導入する
  • チームに必ず一人めっちゃ詳しい人がいる状態にする
  • 最初のプロジェクトは一番メリットの出る場所を戦略的に選ぶ
  • 議論も良いがとにかく Elm のコードを実際に書いてみる

本文にも書いてある通り 「リスクを最小化する」 のがポイント(というか、これ全然 Elm に限った話じゃないと思う)。

まとめ

なんやかんや言って、コードを見るのが一番イメージ湧きませんか?なので連携部分をコードで紹介しました。参考になれば幸いです。

追伸: Elm 本は 0.19 が出たタイミング(時期未定)で校正入れるので、もう少しお待ち下さい。