I can’t believe it’s been over 2 years since I first wrote about Using Angular CLI to create Angular 2 applications in Docker. We use Docker to run every line of code that moves through SimBco. We work with so many different clients and environments our world would be a mess without it. Some of these apps are huge enterprise apps that have been running for years. Some of them are marketing sites that will only live for a few months. We even use it to test the extensions we write for our Facebook Messenger Marketing!
Our original article was written for Angular 2 when it was fresh and new. Obviously we are a long way down the path now, and a couple things have changed. So I wanted to create a post really quick to get you the update. I just used this to create a project a few minutes ago so I know it should be current 🙂
Without further ado, create a new directory for our project to live inside and create a new file named Dockerfile.
FROM node:8-alpine ENV HOME=/usr/src/app RUN mkdir -p $HOME WORKDIR $HOME RUN yarn global add @angular/cli EXPOSE 4200 USER 1000
I found it is better to prefix the version of node so that you don’t get unexpected version differences between new team members coming on line.
Next we want to create a docker-compose.yml file which will define our service we will use to execute the build commands and run our development web server inside.
node: build: . ports: - "4200:4200" volumes: - .:/usr/src/app command: yarn run start
Also even though this project is client facing only I went with a generic “node” service name. This has allowed us to use consistent commands in project with a Node.js backend and an Angular front end.
The final step is to build our image so we can use it to run containers.
Now we have an environment which we can execute JS and create our project. Because we want to create our project into this directory the command to create the project is just a little more complicated than what you would normally run.
docker-compose run --rm node ng new --directory=./ --skip-install my-app-name
docker-compose run --rm node yarn
These two commands will allow you to create a new Angular project inside the current directory named `my-app-name` then install all the dependencies required.
The only configuration change required to this code because of our docker environment is to update the start script to bind to all interfaces. Please edit this line in our package.json file
... "start": "ng serve --host 0.0.0.0", ...
Finally we just need to start the watcher and development web server
This will compile the project and start a development web server running on http://localhost:4200/. Fire up your browser and give that page a look. Congratulations! You created a fresh Angular project, compiled it and ran it in your browser.
At SimBco we have lots of fun writing code and solving business problems. If your team needs help implementing Angular or Docker in your projects drop us a line. We would love to help!
Hello, thank you for sharing! It worked perfectly here. But how do I update the project changes in real time with the nodemon?
What I will typically do in that scenario is add another “script” to my package.json that starts the application using nodemon instead of node. It looks something like this:
“test”: “yarn run lint && NODE_ENV= yarn run mocha”,
“lint”: “eslint src/. test/. –config .eslintrc.json”,
“dev”: “nodemon src/”,
“start”: “node src/”,
“queue”: “node src/queue”,
“mocha”: “mocha test/ –recursive –exit –timeout 50000”,
“migrate”: “sequelize db:migrate”
Then I update the docker-compose.yml so that the “command” is `yarn run dev` instead of `yarn run start`
Then everything runs happy.
That being said, I usually only have to do this for our backend nodejs apps. Using the angular cli steps we use above it will automatically watch for changes and then reload the application in the browser. So you should not need these steps .
From all the tuts about how to get AngularCLI and docker/docker-compose to work together so far yours is the only one that works out of the box.
I am wondering something though.
Can we not put all the work that needs to be done into the build process of the Node container?
I have been trying to somehow include that in the Dockerfile and then just run docker-compose up, but it is not working for various reasons.
Here is what I am trying to do.
RUN mkdir -p $HOME
RUN npm install -g @angular/cli –verbose
# To this point it works, but installing a default new app into the container
# does not seem to work.
# I wanted to install the Agular demo app, the Heros stuff, into a folder called “heroapp”.
# I pass the options to the ng command.
# RUN ng new heroapp –directory=./heroappp –routing=true –style=scss –skipGit=true –verbose=true
# Then I switch to this newly created folder.
# WORKDIR /usr/src/app/heroapp
# RUN npm install –verbose
# Here I try to copy everything from the container to the host.
# But it does not work, the host folder stays empty.
# That is because it goes direction src to dest, and when source is empty
# it will overwrite the container.
# So how to get the container content into the host?
# COPY . .
My docker-compose looks the same as yours.
command: yarn run start
Here the root host folder is the container’s app folder, so when building from the Dockerfile I should see the folder “heroapp” on the host, but I don’t, well I do but it is empty. That is possibly because of the bad COPY command in the Dockerfile.
Regardless, in one sentence.
How do I adjust the Dockerfile so a default app is being created with AngularCLI (into a folder with the name of the app|optional) so that I only have to do docker-compose up and all will be done ready for development?
Thank you heaps!
Learning lots from your post. 😉
Glad the scripts worked for you! I probably need to update them for Angular 8 now, but at least they are still working.
The trick with your Dockerfile is that you only want the bare necessities that you will require for every part of your app. You will only generate the app base template once. So you don’t really want that to be part of the Dockerfile. Once you have generated the base app the first time you will have all those files in your source code repository. So you or anyone else with your codebase will be able to just run docker-compose up and have it just work. If you got what you are trying to do working it would just generate a new app every-time you build your Dockerfile.
Also there are really two use cases here. One is development with live reload of the application in the browser, and the other would be deploying the compiled application that can be served by an HTTP process. So if you are doing development you only want the files inside the container by volume. Because the alternative is that you have to rebuild your Dockerfile every time you make a change to the files. That is gonna be super slow.