How to get DaisyUI and Phoenix to work?

There is a fix for this issue: Tailwindcss/forms and other plugin compatibility issue (DaisyUI) · Issue #134 · tailwindlabs/tailwindcss-forms · GitHub

1 Like

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.

2 Likes

Anything that makes the tooling around web-projects more complicated is always welcome, so I can guarantee success here! :grin:

1 Like

That’s exactly what this setting is there for :smiley:

1 Like

LMAO! :joy:

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.

3 Likes

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:

  1. Remove the :tailwind library and its configuration from config.exs and dev.exs (the line in watchers:)
  2. Install tailwindcss and DaisyUI using npm with cd assets && npm install -D tailwindcss daisyui.
  3. Add a deploy script in your package.json. My package.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"
  }
  1. In your mix.exs update the aliases 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!

4 Likes

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.

2 Likes

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 directory assets/:

    • 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 :grin:)!

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 install nodejs and npm
    • Install our project’s npm dependencies
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"),
9 Likes

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.

1 Like

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.

1 Like

Worked like a charm, yay, thanks a lot!

1 Like

@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.

1 Like