Tailwind in prod - sh: 1: tailwindcss: not found

Hello,

After I successfully figured out how to set up my Dockerfile to support Rust (for package Explorer) I run into an error with mix assets.deploy as it misses TailwindCSS:

NODE_ENV=production tailwindcss --postcss --minify -i css/app.css -o ../priv/static/assets/app.css

sh: 1: tailwindcss: not found

“assets.deploy” is defined in my mix.exs with

        "cmd --cd assets npm run deploy",
        "esbuild default --minify",
        "phx.digest"
      ]

What can I do?

Here’s my entire 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.12.3-erlang-24.1.4-debian-bullseye-20210902-slim

ARG BUILDER_IMAGE="hexpm/elixir:1.12.3-erlang-24.1.4-debian-bullseye-20210902-slim"

ARG RUNNER_IMAGE="debian:bullseye-20210902-slim"

FROM ${BUILDER_IMAGE} as builder

# install build dependencies

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

# Get Rust

RUN curl https://sh.rustup.rs -sSf | bash -s -- -y

ENV PATH="/root/.cargo/bin:${PATH}"

# 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

# note: if your project uses a tool like https://purgecss.com/,
# which customizes asset compilation based on what it finds in
# your Elixir templates, you will need to move the asset compilation
# step down so that `lib` is available.

COPY assets assets

# For Phoenix 1.6 and later, compile assets using esbuild

RUN mix assets.deploy

# For Phoenix versions earlier than 1.6, compile assets npm

# RUN cd assets && yarn install && yarn run webpack --mode production

# RUN mix phx.digest

# Compile the release

COPY lib lib

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

# Only copy the final release from the build stage

COPY --from=builder --chown=nobody:root /app/_build/prod/rel ./

USER nobody

# Create a symlink to the application directory by extracting the directory name. This is required
# since the release directory will be named after the application, and we don't know that name.

RUN set -eux; \

ln -nfs /app/$(basename *)/bin/$(basename *) /app/entry

CMD /app/entry start

this assets.deploy is still calling npm
so, IMHO, you need to npm install -g tailwindcss in your docker file.

^^ this is the npm run deploy in your package.json, right?

2 Likes

Correct!

I have now put

RUN npm install -g tailwindcss postcss autoprefixer postcss-import postcss-nested

right before RUN mix assets.deploy as I use all of them in my :

module.exports = {
  plugins: {
    "postcss-import": {},
    tailwindcss: {},
    autoprefixer: {},
    "postcss-nested": {},
  },
}

Now I get

(node:19) UnhandledPromiseRejectionWarning: Error: Loading PostCSS Plugin failed: Cannot find module 'postcss-import'

The execution of the npm install command is missing (without -g). Some of these packages must be installed locally (not globally).

RUN npm install tailwindcss postcss autoprefixer postcss-import postcss-nested

And you can call tailwindcss command with npx before: like this NODE_ENV=production npx tailwindcss --postcss --minify -i css/app.css -o ../priv/static/assets/app.css

4 Likes

Thanks a lot :slight_smile:

With your help I was able to create a working Dockerfile to deploy to fly.io.

If anyone should see this thread later, you can find my final Dockerfile here: Deployment of NX.Explorer to fly.io - #18 by Nefcairon

2 Likes