How to get DaisyUI and Phoenix to work?

Thank you @benwilson512 .

Here’s a summary of my situation:

  1. I’m trying to use DaisyUI in a Phoenix 1.6 app.
  2. I need to add DaisyUI as a required Tailwind plugin in the tailwind.config.js file
  3. As per, GitHub - phoenixframework/tailwind: An installer for tailwind, the Elixir installer for tailwind does not cater for external plugins:

Note : The stand-alone Tailwind client bundles first-class tailwind packages within the precompiled executable. For third-party Tailwind plugin support, the node package must be used.

PS: I suggest this should be stated clearly at the top of the README rather than as a bottom comment. I already submitted a PR for this.

  1. I’m trying to build my assets in production, not at compile time.
  2. The recommended tailwind nodejs installation instructions help with a local workaround. Trying to deploy the app (to Fly.io in my case) with its nodejs installations is another hurdle (think Docker). The guides I found focus on assets bundled using esbuild.

Eventually, I had to choose between following this workaround, using a CDN or precompiling my assets and excluding the output folder from gitignore.

(There was also the side issue of my site not looking the same in production when I followed this workaround.)

So,

  1. I wish to understand why the Tailwind Hex package does not allow external plugins, especially DasiyUI seeing how widespread it is. I’d want to know if this is permanent or it will be resolved in future versions (and how I can contribute)
  2. It would be great if more information was available on integrating DaisyUI with Phoenix
1 Like

I think you need esbuild as well as the Tailwind library.

1 Like

This didn’t work when I tried it.

My require("daisyui") code was flagged.

But since you have used this successfully, is there an open/barebones sample app you can point me to?

You can generate a Tailwind boilerplate here:
https://fullstackphoenix.com/boilerplates/new

I havent implemented the Tailwind cli (yet) but its basically just to follow these steps:

1 Like

Finding the article you referred to gave me the missing piece.

Here are the relevant steps. I assume you have a Phoenix app setup and npm installed on you device.

  1. Install and setup the Elixir Tailwind library. The README of the library is a great resource.
  2. Publish your app to fly using flyctl. This post is a great guide. Just note that the fly commands in the post might need to be replaced with flyctl commands.
  3. On your local machine, cd into your project’s assets folder and run npm init.
  4. From within your assets folder, follow the DaisyUI installation steps.
  5. Update the Dockerfile generated during the early fly.io deployment. Perform the following
    a. Ensure the COPY lib lib command comes before the RUN mix assets.deploy commnd
    b. Include this command RUN npm --prefix ./assets ci --progress=false --no-audit --loglevel=error in the Dockerfile. This should also come before the RUN mix assets.deploy command

Expectedly, you should be good to go and your app should properly deploy to fly.io :clinking_glasses:

15 Likes

Thanks - running npm init (at least locally) is the step I missed - now it works well. I am still getting the point where I want to try Fly.io - glad you’ve written these steps!

2 Likes

Thanks for the information. I have got tailwind and daisyui running on localhost and deploy on fly.io.

I am trying to add a tailwind custom.css. How do I go about it. I’d be grateful if you could offer some tips.

Hey.

This should help.

Have you checked it out?

@kingdomcoder
Thank you for your steps above. I am following them, but I am getting an error on fly deploy. Do you have any advice regarding the following?

=> ERROR [builder  3/18] RUN npm --prefix ./assets ci --progress=false --no-audit --loglevel=error                                      0.3s
------
 > [builder  3/18] RUN npm --prefix ./assets ci --progress=false --no-audit --loglevel=error:
#12 0.263 /bin/sh: 1: npm: not found
------
Error failed to fetch an image or build from source: error building: executor failed running [/bin/sh -c npm --prefix ./assets ci --progress=false --no-audit --loglevel=error]: exit code: 127

Hello @henning

From the error npm: not found, I suspect that it’s either you don’t have npm installed in your docker environment or docker doesn’t know the path to where it’s located

Check your Dockerfile. Is there any command like RUN apt-get install -y nodejs or RUN apt-get install -y npm?

If there isn’t, add RUN apt-get install -y nodejs before the RUN npm command that gave this error

@kingdomcoder
Thanks for your feedback. I tried your suggestion and am not successful yet.

My current error looks like:

#14 0.608 npm ERR! The `npm ci` command can only install with an existing package-lock.json or
#14 0.609 npm ERR! npm-shrinkwrap.json with lockfileVersion >= 1. Run an install with npm@5 or
#14 0.609 npm ERR! later to generate a package-lock.json file, then try again.
#14 0.616 
#14 0.616 npm ERR! A complete log of this run can be found in:
#14 0.616 npm ERR!     /root/.npm/_logs/2022-06-16T15_11_58_766Z-debug.log
------
Error failed to fetch an image or build from source: error building: executor failed running [/bin/sh -c npm --prefix ./assets ci --progress=false --no-audit --loglevel=error]: exit code: 1

