Node.js developers are embracing Docker for repeatable builds, and WebStorm supports Docker-oriented workflows: Quickly bootstrap your Node.js app with a Dockerfile, then run and debug your app in Docker, from the WebStorm IDE.
Let’s take a look.
Note: WebStorm’s Docker support is for server-side Node.js applications. It isn’t aimed at client-side applications, e.g. Angular or React. Nor is it for tools like linters or test runners which need to interact with the editor.
- Setup your local Docker environment
- Create, run, and debug a local demo Express application
- Connect to your Docker servers
- Setup a remote Node.js interpreter based on Docker
- Run your Express application in Docker, and connect from WebStorm’s REST client
- Debug the Express application, in a Docker container
WebStorm manages the running of your code in Node.js, as well as debugging, profiling, testing, and more. Your run configuration specifies a path to your locally-installed Node.js interpreter – e.g.
/usr/local/bin/node – and options that go with it.
WebStorm can also, though, manage remote interpreters. Meaning, your code is executed by a Node.js interpreter inside another environment, such as Vagrant or on an SSH-available server.
With WebStorm 2016.3, Docker is added to the list of remote interpreter options. Once configured, WebStorm will create a new container on each run, with the container bound to the project directory, then execute your project code in the Docker-based Node.js environment.
Docker has become easy to download and install, across multiple platforms, and in multiple ways. For this article, we targeted macOS and used the standard Docker for Mac package, version 1.13.1 at the time of the writing. This version is after Docker’s switch away from Virtualbox, hallelujah to all our souls.
The purpose of this article isn’t to show developing Node.js applications, but rather, to show running a Node.js application in a container, then talking to it from the IDE. Therefore we’ll use a simple Express app saved in a
hello_express.js file, with a single REST endpoint at root that returns ‘Hello World’:
With that file saved in our WebStorm project, we’ll run it with the local interpreter:
We can connect to it using WebStorm’s built-in REST client:
During development, we can use WebStorm’s debugger:
Hello Docker Server
We want to talk to Docker servers, but first we need to tell WebStorm where they are located. Let’s start by adding a new Docker server. While we can do this in the dialog for editing a run/debug configuration, the line between interpreter/server/container can get kind of blurred. Plus, we need to see where WebStorm manages its list of Docker servers.
Preferences -> Build, Execution, Deployment -> Docker and you’ll see the following screen:
As you can see, you have no Docker servers defined. As a note, this is an IDE preference, not a project preference, which means this is the list of Docker servers available in all of your WebStorm projects.
Click the plus button to add a new Docker server. Change its
Local Docker. Then, if you are on macOS or Linux, change the
API URL: field to
OK to dismiss the preferences.
You will now see a new Docker tool window button has appeared, with the tool window opened to show your
Local Docker server that you just configured:
If you have no servers configured, this tool icon disappears.
You can connect to the Docker server by clicking the play icon. If Docker isn’t running, after a timeout period, you will get a “connection timed out” message saying the server couldn’t be reached at the API URL that you configured. If Docker is running, though, you will see a listing of Containers and Images:
If you are completely new to Docker on your computer, you’ll see a grand total of…nothing. You’ve created no Docker containers and downloaded no Docker images. Good news: WebStorm does this work for you, and as we’ll see later, this tool window makes it easy to manage the basics of your Docker server.
We’re getting closer. We need a container and a Node.js interpreter inside of it. We’ll let WebStorm stitch that together with a Docker-based remote interpreter.
Hello Remote Interpreter
In our first step of this blog post, we wrote an Express application and made a run/debug configuration. That configuration used a local interpreter. Let’s edit that configuration, and have it instead use a remote interpreter – one running in a container on the Docker server we just connected.
First, go to
Run -> Edit Configurations and select
hello_express. At the far right of the line for Node interpreter: click the browse icon to bring up the
Node.js Interpreters dialog. Then click the plus sign and select
Add remote... to add a new Remote interpreter:
You will now get a dialog
Configure Node.js Remote Interpreter. Click the radio box for
Docker and…here we have it, a chance to make a new, Docker-based remote Node.js interpreter:
As you can see, WebStorm defaults to Local Docker, the only Docker server that we have defined in the WebStorm IDE-wide preferences. We’ve never gotten any Docker “images” (used to make new containers) so WebStorm helpfully chooses a reasonable default. Click
OK to add this new interpreter to the run/debug configuration, then
OK again to close the
Node.js Interpreters dialog.
And…we’re not there yet. We’ve defined:
- A Docker server
- A remote interpreter
- The Docker image associated with that interpreter
This is enough for WebStorm and the Docker server to create (then destroy) a new container, based on the selected image, whenever you run your code.
But the Run/Debug configuration needs some extra information about this project: how to mount your project directory into the container, etc. Lots of Docker knobs to fiddle with, and WebStorm gives you a warning at the bottom about this:
Auto configure checkbox and WebStorm will make sane choices for configuration:
Once you have checked auto configure, you can now click
OK to save the changes to this run/debug configuration.
Finally, we can run it.
When you click play to run your hello_express.js app, it runs in Docker:
- Docker has never retrieved the
node:latestDocker image, so WebStorm tells it to do so.
- WebStorm creates a new image using
node:latestas a base, then installs your project’s packages from
package.jsoninto a tmp folder for the image. This speeds up each run: the Docker image doesn’t need to re-fetch npm packages unless
- With the image ready, WebStorm creates a container and runs your code in the container’s
- Node.js interpreter, with your project mounted as
/opt/projectinside the container.
- After the run is completed, the container is destroyed.
With this optimization, WebStorm can re-run your code quite quickly, despite destroying containers every time.
We now have an Express app running inside the container, listening on port 3000. But we can’t connect to it from the outside. We need to bind the container’s port to a port on the host.
Connecting to the Web Service
Port binding is a bit arcane. WebStorm helps by putting a nice UI on the configuration. Edit your run/debug configuration and click on the browse icon beside
Docker container settings: to bring up the
Edit Docker Container Settings dialog:
Click the triangle to expand the
Port bindings section, then click the plus button to add a new port binding, with the following values:
OK to dismiss the port binding dialog, then
OK to dismiss the container settings dialog, then
OK again to dismiss the Run/Debug Configurations dialog.
Re-start your run window by clicking restart…don’t worry, it can’t take a bit to shut down the container when Express has the loop running.
Bring back your REST Client tool window and change the port from
3001. Click the play icon to issue a request. You again get
Hello World! as the output, but this time, it ran from inside the Docker container:
There we go, WebStorm-managed Docker. Before looking at debugging, let’s cover what’s going on behind the scenes.
What Happens On Each Run
Containers provide isolation. Since your software likely changes between runs, WebStorm provides a newly-minted container on each run. Sounds slow, right? Fortunately, WebStorm takes a number of steps to make this feasible.
First, WebStorm creates a new Dockerfile, keeping your source code up-to-date and installing npm dependencies into the container. This Dockerfile comes from the image that you choose when configuring the remote interpreter. WebStorm makes it convenient to use images from Docker Hub, or your own custom image.
WebStorm then creates a new image and installs the npm modules into the image. To avoid reinstalling the local/global npm modules on every start of the container,
package.json is copied to the
/tmp/project_modules folder on the image.
npm install is then run and the modules will be copied to the project folder in the container. Changing the
package.json in the project results in re-building the image.
After this, WebStorm runs the Docker container with the created image and binds your project folder to
/opt/project folder in the Docker container to ensure synchronization on update. Additionally,
/opt/project/node_modules is mapped to the OS temporary directory.
Here’s an illustration of the configuration created by WebStorm:
If you want custom settings, you can configure Volume mappings for project files and dependencies yourself in “Docker container settings”.
Note: Debugging Node.js apps in Docker is only supported for Node.js version 6.3+.
We’ve now shown running your NodeJS applications in an interpreter in a Docker container. In WebStorm, debugging is just a variation of running: you click a different button, but it uses the same Run/Debug Configuration. Does this mean we can debug NodeJS-Docker apps?
Yes, and it really is that easy. Just set a breakpoint, click the Debug icon in the toolbar, and WebStorm will launch the debug session:
When you issue a request from the REST Client, the debugger stops execution in the Docker container, driven from the IDE:
Like the Run tool, finishing a debugging session deletes the container.
When we added a Docker server, WebStorm added a Docker icon tool icon and tool window. When we connected previously, there wasn’t much to look at. Now, however, we see that two images have been downloaded. You can right-click on container and image listings to perform operations such as removal:
This covers the basic setup of Docker, as used from WebStorm, with an explanation of what happens behind the scenes. Support for Docker is an ongoing effort, so please keep an eye on our issue tracker for Docker-related tickets.