にむかひて

PETAL構築 2022/08

2022年8月 トップ > ひとこと > 調査したことの記録
#Phoenix #Elixir #Tailwindcss #Alpine.js #LiveView

  • 新プロジェクトを構築した際のメモ
  • おまけで、daisyUI, sass, sw.js を追加
  • 補足: petal (components?) なるデザインセットとは関係なし

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

// ElixirはDocker環境まま

T: Tailwindcss

A: Alpine.js

パッケージインストール

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) {
+        window.Alpine.clone(from, to)
+      }
+    }
+  }
+})

テストコード 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ではデフォルトで採用されている

  • LiveViewで扱うリソースとAlpine.jsと扱うリソースは、扱いを混ぜない方が良さそう
  • ベースとなるLiveView+クライアント側で完結するような処理にAlpine.jsを使う
    • 例えば、CSSテーマの切り替えなどはAlpine.js

おまけ: 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: ユーザーがダークモードを使用した際に適用されるデフォルト
    • // 明示した方がわかりやすいと考えている

設定例 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>

参考させていただいた資料

コード差分

以下は、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

サイト内検索