JavaScript
Elm
webpack
parcel

Parcel でまとめる Elm と css と js のススメ

これまで

例えば、elm make src/Main.elmとするとindex.htmlを生成してくれて、これをブラウザで開けば結果が表示されます。

また、elm reactorとすれば、開発用のサーバーを立ち上げてくれて、そこからElmのコードの実行が出来ます。

CssフレームワークやJavaScriptライブラリの導入

ただ、やっぱportsflagsを利用したり、何らかのjsライブラリやcssフレームワークを取り入れたくなってきます。これを実現するには、エントリーポイントとなるindex.htmlを用意し、

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

適当なディレクトリを作成し、以下の様な構成で、外部jscssの読み込みを考慮し、下記のようにファイルを用意します。

index.html
js/index.js
css/style.css
src/Main.elm
index.html
<!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>
js/index.js
require('../css/style.css');
const { Elm } = require('../src/Main.elm');

var app = Elm.Main.init({
  node: document.getElementById('elm')
});
css/style.css
body {
  color: white;
  background-color: blue;
}
src/Main.elm
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ファイルを以下のように変更します。

css/style.css
@tailwind preflight;
@tailwind components;
@tailwind utilities;

/* 生cssが必要ならこの辺に記述か@importする */
body {
  color: white;
  background-color: blue;
}

そして、postcssの設定を用意してtailwindcssを実行し、さらにその結果をautoprefixerで後処理をします。

postcss.config.js
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