aswinmohanme

aswinmohanme

Phoenix 1.6.0.rc-0 esbuild assets.deploy fails in production

I have a Phoenix 1.6 app deployed on fly.io, I followed the official guides by fly and the new 1.6 docs to deploy to fly.io. I have also integrated tailwindcss and custom fonts on the pipeline. The deploy fails at assets.deploy because it then checks for runtime secrets that are not present in the builder that fly.io uses.

Here is my Dockerfile

###
### Fist Stage - Building the Release
###
FROM hexpm/elixir:1.12.1-erlang-24.0.1-alpine-3.13.3 AS build

# install build dependencies
RUN apk add --no-cache build-base npm

# prepare build dir
WORKDIR /app

# extend hex timeout
ENV HEX_HTTP_TIMEOUT=20

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

# set build ENV as prod
ENV MIX_ENV=prod
ENV SECRET_KEY_BASE=nokey

# Copy over the mix.exs and mix.lock files to load the dependencies. If those
# files don't change, then we don't keep re-fetching and rebuilding the deps.
COPY mix.exs mix.lock ./
COPY config config

RUN mix deps.get --only prod && \
    mix deps.compile

# install npm dependencies
COPY assets/package.json assets/package-lock.json ./assets/
RUN npm --prefix ./assets ci --progress=false --no-audit --loglevel=error

COPY priv priv
COPY assets assets

# NOTE: If using TailwindCSS, it uses a special "purge" step and that requires
# the code in `lib` to see what is being used. Uncomment that here before
# running the npm deploy script if that's the case.
COPY lib lib

# build assets
# RUN npm run --prefix ./assets deploy
# RUN mix phx.digest
RUN mix assets.deploy

# copy source here if not using TailwindCSS
COPY lib lib

# compile and build release
COPY rel rel
RUN mix do compile, release

###
### Second Stage - Setup the Runtime Environment
###

# prepare release docker image
FROM alpine:3.13.3 AS app
RUN apk add --no-cache libstdc++ openssl ncurses-libs

WORKDIR /app

RUN chown nobody:nobody /app

USER nobody:nobody

COPY --from=build --chown=nobody:nobody /app/_build/prod/rel/indie_paper ./

ENV HOME=/app
ENV MIX_ENV=prod
ENV SECRET_KEY_BASE=nokey
ENV PORT=4000

CMD ["bin/indie_paper", "start"]

Here is my runtime config file

if config_env() == :prod do
  database_url =
    System.get_env("DATABASE_URL") ||
      raise "
      environment variable DATABASE_URL is missing.
      For example: ecto://USER:PASS@HOST/DATABASE
      "

  config :indie_paper, IndiePaper.Repo,
    # ssl: true,
    socket_options: [:inet6],
    url: database_url,
    pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10")

  secret_key_base =
    System.get_env("SECRET_KEY_BASE") ||
      raise "
      environment variable SECRET_KEY_BASE is missing.
      You can generate one by calling: mix phx.gen.secret
      "

  app_name =
    System.get_env("FLY_APP_NAME") ||
      raise "FLY_APP_NAME not available"

  config :indie_paper, IndiePaperWeb.Endpoint,
    server: true,
    url: [host: "#{app_name}.fly.dev", port: 80],
    http: [
      ip: {0, 0, 0, 0, 0, 0, 0, 0},
      port: String.to_integer(System.get_env("PORT") || "4000")
    ],
    secret_key_base: secret_key_base

Here is my updated parts of the mix.exs file

  defp aliases do
    [
      setup: ["deps.get", "ecto.setup", "cmd --cd assets npm install"],
      "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": [
        "cmd --cd assets npm run deploy",
        "esbuild default --minify",
        "phx.digest"
      ]
    ]
  end

The build command fails at esbuild during the build phase with the following error. This might be because fly.io uses a separate build machine that builds the image and then pushes it onto the machine with the secrets. How do I fix this ?

Step 16/30 : RUN mix assets.deploy
 ---> Running in c2f024ff203d

> @ deploy /app/assets
> NODE_ENV=production postcss css/app.css -o ../priv/static/assets/app.css


warn - You have enabled the JIT engine which is currently in preview.
warn - Preview features are not covered by semver, may introduce breaking changes, and can change at any time.
Compiling 34 files (.ex)
Generated indie_paper app
** (RuntimeError) environment variable DATABASE_URL is missing.
For example: ecto://USER:PASS@HOST/DATABASE

    (stdlib 3.15) erl_eval.erl:685: :erl_eval.do_apply/6
    (stdlib 3.15) erl_eval.erl:446: :erl_eval.expr/5
    (stdlib 3.15) erl_eval.erl:123: :erl_eval.exprs/5
    (elixir 1.12.1) lib/code.ex:656: Code.eval_string_with_error_handling/3
    (elixir 1.12.1) lib/config.ex:258: Config.__eval__!/3
    (elixir 1.12.1) lib/config/reader.ex:86: Config.Reader.read!/2

