これまで
例えば、elm make src/Main.elm
とするとindex.html
を生成してくれて、これをブラウザで開けば結果が表示されます。
また、elm reactor
とすれば、開発用のサーバーを立ち上げてくれて、そこからElm
のコードの実行が出来ます。
CssフレームワークやJavaScriptライブラリの導入
ただ、やっぱports
やflags
を利用したり、何らかのjs
ライブラリやcss
フレームワークを取り入れたくなってきます。これを実現するには、エントリーポイントとなるindex.html
を用意し、
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<title>Main</title>
<link rel="stylesheet" href="whatever-you-want.css">
<script src="main.js"></script>
</head>
<body>
<div id="elm"></div>
<script>
var app = Elm.Main.init({
node: document.getElementById('elm')
});
</script>
</body>
</html>
コマンドラインからelm make src/Main.elm --output main.js
として、Elm
のソースコードをJavaScript
にトランスパイルします。
そして、このindex.html
をブラウザで直接開いたり、適当なWebサーバーを立ち上げてからブラウザでアクセスします。
しかし、毎回これを手動でやるのも面倒、もし間違えて--output
オプションを忘れるとindex.html
が上書きされてしまうという悲惨な事故に繋がりかねないので、なんらかのバンドラーを使うのが一般的です。
メジャーなのはwebpack
、自分で設定を用意したり、webpack
をベースにしたcreate-elm-appを使ったりしますが、このwebpack
の設定が分かりづらくて大嫌いなのです。未熟な自分は、この設定で一日潰れたりしたことも…
parceljsの導入
そこで登場するのが、最近になってElm
をサポートするようになった、parceljsです。設定不要で高速が謳い文句のバンドラーです。
グローバルにインストールしてみます。
# npm install -g parcel-bundler
適当なディレクトリを作成し、以下の様な構成で、外部js
とcss
の読み込みを考慮し、下記のようにファイルを用意します。
index.html
js/index.js
css/style.css
src/Main.elm
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<title>Main</title>
</head>
<body>
<div id="elm"></div>
<script src="js/index.js"></script>
</body>
</html>
require('../css/style.css');
const { Elm } = require('../src/Main.elm');
var app = Elm.Main.init({
node: document.getElementById('elm')
});
body {
color: white;
background-color: blue;
}
module Main exposing (main)
...
...
これらの用意が出来たら、
# parcel index.html
とすると、開発用のサーバーがポート1234で立ち上がります。もし任意のファイルに変更があれば、検知して自動でコンパイルし直してくれます。
チョー便利ですw
postcssとtailwindcssの導入
自分はcss
が苦手なので、何らかのフレームワークを使うことが多いのですが、最近はtailwindcssにハマっています。いわゆるAtomic Cssと呼ばれる系のライブラリですが、自分にはとても合っているようです。
CDNからデフォルトのcss
ファイルを読み込んでも良いのですが、やはりちょっとはカスタマイズをしたくなってくるので、parceljs
のツールチェインに組み込んでしまうと、とても楽が出来ます。
ただ、parceljs
も流石にこの辺までは設定なしでは面倒を見てくれないので、必要なツール群一式を用意します。
# npm install -D postcss-modules autoprefixer tailwindcss
tailwindcss
のカスタマイズ用のファイルが必要になりますので次のように生成します。
# npx tailwind init js/tailwind-config.js
必要に応じてこのコンフィグファイルに修正を加えます。また、css
ファイルを以下のように変更します。
@tailwind preflight;
@tailwind components;
@tailwind utilities;
/* 生cssが必要ならこの辺に記述か@importする */
body {
color: white;
background-color: blue;
}
そして、postcss
の設定を用意してtailwindcss
を実行し、さらにその結果をautoprefixer
で後処理をします。
module.exports = {
plugins: [
require('tailwindcss')('./js/tailwind-config.js'),
require('autoprefixer')
]
}
これで準備完了、
# parcel index.html
とすると、めでたくtailwindcss
のクラスが反映された環境で開発用サーバーが立ち上がります。Elm
コード内で必要なクラス名を埋め込むと自動的に反映されます。
最後に
正直なところparceljs
がどのように動作するのか全くわかりませんし調べてもいません。
ファイルの変更の検知に失敗したり、それに伴うホットリローディングも失敗する時があります。
また、Elm
のコンパイルでフォーマット的なエラー(カッコを忘れたとか)があった場合に、parcel
を再起動しないとホットリローディングしてくれない時があります。
Elm
コンパイラへの--debug
や--optimize
などのオプションの渡し方が今の所わかりませんw。
リポジトリ用意しましたのでお試しください…
https://github.com/kyasu1/elm-parcel-tailwind
2019/02/11
最新版のparcel
ではElm
でもHMRに対応して更に便利になりました。同時に--debug
オプションが自動的に追加されるようになって、Time Travelling Debuggerが有効になります。
ただし、ここに大きな罠がありまして、--debug
をつけると、謎のMap.!: given key is not an element in the map
なる極悪なエラーが発生してコンパイル自体に失敗するケースがあります。Array
やHtml.Attribute
を含むMsg
があると必ずエラーとなるようです。自分自身のコードで使っていなくても、利用しているパッケージの中で似たようなことをしているとエラーとなって詰んでしまいます…
elm/compiler
の方での根本的な解決が望ましいですが、--debug
オプションを付けなければコンパイルに成功するので、もしこのエラーに遭遇したらelm make
でオプションなしでコンパイルしてください。
だと身も蓋もないですので、parcel
の方に聞いたら、以前のバージョンをインストールすればとりあえず大丈夫でしょ( https://github.com/parcel-bundler/parcel/pull/2626#issuecomment-462212763 )と教えていただきました。
自分のプロジェクトフォルダで
# npm install -D parcel@1.10.3
とすれば無事に解決です。このバージョンではHMRが組み込まれていないので、
# npm install -D parcel-plugin-elm-hot
としてインストールします。
以上で引き続きparcel
で楽ちん開発が続けられます!