How to use CI to build your Node.js project?

CocoaCaa
5 min readFeb 28, 2021

You could just zip your whole project or git clone into your production server and run, but… (´・_・`)

Why?

If your project has a native module and is different from your local development machine. You may need to do npm install on the server. With TypeScript, you may also need to transpile to JavaScript. If your project is running on Docker with a custom build Dockerfile may require you to do build the image before use.

Those steps may allow you to do in your local development machine, but the production server may less resource and now allow you to do heavy builds.

So I try to use CI (Continuous integration) to build the whole thing and on the production server just plug-n-play. d(d'∀')

Example requirement

In this article, I will create a Node.js project with TypeScript and Docker w/ custom Dockerfile and native modules ( imagemagick, ffmpeg)

Actually, not only Node.js, the build steps should be applied to most cases. But this article will use Node.js as an example.

Step 0 — The codebase and structure

First of all, set up the project structure, I will make it like the below screenshot

The example project structure

Note that the .circleci, in this example, I will use CircleCI as the CI build service, there are many different CI services you could use such as GitLab CI, Travis CI, etc. And start to implement the major feature.

Step 1 — The Dockerfile and docker-compose

We could bundle all the native modules and npm modules into the docker image, in production server only pull it and use it.

The example Dockerfile

For the docker-compose.yml use on local development, we could write it like this:

The example docker-compose.yml

The container image is built from a local Dockerfile, but how about in production? I will show you the “magic” in the next few steps later.

Step 2 — package.json scripts

You may write the script directly on the CI settings file or in the terminal, it may better to write it on package.json for reuse more easily.

Example scripts block in package.json

Simple build is transpile to JavaScript and start is to start the application.

Step 3 — Writing the CircleCI config file

In CircleCI, the config file will be located on <your_project_root>/.circleci/config.yml, the CI jobs will be to build the docker image, push to the Docker hub, build and archive the project files, push to the GitHub releases page. I will show you the config part by part (since it is very long).

The example CircleCI config file environment and executors

The environment block stores the environment variable that will use on the below jobs. The executors block is the definition for the jobs. In this case, I will push the Docker image to my docker hub repository.

The example CircleCI config file workflows

The jobs will only execute when there is a new tag with /^\d+\/\d+\.\d+$/ (e.g. 0.0.1), and parallelly run the Docker build and project build jobs.

The example CircleCI config file build Docker jobs

build-docker job is to build the Docker image from Dockerfile. After that, persist_to_workspace share the build image for the next job. publish-docker-latest is push the build image to Docker Hub. $DOCKERHUB_PASS and $DOCKERHUB_USERNAME is your Docker Hub login password and username, you could set it on your CircleCI organization setting → Contexts for this config read later. https://circleci.com/docs/2.0/env-vars/

The example CircleCI config file build project file jobs

build is build the project files and archive them. The $GITHUB_TOKEN is your GitHub personal token https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token, could also set it like the above Contexts. You may notice there is a create-prod-docker-compose.sh, it is “magic” I have mentioned on Step 1, and now we are creating another docker-compose file for production. The script is like below:

The create-prod-docker-compose.sh file

$IMAGE_NAME and $CIRCLE_TAG (git tag) will be available in the CI environment, in this case, will be like cocoacaa/sample-ci-release-build:0.0.1.

Step 4 — Push to remote Git server

In this example, I will push the source to GitHub, and link to CircleCI.

Step 5 — Setup CI project

Go to CircleCI projects dashboard and click the Set Up Project button where the project you just pushed to GitHub. After clicking the button, click Use Existing Config since we have this config file already in the sources.

Step 6 — Push the git tag and wait for the build

Now we add a tag (e.g. 0.0.1) to the main branch and push it. Go back to the CircleCI pipeline dashboard and you will see the jobs are starting.

CicleCI building the project

Step 7 — Check the build files

After the builds are done, go to Docker Hub, there is a 0.0.1, and the latest tag will be created.

Docker Hub tags

Also, on your GitHub repository release page and you will find the build archive under assets.

The build file in the GitHub release page

Finally, you could download the artifact.tar.gz, unarchive it and try to run by using docker-compose up -d command in your server.

That’s all! And every time code changes and commits to git with the tag, the CI will automate build your project files. Deploy to your server only need to download the release archive file to your server, unarchive it and start it immediately. d(`・∀・)b

--

--