Blog Home

Dev Tips: Debugging Reaction in a Docker Container

Whether it’s getting code reviewed by coworkers or waiting for tests to pass, a key part of learning is getting feedback. The faster the feedback loop, the faster you learn from mistakes. Especially as a software engineer, the most valuable learning often happens after I’ve been grappling with a failing test and trying again and again until it passes.

As a developer here at Reaction, I know that the Reaction application can take quite a while to start and restart, which can feel like it’s blocking you from developing and learning faster. The team has been putting all sorts of efforts into improving Reaction’s overall performance—including code changes on the API side—but also adding in new ways developers can work in the codebase as well. Figuring out how developers can get faster feedback while developing on Reaction has been one of my personal goals this year, and I’m happy to say that as of the latest version of Reaction, it’s much easier to use the Node inspector with Chrome DevTools with Reaction Admin, plugins, and the API.

Ever since I wrote my first “Hello world” and got back an output in an interactive shell, the shell— sometimes called a REPL (read-eval-print-loop)—has been my most reliable programming learning playground. From the now-defunct Firefox’s Firebug extension for fiddling with the DOM, to Ruby’s IRB for learning my first web application framework, REPLs have been where I tested out new methods and stepped my way through complex applications.

Why REPL?

A REPL, like a browser’s console or Node’s REPL in the Terminal, allows me to test a single expression of JavaScript and immediately get the result. If, say, I’m trying to learn the syntax of JavaScript’s Array.prototype.reduce(), I can copy some example code and get the evaluation immediately. Being able to pause a complex application, like Reaction, and evaluate code within a specific function, can give you access to error messages or variables that are harder to simply log into the console.

Meteor’s previous web-based debugger tool used node-inspect, which ran directly in the Terminal, without the DevTool’s line numbers, play and pause buttons, and more. It also ran with a significant performance penalty, as explained by Ben Newman of Meteor. I was often frustrated using the slow node-inspector, combined with Reaction’s often long restart times and the added complication of running the app within Docker, and would rely on console logging variables instead. But no longer.

Getting to the inspector

Ever since Reaction was updated to use Meteor 1.6, I’ve been using the native Node debugger in Chrome DevTools, all within the Docker environment. For regular Node and Meteor apps alike, passing in an extra flag at startup, --inspect, will make the Node inspector available. It looks like this: node --inspect or meteor --inspect.

To start up Reaction with the inspector, make sure you have Docker running and then run this command from the reaction directory:

docker-compose run --rm --service-ports reaction npm run inspect-docker

Tip: Always remember to pass --service-ports when running inspect mode in Docker

After the application is built, open Google Chrome to chrome://inspect/ and click Open dedicated DevTools for Node.

Nowadays when I’m working on Reaction plugins, the API, or writing tests, I always run the application in inspect mode. I have a lot of breakpoints set in Chrome DevTools that I can easily turn off if I don’t need to inspect anything.

For example, I recently encountered a bug in a mysteriously and silently failing test. And of course, I wanted to inspect it. Running a single test already has its own script: test:file. I created this monster of a command in my own local package.json file:

"test:file:inspect": "NODE_ENV=jesttest BABEL_DISABLE_CACHE=1 node --inspect=0.0.0.0:9229 ./node_modules/jest/bin/jest.js --no-cache --runInBand"

After I added a few breakpoints in both the test file and the file I’m testing, I ran a command like this:

docker-compose run --service-ports reaction yarn run test:file:inspect imports/plugins/core/orders/server/no-meteor/util/myTestFile.test.js

This command isn’t available in the stock version of Reaction, but you can always add your own in development.

Even if you’re happy with your current development workflow (and endless console.log feedback loops) with Reaction and Node apps in general, it never hurts to have one more tool in your debugging and development toolbox.

Next steps

For a step-by-step guide on setting this up for editors like Visual Studio Code and WebStorm, and a more in-depth tutorial on using the inspector, see our Docs on this topic.

For those that want to get under the hood and understand how running the Node inspector in a Docker container works, here’s my short explanation. Let’s start with Node script first. The inspect-docker script runs the Reaction application in experimental module mode and passes --inspect=0.0.0.0:9229. This command explicitly sets the port that the Node inspector uses to 0.0.0.0:9229, which is different from Node’s default port.

That port 9229 comes is set in Reaction’s docker-compose.yml file. And in order to get Docker to use this port, the command above also passes in another key flag: -service-ports. This Docker run flag properly exposes the Node inspector port specified in the node run command.

Special thanks to my coworkers Pete Lyons and Eric Dobbertin for helping me figure this out after many, many tries, and getting this command out for all Reaction developers.

comments powered by Disqus