先日あるPhoenixアプリをPhoenix 1.6に更新していたときに、SCSSをどのように設定すればよいのか戸惑ったのでメモします。ちなみになぜSCSSが必要だったかというと、BootstrapをSCSSでカスタマイズしていたからです。また、Tailwindは使わない方針なのです。
結論
- 必要な知識はすべてPhoenix 1.6 Asset Management ドキュメントに書いてある。
- 一番シンプルなやり方は、phoenixframework/esbuildでJS、CargoSense/dart_sassでSCSSの分業体制。
- SCSSを使いたいときは、phoenixframework/esbuildとCargoSense/dart_sassとを両方使ったら良い。ただし、闇雲にドキュメントに書いてあるコードをコピーせず、事前にどのような手順でアセットを処理したいのかしっかり考えた上で設定することが大事。
phoenixframework/esbuild
- 新規作成のPhoenix 1.6アプリでは何もしなくても設定済。
- JSをビルドして、まとめてくれる。(生成物:
priv/static/assets/assets/app.js
) - CSSがimportされている場合は、CSSをビルドして、まとめてくれる。(生成物:
priv/static/assets/assets/app.css
) - esbuildの実行プログラムはphoenixframework/esbuildさえ正しく設定されていれば、自動的にインストールされる。
-
SCSSを使いたい場合な、以下のいずれかが必要になるそうです。
- CargoSense/dart_sass
- esbuild plugins(これはphoenixframework/esbuildでは無理っぽい)
- 開発時、 Phoenix.Endpoint watcherを用いることにより、アセットに変更があるたびに自動でビルドされるようにすることができます。
- 本番用にはデプロイの都度
mix assets.deploy
コマンドでコンパイルをすることになると思います。 - たまに古い生成物が悪さをする場合があります。挙動が変だったら
priv/static/assets/
を確認して、不要なファイルを削除してください。
esbuildの設定
3つのファイルに渡って設定されるようです。
-
mix.exs
- elixir関連
-
config/config.exs
- esbuild関連
- 実行時の引数を指定
- 使用したいesbuildの実行プログラムのバージョン
- ビルドしたいファイル
- ビルド生成物を置くディレクトリー
- など
-
config/dev.exs
- Phoenix.Endpoint watcher関連(開発用)
phoenixframework/esbuildの基本的な使い方については思っていたより簡単でした。ただ、初期設定のままだとSCSSが使えないのです。
どうしてもSCSSが使いたいときにはCargoSense/dart_sassが便利です。
CargoSense/dart_sass
- SCSSをphoenixframework/esbuildと同じ要領で設定できる。
-
phoenixframework/esbuild同様、3つのファイルに渡って設定される。
mix.exs
config/config.exs
config/dev.exs
注意点
最初、何も考えずにCargoSense/dart_sassのドキュメントに書いてあるコードをそのままつかっていたのですが、それでは正しくイゴかない場合があることが判明しました。別にドキュメントが悪いわけではなく、自分がどのように自分のアセットを処理したいのかの方針を明確する必要があるのです。
例えば、phoenixframework/esbuildとCargoSense/dart_sassの両方のCSSビルド生成物はの行き先がpriv/static/assets/app.css
となっていると、JSファイルにCSSがimportされている場合に競合して同じファイルを上書きすることになってしまうのです。これに気付くまで時間を燃やすことになります。
最初はいろいろゴニョゴニョしようと試行錯誤してしてましたが、結局phoenixframework/esbuildでJS、CargoSense/dart_sassでSCSSの分業体制がベストだという結論に達しました。一番簡単で確実です。
例えば、以下のような方針が考えられます。
- phoenixframework/esbuildではCSSを一切取り扱わない。
-
CargoSense/dart_sassの成果物のファイルを
app.css
以外の名前にすると、万一phoenixframework/esbuildがCSSを生成しても競合しないので、デバグしやすいかもしれません。
そして、HTMLテンプレートでそのファイルを参照するようにします。
- <link phx-track-static rel="stylesheet" href={Routes.static_path(@conn, "/assets/app.css")}/>
+ <link phx-track-static rel="stylesheet" href={Routes.static_path(@conn, "/assets/from_scss.css")}/>
<script defer phx-track-static type="text/javascript" src={Routes.static_path(@conn, "/assets/app.js")}></script>
例えば、config/config.exs
はこんな感じになりました。
...
# Configure esbuild (the version is required)
config :esbuild,
version: "0.14.1",
default: [
args: [
"js/app.js",
"--bundle",
"--target=es2016",
"--outdir=../priv/static/assets",
"--external:/fonts/*",
"--external:/images/*"
],
cd: Path.expand("../assets", __DIR__),
env: %{"NODE_PATH" => Path.expand("../deps", __DIR__)}
]
# https://github.com/CargoSense/dart_sass
config :dart_sass,
version: "1.44.0",
default: [
args: [
"scss/index.scss",
"../priv/static/assets/from_scss.css" # デバグしやすいよう`app.css`以外の名前にする
],
cd: Path.expand("../assets", __DIR__)
]
...
phoenixdiff.org
古いPhoenixをPhoenix 1.6更新したい場合にはphoenixdiff.orgが便利です。差分が確認できます。