Nodejs Builds

A build script to build a client-side web application in Docker

It was a challenge. I decided to try to create a web page to demo my HTTP API endpoint. I set myself a goal: if I do a prototype in 1 hour - I’ll have it for my project. I made it in 1.5 hours thou. It will be another story, how I made it deployed (and it include AWS, Terraform, and gotchas). This time, let’s focus on Node and NPM.

Backgrounds

The best for a hackathon like projects, when the time is limited, it to get the goal done. Surprise, it is not always the super-duper technology, or programming language. For me it was obvious - I need to make the site to demo the API endpoint. Technology stack is up to me.

The time is limited. Pick a technology you know the best. Pick an option, you most confident with. It is tricky, again, it should be technology that makes goals achievable faster. It is not the technology you know, but you cannot make it.

I’m not a web developer professional. I had nothing to pick from.

Ask an expert if you are doubts. Andrey suggested using Ring UI library. Right now I’m happy I decided using the library. Frankly, I like the way React approaches to web pages.

The best part - Ring UI comes with the generator, the generator generates an alive skeleton for the website. Now one can start, debug, and build the site. That is it. Of course, Node JS is required on the machine. Awesome! I use IntelliJ IDEA with the Node JS Plugin to develop it.

Building

Back from the old days, I remember how painful it can be to build a web site if you do not have right tooling on your machine. One needs similar tooling for the CI builds too!

So I wrote few bash scripts to automate it for me. I use Docker image with Node JS. It helps a lot!

Dockerfile

The Dockerfile:

FROM node:11

RUN apt-get update && apt-get install -y rsync

RUN mkdir /build /build-src

COPY package.json package-lock.json /build/
RUN cd /build && npm install

All we need to build the project - is an environment with Node, NPM and warm node_modules. Let’s do it! The Dockerfile uses node:11 as the base image to have Node and NPM. Next, we add current package.json to install node_modules. Now node_modules and NPM caches are pre-packed into the container!

Building

As you see from the Dockerfile, we have node_modules created in the /build/ folder. Now we need project sources to be in the folder to run the true build. We must not mix node_modules from the host computer with node_modules from our Docker container. The fact is, you may have OS-specific binaries under node_modules, and it may not play nice if you mix them.

We mount original project sources under /build-src/ folder in docker. We assume the build will share the compiled site into /build-dist/ folder. I use the following script to make it.

The build-container.sh:

#!/bin/bash
set -e -x -u


## copy sources into the right folder
rsync -ai --delete --progress /build-src/ /build/ --exclude node_modules

## do the build
cd /build
npm run build

## copy results back
rsync -ai --delete --progress /build/dist/  /build-dist/

Running in the Container

Let’s start the build in the container. For that, I have the following script.

build.sh

#!/bin/bash

DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
set -e -x -u

IMAGE=project-node-js

docker build --tag ${IMAGE} .

ROOT="$(cd $DIR && pwd)"
DIST="${ROOT}/dist"

rm -rf ${DIST}

docker run -it --rm \
     -v ${ROOT}:/build-src:ro \
     -v ${DIST}:/build-dist \
     ${IMAGE} /build-src/build-container.sh

You also need to add the host node_modules to the .dockerignore file. It will make docker build command to run faster.

The first step - we build the docker container from the Dockerfile. Docker does incremental builds for us. A change in package.json will trigger the container rebuild. Without changes in package.json, it will do nothing pretty fast.

The second step - we run the build in the container.

It may be necessary to fix permissions of the files, that you have under the ${DIST} folder on Linux. That is not needed for builds on Mac, and I assume on Windows.

Conclusion

Now I have a build script for my project. One needs only Docker to build the project. It is essential, the version of Node is hard-coded in the build scripts, we will need to changes to the environment what it changes. The CI builds simplified too! We have no duplication between local builds and CI builds. Everyone calls the same build.sh file to make it.

Do you like to try that? Here is a small exercise for you - add the development web server support into the scripts. I’ll be happy to see your code and update that post.

comments powered by Disqus