🚀
PETAL(Phoenix/Elixir/Tailwindcss/Alpinejs/LiveView) 環境構築 2022/8
- 新プロジェクトを構築した際のメモです。
- おまけでdaisyUIも適用しています
PETALの導入方法
P: Phoenix
Dockerfileの例
FROM elixir:1.13
ENV PHOENIX_VERSION 1.6.11
ENV NPM_VERSION 8.16.0
ENV NODE_VERSION 18.x
# NODE/NPM
RUN curl -fsSL https://deb.nodesource.com/setup_${NODE_VERSION} | bash - \
&& apt install -y nodejs
RUN npm install npm@${NPM_VERSION} -g
# Phoenix
RUN mix local.hex --force && \
mix archive.install --force hex phx_new ${PHOENIX_VERSION} && \
mix local.rebar --force
E: Elixir
Docker環境ままです
T: Tailwindcss
-
公式のままでした
- (記事末尾に差分掲載しています)
- 以前導入したときに比べるとPhoenixのためのカスタム疑似クラスバリアントの定義が増えているようです。
plugin(({addVariant}) => addVariant('phx-no-feedback', ['&.phx-no-feedback', '.phx-no-feedback &']))
等
A: Alpine.js
Alpine.jsはLiveViweと役割が重なるところがありますが、
- ベースとなるのはLiveViewで、クライアント側で完結するような処理にAlpine.jsを使う
- 例えば、レスポンシブ対応のための切り替えなどはAlpine.jsが合いそう
- キー押下(Ctrl+Enterで送信等)の処理はちょっと悩ましいかもしれない
- https://hexdocs.pm/phoenix_live_view/bindings.html#key-events
- サーバーとやりとりするほどのものかどうか
- 一見Alpine.jsの領域だなと思ってもLiveView側でもできるようになってきている
-
x-init
はpush_patch
による画面update時は発火しない、といったことがあるので気を付ける
- LiveViewで扱うリソースとAlpine.jsで扱うリソースとは、扱いを混ぜない方が良い
- LiveViewTestを活かす意味でもJSは控えめにしておきたい(ベースはLiveView)
という感想です。
パッケージインストール
cd assets && npm install alpinejs
設定差分 assets/js/app.js
+import Alpine from "alpinejs"
+Alpine.start()
-let liveSocket = new LiveSocket("/live", Socket, {params: {_csrf_token: csrfToken}})
+let liveSocket = new LiveSocket("/live", Socket, {
+ params: {_csrf_token: csrfToken},
+ dom: {
+ onBeforeElUpdated(from, to) {
+ if (from._x_dataStack) {
+ Alpine.clone(from, to)
+ }
+ }
+ }
+})
確認用HTML templates/page/index.html.heex
<div x-data="{open: false}">
<button @click="open = true">Expand</button>
<span x-show="open">
Content...
</span>
</div>
L: LiveView
LiveViewは、現在のPhenixではデフォルトで採用されています。
おまけ: DaisyUI
DaisyUIはTailwindcssを使用したコンポーネントセットです
パッケージインストール
cd assets && npm install daisyui theme-change
- テーマ変更方法として公式でtheme-changeを使うのをお勧めされています
設定例 assets/tailwind.config.js
module.exports = {
...
plugins: [
...
require("daisyui")
],
daisyui: {
themes: ["garden", "light", "forest", "dark"],
darkTheme: "forest"
}
]
-
themes
: 最初に指定したテーマがデフォルトで適用されます -
darkTheme
: ユーザーがダークモードを使用した際に適用されるデフォルトです- //
themes
からよしなにしてくれるようですが明示した方がわかりやすいと考えています
- //
設定例 assets/js/app.js
import { themeChange } from "theme-change";
themeChange();
確認用HTML例 templates/page/index.html.heex
<select class="select" data-choose-theme>
<option value="">Default</option>
<option value="light">Light</option>
<option value="forest">Forest</option>
<option value="dark">Dark</option>
</select>
(追記)Alpine.jsとあわせて、現在の設定を取れるようにするには下記のような感じです。
<div
x-data="{'theme': ''}"
x-init="$nextTick(() => theme=document.querySelector('html').dataset.theme || 'cupcake')">
<select
class="select select-bordered"
x-model="theme"
data-choose-theme
>
略
</select>
</div>
(追記)↑ もしかするとLiveViewと相性が悪いかもしれません。画面切り替えを行うと動かなくなる事象がありました。
参考させていただいた資料
コード差分
以下は、Tailwindcss導入時のコード差分です。
diff --git a/assets/css/app.css b/assets/css/app.css
--- a/assets/css/app.css
+++ b/assets/css/app.css
@@ -1,5 +1,8 @@
+@import "tailwindcss/base";
+@import "tailwindcss/components";
+@import "tailwindcss/utilities";
+
/* This file is for your main application CSS */
-@import "./phoenix.css";
/* Alerts and form errors used by phx.new */
.alert {
diff --git a/assets/tailwind.config.js b/assets/tailwind.config.js
new file mode 100644
--- /dev/null
+++ b/assets/tailwind.config.js
@@ -0,0 +1,22 @@
+// See the Tailwind configuration guide for advanced usage
+// https://tailwindcss.com/docs/configuration
+
+let plugin = require('tailwindcss/plugin')
+
+module.exports = {
+ content: [
+ './js/**/*.js',
+ '../lib/*_web.ex',
+ '../lib/*_web/**/*.*ex'
+ ],
+ theme: {
+ extend: {},
+ },
+ plugins: [
+ require('@tailwindcss/forms'),
+ plugin(({addVariant}) => addVariant('phx-no-feedback', ['&.phx-no-feedback', '.phx-no-feedback &'])),
+ plugin(({addVariant}) => addVariant('phx-click-loading', ['&.phx-click-loading', '.phx-click-loading &'])),
+ plugin(({addVariant}) => addVariant('phx-submit-loading', ['&.phx-submit-loading', '.phx-submit-loading &'])),
+ plugin(({addVariant}) => addVariant('phx-change-loading', ['&.phx-change-loading', '.phx-change-loading &']))
+ ]
+}
diff --git a/config/config.exs b/config/config.exs
--- a/config/config.exs
+++ b/config/config.exs
@@ -47,6 +47,16 @@ config :logger, :console,
# Use Jason for JSON parsing in Phoenix
config :phoenix, :json_library, Jason
+# Use Tailwindcss
+config :tailwind, version: "3.1.6", default: [
+ args: ~w(
+ --config=tailwind.config.js
+ --input=css/app.css
+ --output=../priv/static/assets/app.css
+ ),
+ cd: Path.expand("../assets", __DIR__)
+]
+
# Import environment specific config. This must remain at the bottom
# of this file so it overrides the configuration defined above.
import_config "#{config_env()}.exs"
diff --git a/config/dev.exs b/config/dev.exs
--- a/config/dev.exs
+++ b/config/dev.exs
@@ -26,7 +26,9 @@ config :tontenkan, TontenkanWeb.Endpoint,
secret_key_base: "SqNDkijN2qE5jf7X0cjdC3rgggxZnq/pyRCaKHsBf0ccJwxH6ZAGHRXizTrgOZsv",
watchers: [
# Start the esbuild watcher by calling Esbuild.install_and_run(:default, args)
- esbuild: {Esbuild, :install_and_run, [:default, ~w(--sourcemap=inline --watch)]}
+ esbuild: {Esbuild, :install_and_run, [:default, ~w(--sourcemap=inline --watch)]},
+ # Tailwindcss
+ tailwind: {Tailwind, :install_and_run, [:default, ~w(--watch)]}
]
# ## SSL Support
diff --git a/lib/tontenkan_web/templates/page/index.html.heex b/lib/tontenkan_web/templates/page/index.html.heex
--- a/lib/tontenkan_web/templates/page/index.html.heex
+++ b/lib/tontenkan_web/templates/page/index.html.heex
@@ -3,6 +3,10 @@
<p>Peace of mind from prototype to production</p>
</section>
+<h1 class="text-3xl font-bold underline">
+ Hello world!
+</h1>
+
<section class="row">
<article class="column">
<h2>Resources</h2>
diff --git a/mix.exs b/mix.exs
--- a/mix.exs
+++ b/mix.exs
@@ -49,6 +49,8 @@ defmodule Tontenkan.MixProject do
{:gettext, "~> 0.18"},
{:jason, "~> 1.2"},
{:plug_cowboy, "~> 2.5"},
+ # assets
+ {:tailwind, "~> 0.1", runtime: Mix.env() == :dev},
# tools
{:mecab, "~> 1.0"},
# for test
@@ -68,7 +70,7 @@ defmodule Tontenkan.MixProject do
"ecto.setup": ["ecto.create", "ecto.migrate", "run priv/repo/seeds.exs"],
"ecto.reset": ["ecto.drop", "ecto.setup"],
test: ["ecto.create --quiet", "ecto.migrate --quiet", "test"],
- "assets.deploy": ["esbuild default --minify", "phx.digest"]
+ "assets.deploy": ["tailwind default --minify", "esbuild default --minify", "phx.digest"]
]
end
end
Discussion