elm-css で PostCSS も使える CSS in Elm

(筆者は今では積極的にはこの手法を使っていません。詳しくは[追記](#追記)をご覧ください。)

[`elm-css`](https://github.com/rtfeldman/elm-css/)ライブラリのCSS生成機能と[`elm-css-webpack-loader`](https://github.com/tcoopman/elm-css-webpack-loader)を用いることで、CSS in Elm のさまざまな恩恵にあずかれます。

## はじめに
### なぜ CSS in Elm が必要か

CSS in JS という言葉が、[React界隈で使われ](https://speakerdeck.com/vjeux/react-css-in-js)るようになっていくらか経ちました。
CSS in JS は、本来 CSS で記述するスタイルを JavaScript  で書いてしまうことで、名前空間やネスト構造が使えない不便なCSSから解放されることを目的にしています。

Elm で CSS in JS (Elm) を採用することで、従来のCSSによるスタイルにおける以下の問題を解決できます。

a. スタイルの記述が Elm コンポーネントとは別のファイルになって、配布しづらい
b. CSS に名前空間がないので、Elm コンポーネントを作っても、そのコンポーネントにのみ局所的にスタイルを当てるのが困難
c. その他 CSS は言語としてイケてない

これらの問題を解決しようとする他の方法に、[Elm UI](https://github.com/gdotdesign/elm-ui)があります。
Elm UI は、`elm-make`に変わる独自のコマンドを採用することで a の問題を、Sass を採用することで b, c の問題を解決する方針をとっていますが、独自のコマンドを使わなければならず、"Elm UI way" に完全に染まる必要があります。

### CSS in Elm に関する既存手法との比較

Elm で CSS in JS (Elm) を試みた日本語の記事としては、インラインスタイルを Elm コードで管理する[@jinjor さんの記事](http://jinjor-labo.hatenablog.com/entry/2016/05/30/165816)などがありますが、今回紹介する手法は

* `elm-css` ライブラリを利用する
* Elm で記述したスタイルを、コンパイル時にCSSファイルとして書き出す

点において異なり、以下のメリットを得られます。

A. 型安全なスタイル記述
B. オレオレスタイルではない、一般に認知された記述形式
C. `::after`, `:hover` などの擬似要素を使える
D. メディアクエリも普通に使える
E. ページ読み込み時に、並行してCSSを読み込める
F. ランタイム速度が向上する (インラインスタイルを当てるためのDOM操作が不要なため)
G. auto-prefixer, flexbugs-fix など、PostCSS の資産をそのまま使える

一方で、@jinjorさんの手法と比較した場合に、以下のデメリットがあります。

* `elm-css` の記述方法を学習するコスト
* `elm-css` がメンテナンスされなくなるリスク
* 動的な値を使うことができない

他にも差異があるかもしれませんが、ご自身の用途に応じて最適な手法をお選びください。

### 余談: CSS in Elm に関わる歴史

実は、React 界隈で CSS in JS という言葉が出てくるよりも前から、Elm は [CSS in Elm 的な考え](http://postd.cc/css-is-unnecessary/)を持っていました[^1]。

その後、`elm-html`ライブラリの出現によって、「CSSを直接書くことができない」という、とがった方針はいったん転換されるのですが、`elm-css` の背景にある思想は、この記事にあるものに似ているのではないかと推測しています。

## elm-css + elm-css-webpack-loader による解決方法

基本的な `elm-css` の使い方は、[githubのREADME](https://github.com/rtfeldman/elm-css)を見れば、とくに困らないと思うので、詳しくはここでは述べません。
`elm-css`の使い方には、大きく2つの方法があります。

1. インラインスタイル
2. CSSファイルを事前に生成する

1を採用すると、前述の@jinjorさんの記事とほぼ同じことが可能になります。
以下のメリットだけで良い場合は、こちらを選ぶと良いでしょう。

> A. 型安全なスタイル記述
> B. オレオレスタイルではない、一般に認知された記述形式

2を採用することで、メリットC,D,E,F が得られます。
しかし、`elm-css`のみをつかっていては、

> G. auto-prefixer, flexbugs-fix など、PostCSS の資産をそのまま使える

を享受することができません。
これを可能にするのが、[`elm-css-webpack-loader`](https://github.com/tcoopman/elm-css-webpack-loader)です。
[elm-css の issue](https://github.com/rtfeldman/elm-css/issues/74)から生まれました。
この webpack-loader によって、`elm-css` で記述したスタイルを CSS に変換、webpackによってPostCSSなどの処理を加えることができます。

ただ、`elm-css-webpack-loader` の `/example` コードが最新の Elm 0.18 に対応していなかったり、改善の余地があったため、より良いサンプルを用意しました。

## elm-chat-scenario のサンプルを動かす

今回作成したサンプルは、[github のレポジトリ](https://github.com/arowM/elm-chat-scenario)に置いてあります。
このレポジトリは、Conversational User Interface (チャットボットなどの根底にある思想) を型安全に実現するために作ったものです。
CSS in Elm によって作成された[デモ](https://arowm.github.io/elm-chat-scenario/chat-ui/) をご覧ください。
まだUIが荒削りですが、CSSを使わずにスタイルを記述し、flexbugs-fix や auto-prefixer を使っています。

このライブラリの構成は以下のとおりです。

```bash
src
├── Scenario
│   ├── ChatUI
│   │   └── Css.elm
│   └── ChatUI.elm
└── Scenario.elm
```

`Scenario.elm` に、UIとは独立したコアとなる機能を、`Scenario/`以下に、ライブラリ利用者がすぐに使える便利なUIを配置する構成です。
今回のメインテーマである Elm in CSS は、[`Scenario/ChatUI/Css.elm`](https://github.com/arowM/elm-chat-scenario/blob/master/src/Scenario/ChatUI/Css.elm)に記述されています。

次に、デモとしてお見せしたサンプルアプリのソース構成です。

```bash
sample/chat-ui/src
├── elm
│   ├── HomepageView.elm
│   └── Stylesheets.elm
├── index.js
└── index.pug
```

`HomepageView.elm`は、Elm Architecture にしたがって、`Scenario.ChatUI`のUIを組み込んでいるだけです。
`Stylesheets.elm`が、`Scenario.ChatUI.Css`を読み込み、`npm run build`でコンパイルした際に、CSSファイルを書き出します。
`sample/chat-ui/webpack.config.js` に webpack の設定ファイルが置いてあるので、ご参照ください。
[elm-webpack-starter](https://github.com/moarwick/elm-webpack-starter)を参考に、`npm start` でホットリロードしながら開発できるようにもしています。

## まとめ

以上、`elm-css`のCSSファイル書き出し機能と`elm-css-webpack-loader`の合わせ技で、PostCSSなどの便利な機能を使えるようにしつつ、スタイルをElmコードと一緒に配布する方法について、他の手法と比較しながら簡単にご紹介しました。
正直なところ、`elm-css`を使ったCSS記述は、Sassで書くのに比べてめんどうです。
ただ、それでも、一般に認知された共通のルールでスコープ付きのスタイルを記述し、Elm プログラムとともに配布できるのはメリットが大きいと思います。

## 追記

この手法も結構メリットがあるんですが、elmの文法で型安全にCSSを書くために独自の記法に従わないといけません。
elm-css の主張としては「CSSを型安全に書ける」ということなのですが、正直CSSに型安全なんていらないというのが現在の僕の考えです。
だって、プログラムだったら100年に1度しか実行されないようなコードにバグを残す可能性があるので型安全にしてコンパイル時にtypoなどを検知することに大きなメリットがありますが、CSSですよ？ typoとかしてもブラウザ上でチェックして普通はすぐ分かるじゃないですか。
たったそれだけのために毎度packageを検索して「あれ〜 `background-color` のプロパティはどうやって指定するんだっけな？」って探すのは工数に見合わないと思うんです。

ということで、現在は単純に Sass (SCSS) で別ファイルにスタイルを記述する方法と、[elm-css-modules-loader](https://github.com/cultureamp/elm-css-modules-loader/) を併用しています。
`elm-css-modules-loader` はちょっとイケてない設計をしていたり、githubのissueがまともに機能していなかったりするので、いつか `yet-another-elm-css-modules-loader` を作ろうと思いつつ無情にも時間が過ぎています。

## 追記2

さらに最新の方法を記事にしました。
[「ElmにクリーンでハックのないCSS modulesを」](https://qiita.com/arowM/items/2d5ff8f773e8b53c5f79)
[「Elmでもっと気軽にCSS modules」](https://qiita.com/arowM/items/ba08d0a705eef2626b69)


[![Df-s7diV4AA_7bj.jpg:large.jpeg](https://qiita-image-store.s3.amazonaws.com/0/16345/14d7a867-f808-744f-85d0-3bb32db40c84.jpeg)](https://twitter.com/hashtag/%E3%81%95%E3%81%8F%E3%82%89%E3%81%A1%E3%82%83%E3%82%93%E6%97%A5%E8%A8%98?src=hash)
[さくらちゃんにご飯をあげる](https://www.amazon.co.jp/gp/registry/wishlist/20ZV2VC57615B/ref=nav_wishlist_lists_1)
[^1]: vjeux 氏のスライドよりも前にこの発表をしている