visit
One can add a breakpoint to pause execution. Secondly, one can also add logic to a breakpoint to halt the execution. As an example, consider a for
loop having 1,000 iterations. The execution should stop when the iteration count reaches above 100. To do so, put a breakpoint on the for
loop. Next, add the logic to halt the execution when the iteration goes above 100.
If you love this article so far, check out other such awesome articles on my profile.
We are going to create a very simple express Node JS project. It will simply return a static JSON string on opening a specific URL. For this, we will create a file named server.js
, which is the entry point to our project.
Create a server.js
file with the following contents:
const server = require("express")();
server.listen(3000, async () => { });
server.get("/node-app", async (_, response) => {
response.json({ "node": "app" });
});
The server.js
file states that display {“node”: “app”}
on opening //localhost:3000/node-app
URL in the browser.
Secondly, we will need a package.json
file to configure the project and add dependencies. For that, create a package.json
file with the following content:
{
"name": "node-app",
"dependencies": {
"express": "^4.17.1"
}
}
Run the npm install
command to install the dependencies locally. This will create a node_modules
in the project directory.
A Dockerfile
is needed to run the project as a docker container. Create a Dockerfile
with the following contents:
# Download the slim version of node
FROM node:17-slim
# Needed for monitoring any file changes
RUN npm install -g nodemon
# Set the work directory to app folder.
# We will be copying our code here
WORKDIR /node
#Copy all files from current directory to the container
COPY . .
# Needed for production. Check comments below
RUN npm install
The RUN npm install
command is needed only when deploying to production. We will map the /node
directory of our container to the current project directory on localhost using Docker Compose (next section). But when the app is deployed on the container, it needs to install the dependencies on its own.
The Docker ignore feature is very much similar to git ignore. .gitignore
doesn’t track the files or folders mentioned in it. Similarly, we don’t want to copy unnecessary files in the container, which takes up space.
In our case, we don’t want to copy the node_modules folder to the container. To do so, create a .dockerignore
file in the project directory with the following contents:
node_modules/
Now, let’s create a docker-compose.yml
file to add some more configurations. Add the below contents to docker-compose.yml
file once created:
version: '3.4'
services:
node-app:
# 1. build the current directory
build: .
# 2. Run the project using nodemon, for monitoring file changes
# Run the debugger on 9229 port
command: nodemon --inspect=0.0.0.0:9229 /node/server.js 3000
volumes:
# 3. Bind the current directory on local machine with /node inside the container.
- .:/node
ports:
# 4. map the 3000 and 9229 ports of container and host
- "3000:3000"
- "9229:9229"
The docker-compose.yml
file is explained point-wise below.
Run the project using nodemon, since if there are any changes in the local directory, we want to restart the project in the docker with the changes.
Bind our current directory to the /node
directory using
Use the above docker-compose.yml file only for debugging.
The above docker-compose.yml
exposes the debug port. In addition, it also monitors for any file changes inside the container (which are not going to happen). Lastly, it maps the volumes of the container to the project directory.
For production, create a new file docker-compose-prod.yml
with the following contents:
version: '3.4'
services:
node-app:
build: .
command: node /node/server.js 3000
ports:
- "3000:3000"
First, check if you have launch.json
file created in your project. launch.json
defines different types of configurations we can run for debugging. If it is not created, visit the RUN AND DEBUG
tab on the left in your VS Code, as seen in the image below:
Click on the text that says create a launch.json
file. Before you can proceed, it will ask the type of application to proceed. Select Node.js
. It will create a new launch.json
file in your project with a default Node.js configuration added.
{
"version": "0.2.0",
"configurations": [
{
// 1. Type of application to attach to
"type": "node",
// 2. Type of request. In this case 'attach'
"request": "attach",
// 3. Restart the debugger whenever it gets disconnected
"restart": true,
// 4. Port to connect to
"port": 9229,
// 5. Name of the configuration
"name": "Docker: Attach to Node",
// 6. Connect to /node directory of docker
"remoteRoot": "/node"
}
]
}
The configuration added is pretty self-explanatory. Basically, we are asking the debugger to connect to a remote host with port number 9229. We also request the debugger to restart whenever it gets disconnected from the host. By default, the debugger tries to connect on //localhost:9229/
. But the project is hosted inside the /node
directory in docker. To map /node
, the remoteRoot attribute is used.
That’s about it! Now, if you run docker compose up, your project will start running. For the first run, it will download some layers of the node slim SDK and then install nodemon inside the docker container. But, subsequent runs would be much faster. Running docker compose up
will show the following output in your terminal:
In order to attach the debugger, run the Docker: Attach to Node task from the RUN AND DEBUG
tab. The debugger will now attach to the /node
directory of your docker container. Next, put a breakpoint on line 4 of your server.js
file, i.e., response.json({ “super”: “app1” });
. Finally, open your browser and hit //localhost:3000
. The breakpoint will be hit, and the execution will halt.
For production, we need to use the docker-compose-prod.yml
file. To do so, we need to mention the file name in the docker command. Execute the following command to run the project as if in a production environment:
docker compose -f docker-compose-prod.yml up