There is a fix for this issue: Tailwindcss/forms and other plugin compatibility issue (DaisyUI) · Issue #134 · tailwindlabs/tailwindcss-forms · GitHub
Hio!! We just deployed an app to production that uses Phoenix, Tailwind, and DaisyUI!
We opted not to use Phoenix’s built-in assets manifest and phx.digest
and all that. Instead, our CI system (GitHub Actions) has a job that takes our Elixir image and builds the assets and uploads them to S3 under a commit SHA path.
Then we configure local dev endpoint to use :static_url
with [host: "localhost"]
, but prod with something like [host: "your.cdn.com", path: "$build_sha/"]
.
I should write a Medium post about this and become famous.
Anything that makes the tooling around web-projects more complicated is always welcome, so I can guarantee success here!
That’s exactly what this setting is there for
LMAO!
I know! But I guess I was trying to get at not using mix phx.digest
. And I love that Phoenix makes it easy for you to do this, if you so choose!
We use containers to deploy our app, so we (i.e. me) are very uptight about small image sizes. I don’t really want tailwind
, esbuild
, npm/yarn
(much less node_modules
) installed on our deployed image. That’s why we go through this whole rigmarole.
So our CI builds the Elixir app image. Then we have a CI sub-job that uses that image to build and upload static assets to CDN under a $BUILD_SHA path.
Anyway way, long story short… the people behind Phoenix are just amazing at striking a balance between ease of use and flexibility.
The default docker image phoenix creates uses a multi stage build, so all that stuff can be done done in the build image and is not included in the runner image.
you should, and I will help become famous so you can share the million, LoL
@LostKobrakai would like to learn more on this.
Just a heads up that the :tailwind
library comes with a precompiled binary of Tailwind that does not include third-party libraries like DaisyUI
. I’m not sure whether or when this changed, but to use DaisyUI, you now have to install Tailwind using npm
instead. This is what worked for me:
- Remove the
:tailwind
library and its configuration fromconfig.exs
anddev.exs
(the line inwatchers:
) - Install tailwindcss and DaisyUI using
npm
withcd assets && npm install -D tailwindcss daisyui
. - Add a
deploy
script in yourpackage.json
. Mypackage.json
looks like this:
{
"scripts": {
"deploy": "NODE_ENV=production npx tailwindcss --minify --input=css/app.css --output=../priv/static/assets/app.css"
},
"devDependencies": {
"tailwindcss": "^3.3.3",
"@tailwindcss/forms": "^0.5.4",
"@tailwindcss/typography": "^0.5.9",
"daisyui": "^3.2.1"
}
- In your
mix.exs
update thealiases
like this:
[
setup: ["deps.get", "ecto.setup", "assets.setup", "assets.build"],
"assets.setup": ["esbuild.install --if-missing"],
"assets.build": ["esbuild default", "cmd --cd assets npm run deploy"],
"assets.deploy": ["esbuild default --minify", "cmd --cd assets npm run deploy", "phx.digest"]
]
Make sure that the cmd --cd assets npm run deploy
comes after the esbuild default
step, because (that’s my understanding but I’ve got no clue about any of this frankly) esbuild will install your npm packages (at least locally). So, you need to run esbuild default
to install the npm packages first.
Now, if you run your server with mix phx.server
, it should work. At least it works for me locally and after deleting my _build
and node_modules
folder.
Deploying to Fly.io
Now, the next hurdle is to deploy all this do Fly (if you use them). You have to modify your Dockerfile
a bit to make it work (again, I have no clue about how any of this works, but this worked for me. Suggestions and explanations are much appreciated though)
ARG ELIXIR_VERSION=1.14.4
ARG OTP_VERSION=25.3.2
ARG DEBIAN_VERSION=bullseye-20230227-slim
ARG BUILDER_IMAGE="hexpm/elixir:${ELIXIR_VERSION}-erlang-${OTP_VERSION}-debian-${DEBIAN_VERSION}"
ARG RUNNER_IMAGE="debian:${DEBIAN_VERSION}"
FROM ${BUILDER_IMAGE} as builder
# ADD curl HERE AFTER install -y
RUN apt-get update -y && apt-get install -y curl build-essential git \
&& apt-get clean && rm -f /var/lib/apt/lists/*_*
# Install something so that you can apt-get install nodejs below
# Make sure to select the version of node you want to install.
# This one will install node v20.something
RUN curl -sL https://deb.nodesource.com/setup_20.x | bash
# Install node and npm
RUN apt-get install -y nodejs
# A BUNCH OF OTHER STUFF
COPY assets assets
# Install TailwindCSS and DaisyUI
# I've got no clue why esbuild doesn't do this for us but here we are
RUN npm install --prefix assets
# compile assets
RUN mix assets.deploy
# MORE OTHER STUFF
I hope this helps! If you know how to install the packages without npm/node
and only using esbuild
I’d love to know!
Just a quick addendum, while the :tailwind
library doesn’t include DaisyUI
(or some other plugins), you can still use it by simply installing and including the plugins in your tailwind.config.js
and keep the build process a little simpler that way.
The easiest way I’ve found is just adding daisyui as an npm dependency:
"dependencies": {
"daisyui": "^3.2.1"
}
and extending the existing(?) tailwind.conig.js
file plugin section with require("daisyui")
That way, we don’t need an extra deploy script and can stay closer to the phoenix defaults.
You are overcomplicating things. I just tested this with a fresh Phoenix 1.7.7 project:
Setup DaisyUI
-
Create project:
mix phx.new your_project
-
Initialize an npm project in the directory
assets/
:cd assets && npm init -y
-
Add npm dependency
daisyui
in the directoryassets/
:cd assets && npm i -D daisyui@latest
-
Add daisyUI to Tailwind plugins list (in
assets/tailwind.config.js
):require("daisyUI")
plugins: [
+ require('daisyui'),
require("@tailwindcss/forms"),
- DaisyUI is now installed! Let’s try an example component:
lib/your_project_web/controllers/page_html/home.html.heex
<h1 class="text-brand mt-10 flex items-center text-sm font-semibold leading-6">
Phoenix Framework
<small class="bg-brand/5 text-[0.8125rem] ml-3 rounded-full px-2 font-medium leading-6">
v<%= Application.spec(:phoenix, :vsn) %>
</small>
</h1>
+ <div class="btn btn-primary">
+ Hello daisyUI!
+ </div>
<p class="text-[2rem] mt-4 font-semibold leading-10 tracking-tighter text-zinc-900">
Peace of mind from prototype to production.
</p>
It worked (for me, at least )!
At this point, daisyUI is installed and everything should be working as expected.
Now for the deployment:
Deploy to Fly.io
-
Create Fly.io app:
- ‘flyctl launch’
-
Fix issues with the default Dockerfile generated when we ran
fly launch
:- Use
apt-get
to installnodejs
andnpm
- Install our project’s
npm
dependencies
- Use
FROM ${BUILDER_IMAGE} as builder
# install build dependencies
-RUN apt-get update -y && apt-get install -y build-essential git \
+RUN apt-get update -y && apt-get install -y build-essential git nodejs npm \
&& apt-get clean && rm -f /var/lib/apt/lists/*_*
# ...
COPY priv priv
COPY lib lib
COPY assets assets
+# install npm dependencies
+RUN cd assets && npm install
+
# compile assets
RUN mix assets.deploy
Bonus: Prevent daisyUI from spamming the console when tailwind.config.js
is modified
By default, daisyUI will print a message like this to the console whenever tailwind.config.js
is modified:
🌼 daisyUI 3.5.0 https://daisyui.com
╰╮
╰─ ✔︎ [ 2 ] themes are enabled. You can add more themes or make your own theme:
https://daisyui.com/docs/themes
❤︎ Support daisyUI: https://opencollective.com/daisyui
That’s annoying. Let’s disable that:
assets/tailwind.config.js
module.exports = {
content: ["./js/**/*.js", "../lib/*_web.ex", "../lib/*_web/**/*.*ex"],
+ daisyui: {
+ logs: false,
+ },
plugins: [
Bonus: Remove tailwind/forms
to avoid conflicts with daisyUI form components
The Tailwind forms package will cause conflicts with daisyUI forms. Let’s get rid of it:
assets/tailwind.config.js
plugins: [
require("daisyui"),
- require("@tailwindcss/forms"),
require("@tailwindcss/typography"),
Thanks for the suggestion. That’s what I had at first but I always got the error “Cannot find “taildwindcss/plugin”. When I removed the DaisyUI plugin from my tailwind.config.js, everything worked fine. But when I added it, it broke. That’s why I went down the npm route.
Interesting. Maybe some configuration changed during an upgrade or something?
This is why I like to compare against a fresh project. It helps me to isolate the potential cause of any such strangeness.
Worked like a charm, yay, thanks a lot!
@PJUllrich - I guess npm install daisyui
is the missing step - either in development or in production - wherever the error happens.
The above steps are still working for me. For fly deployment the above @arcanemachine steps are sufficient.