With Dockerfile:

# Find eligible builder and runner images on Docker Hub. We use Ubuntu/Debian instead of
# Alpine to avoid DNS resolution issues in production.
#
# https://hub.docker.com/r/hexpm/elixir/tags?page=1&name=ubuntu
# https://hub.docker.com/_/ubuntu?tab=tags
#
#
# This file is based on these images:
#
#   - https://hub.docker.com/r/hexpm/elixir/tags - for the build image
#   - https://hub.docker.com/_/debian?tab=tags&page=1&name=bullseye-20210902-slim - for the release image
#   - https://pkgs.org/ - resource for finding needed packages
#   - Ex: hexpm/elixir:1.13.4-erlang-24.3.3-debian-bullseye-20210902-slim
#
ARG ELIXIR_VERSION=1.13.4
ARG OTP_VERSION=24.3.3
ARG DEBIAN_VERSION=bullseye-20210902-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



# install build dependencies
RUN apt-get update && apt-get install -y build-essential git \
    && apt-get clean && rm -f /var/lib/apt/lists/*_*

RUN apt-get update && apt-get install -y nodejs 
RUN apt-get update && apt-get install npm -y
#RUN npm install npm@8.11.0
#RUN rm -rf /usr/local/lib/node_modules/npm
#RUN mv node_modules/npm /usr/local/lib/node_modules/npm


RUN npm --prefix ./assets ci --progress=false --no-audit --loglevel=error

# prepare build dir
WORKDIR /app

# install hex + rebar
RUN mix local.hex --force && \
    mix local.rebar --force

# set build ENV
ENV MIX_ENV="prod"

# install mix dependencies
COPY mix.exs mix.lock ./
RUN mix deps.get --only $MIX_ENV
RUN mkdir config

# copy compile-time config files before we compile dependencies
# to ensure any relevant config change will trigger the dependencies
# to be re-compiled.
COPY config/config.exs config/${MIX_ENV}.exs config/
RUN mix deps.compile

COPY priv priv

COPY lib lib

COPY assets assets

# compile assets
RUN mix assets.deploy

# Compile the release
RUN mix compile

# Changes to config/runtime.exs don't require recompiling the code
COPY config/runtime.exs config/

COPY rel rel
RUN mix release

# start a new build stage so that the final image will only contain
# the compiled release and other runtime necessities
FROM ${RUNNER_IMAGE}

RUN apt-get update -y && apt-get install -y libstdc++6 openssl libncurses5 locales \
  && apt-get clean && rm -f /var/lib/apt/lists/*_*

# Set the locale
RUN sed -i '/en_US.UTF-8/s/^# //g' /etc/locale.gen && locale-gen

ENV LANG en_US.UTF-8
ENV LANGUAGE en_US:en
ENV LC_ALL en_US.UTF-8

WORKDIR "/app"
RUN chown nobody /app

# set runner ENV
ENV MIX_ENV="prod"

# Only copy the final release from the build stage
COPY --from=builder --chown=nobody:root /app/_build/${MIX_ENV}/rel/my_test_app ./

USER nobody

CMD ["/app/bin/server"]
# Appended by flyctl
ENV ECTO_IPV6 true
ENV ERL_AFLAGS "-proto_dist inet6_tcp"

Hi @henning

I suspect that your error comes from the fact that you executed RUN npm --prefix ./assets ci --progress=false --no-audit --loglevel=error before you ran COPY assets assets further down.

If you move the RUN npm... line after the COPY assets assets line, that should fix it.

The reason this is necessary is that your command to RUN npm --prefix **./assets**... requires that your assets folder, along with its package-lock.json file should have been copied over prior to this command.

That’s not the case currently in your Dockerfile.

Please, check. I hope this resolves it.

Indeed I have liftoff. Thank you very much, @kingdomcoder

1 Like

I just realized that tailwindcss-cli is working with 3rd party plugins also in the latest version. That would mean that the best way to integrate daisyui into phoenix application is:

  1. create a new phoenix application.
  2. Use phoenixframework/tailwind: An installer for tailwind (github.com) to integrate tailwindcss into the project
  3. cd assets
  4. yarn add daisyui
  5. In your tailwind.config.js file add the line plugins: [require("daisyui")],

That is it. There is no 6th step. :slight_smile:

4 Likes

For 1.7-rc1 that is

cd assets
npm i -g yarn
yarn add daisyui

tailwind config:

  • add require("daisyui") to plugins
  • optionally: add the daisyui config

A thin layer (function components) around the daisy-ui-components would be nice.
Should be easy as daisyui is css only (however they pull that off).

1 Like

Just ran into this issue:

You may need to remove the tailwind-forms plugin as it adds styles to form elements by default, which break daisyui (eg: collapse with checkbox).

1 Like

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