Error error building: error rendering build status stream: The command '/bin/sh -c mix assets.deploy' returned a non-zero code: 1

If I disable the esbuild step the deployment succeeds.

Marked As Solved

aswinmohanme

aswinmohanme

Digging deeper I came across this issue Allow run without config · Issue #18 · phoenixframework/esbuild · GitHub which adds a --no-runtime-config option to esbuild.

This makes my config

      "assets.deploy": [
        "cmd --cd assets npm run deploy",
        "esbuild --no-runtime-config default --minify",

Since the version is not released yet I’ve had to update my esbuild dependency to {:esbuild, git: "https://github.com/phoenixframework/esbuild", runtime: Mix.env() == :dev},

Curently deploying, will come back with results.

EDIT: Deployed and the error went away. Also submitted a PR to generators Add --no-runtime-config option to esbuild by aswinmohanme · Pull Request #4458 · phoenixframework/phoenix · GitHub

Also Liked

maz

maz

Thanks for sharing this Dockerfile. I was having issues where css styles would not appear on Prod. Along with a couple of other changes and this Dockerfile I got it to work.

When I updated to Phoenix 1.6 + tailwind my app.css broke in prod but not dev. So it took quite a long time to figure it out.

  • I forgot to add assets to the static paths in endpoint.ex

  • many app.css references were broken

  • this was the hardest part: my Dockerfile was copying files to the image in the wrong order. This post helped a lot here I updated my dockerfile to your sequence

aswinmohanme

aswinmohanme

The latest version of esbuild ships with the flag by default. So these changes are no longer neccesary.

joerichsen

joerichsen

Hi

Last weekend I deployed a Phoenix 1.6 app to fly.io and ran into the same esbuild error that you encountered :slight_smile:

I fixed it by having the following line in my Dockerfile

RUN DATABASE_URL=ignore FLY_APP_NAME=ignore mix assets.deploy

Does that work for you?

Where Next?

Popular in Questions Top

sergio
In Ruby, I can go: User.find_by(email: "foobar@email.com").update(email: "hello@email.com") How can I do something similar in Elixir? ...
New
9mm
I am constructing a JSON object (map) and I need to conditionally set a field. I’m trying to write proper elixir-way code… and I’m at a l...
New
electic
Hi, I am new to Elixir. I am trying to use the DateTime component to insert a date into MySQL however the there seems to be no way to fo...
New
greenz1
I have a phoenix application from which a user can download multiple(5-6) files of size 1MB. I couldn’t find anything related to sending ...
New
myronmarston
The Elixir Typespec docs show the following syntax for keyword lists in typespecs: # ... | [key: type] # keyword lists...
New
freewebwithme
Using vs code and installed ElixirLS: support and debugger. And I got an error popped up on start up says Failed to run ‘elixir’ comma...
New
SoCreat
i’m a new one to elixir which editor can i use vs code? or atom? Thanks! :smiley:
New
vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
romenigld
I am trying to run a deploy with docker and I successfully runned with this command: docker build -t romenigld/blog-prod . but when I t...
New
svb
Hi! Currently I want to submit a form by pressing the Enter key. However, since my input field is of type “textarea” this is just adds a...
New

Other popular topics Top

Harrisonl
We have an ECS cluster with 4 services, where each task joins a single cluster, via discovery ECS discovery service. Currently when I de...
New
jononomo
I am trying to figure out how Mix knows whether the environment is test, dev, or prod – where is this set? Thanks.
New
minhajuddin
I have seen a lot of code which picks the first element from a list using Enum.at(0) instead of List.first. Is there a reason why people ...
New
aesmail
Hello guys, I have finally made it. I created an admin interface for a framework. It’s been on my todo list for years and with the curre...
New
Qqwy
Original source of discussion: This topic on the Pragmatic Programmers’ Functional Web Development with Elixir, OTP, and Phoenix forum. ...
New
vrod
I am using the Starship cross-shell prompt – it seems pretty nice, but I get some errors: [WARN] - (starship::utils): Executing command ...
New
RisingFromAshes
I’ve read in another post that it may be possible with a router helper - but I couldn’t find an appropriate one, and tbh, I’m still just ...
New
KronicDeth
Elixir plugin for JetBrain’s IntelliJ Platform (including Rubymine) This is a plugin that adds support for Elixir to JetBrains IntelliJ...
289 36432 110
New
sergio
Kind of like when jquery came out, it was super necessary. Existing drag and drop libraries have a bunch of baggage to support old browse...
New
lanycrost
Hi everyone! I need implement if…else if…else condition from my elixir code, and anymore of this control flow structures not work proper...
New

We're in Beta

About us Mission Statement