NPM dependancy and production build

Hi!

I’m struggling a bit with Phoenix and assets.
I have added a dependancy from npm (installed it in the assets-folder according to the docs).
It works fine for development, but I’m having problems with deployments/production.

I use the generated Dockerfile, but when it tries to build it can’t find the npm-package (npm install has not been runned).

What I find a bit lacking in the docs is if I’m supposed to handle this myself? Or should the esbuild task handle this?

(E.g. do I need to add a buildstep in the Dockerfile where I use node to install the package?)

Thanks!

That’s the case. The phoenix boilerplate does use neither node nor npm. So if you want to use those you need to add them to all the necessary places including the docker setup.

3 Likes

Ok! Thanks!
Just wanted to make sure I did things the “correct” way.

I have done this recently, it is as simple as:

# Install node, npm and yarn
RUN curl -sL https://deb.nodesource.com/setup_16.x | bash
RUN apt-get install -y nodejs
RUN npm install --global yarn

The name setup_16.x refers to node 16, replace the number with the version you want to use, npm is automatically installed with node.

Then install the packages with:

# install packages
RUN cd assets && yarn install && cd ..

I am using yarn, however if you want to use npm, you can skip install of yarn and just replace yarn install with npm install.

PS: Don’t forget to install curl, it is not installed with the default dockerfile scaffolding.

And be sure to use the same OS for Node and Elixir (deb/deb).

I was curious if anyone had problems with building the dependencies. Npm didn’t accept the link in the package.json? It was fine however with pnpm (I don’t use yarn).

# package.json
"dependencies": {
    ...
    "phoenix": "link:../deps/phoenix",
    "phoenix_html": "link:../deps/phoenix_html",
    "phoenix_live_view": "link:../deps/phoenix_live_view",

True, the current image used by phoenix generated dockerfile is debian, maybe an option for the generator to add node would be great.

But why would you add phoenix to package.json if esbuild handles it, for example in my project I have:

{
  "dependencies": {
    "daisyui": "^3.6.1"
  }
}

Ah, yes, I forgot :slight_smile: I had to build a custom Esbuild (nicely documented in the doc) as we embed a SolidJS iframe that communicates via websockets/channel.

I ended up adding a nodejs stage which installs the dependancies first.
Like this:

ARG NODE_BUILDER_IMAGE="node:18.17.1-alpine"

########################################
# 1. Build nodejs frontend
########################################
FROM ${NODE_BUILDER_IMAGE} as node-builder

# prepare build dir
RUN mkdir -p /app/assets
WORKDIR /app

# set build ENV
ENV NODE_ENV=prod

# install npm dependencies
COPY assets/package.json assets/package-lock.json ./assets/
RUN cd assets && npm ci

# build assets
COPY assets assets

And on the builder stage, instead of copying the assets from the host, I copy them from the node builder:

# COPY assets assets
COPY --from=node-builder --chown=nobody:root /app/assets ./assets

This seems to work (at least for my current project/setup).

I also feel that this perhaps should be a part of the generator? Like if it detects a package.json in the assets folder it adds an install step to the Dockerfile.

Phoenix used to use node and npm and removed it due to the churn it put on maintainers for making it not break constantly.

Ok! Yes, it can be bit of a pain :slight_smile: