Debugging Cordova build hooks

As your Cordova project grows, you'll need to do outside-the-box things that Cordova doesn't offer support for. You can add build hooks to your project to perform these tasks.

These hooks can run on specific events (before_platform_add, after_prepare, etc.) to execute your arbitrary code. As your build hooks get more complex, you may find that you want to attach a debugger and step through your script. Because build hooks are generally written in JavaScript to be executed in Node.js, this should be as simple as using the Node --inspect parameter. However, there are two different ways to write build scripts, and only one of these can be used in this way.

Legacy Build Hooks

The legacy build hook is easiest method for getting started. To build one, you simply place a file in a subdirectory of the hooks directory of your Cordova project, with the subdirectory name matching the build event you want to hook. For example, to hook the after_prepare event, you would add a file with the following path:

hooks/after_prepare/01_your_script.extension  

This script is executed by Cordova as a shell script. Parameters are passed into this script as environment variables.

This complicates things a bit for cross-platform development. On Windows, your script needs to be something the operating system can execute (e.g., a batch file with extension .bat or .cmd). On Unix-y systems, this would be a shell script with its execute bit set (e.g., chmod +x) and a shebang header:

#!/bin/sh
# Your script here

Thus, the first reason to avoid legacy build hooks is that they make targeting multi-platform development double the effort; you'll need an equivalent script for both Windows and *nix.

Even if you aren't targeting multi-platform development, the aforementioned problem is still introduced when attempting to debug: even if your script is written in JavaScript using #!/usr/bin/env node to indicate it should be executed in Node.js, it will be executed out of process by Cordova. This means that even though you may be able to attach to the Node process running Cordova, the build hook script is in a separate Node process, so your breakpoint will never be hit.

Before you can debug your scripts, you'll need to convert them to the modern format.

Modern Build Hooks

The modern build hook format is JavaScript, without a shebang header. This is because the hooks are not executed as shell scripts, but instead loaded and executed by Cordova in the same Node.js process. If you have legacy build scripts written in JavaScript as shell scripts, you'll need to remove the shebang header and convert them to the new format.

Let's look at converting a script from the legacy format to the modern one. This trivial script simply writes out the names of the Cordova plugins that are installed when executed.

Legacy script:

#!/usr/bin/env node

console.log("Installed plugins are: " + CORDOVA_PLUGINS);  

Modern script:

module.exports = function (context) {  
    console.log("Installed plugins are: " + context.opts.cordova.plugins.toString());
}

In addition to removing the shebang header, you need to wrap your script in a function that is exported. Your function will receive a context object as a way of passing parameters, instead of passing them via environment variables.

One final change is needed: previously, Cordova enumerated the hook directory's subdirectories looking for shell scripts. Now that the script is no longer a shell script, you need to add an entry in config.xml (or plugin.xml, if you are writing a hook for a plugin) to tell Cordova about the hook:

<hook type="after_prepare" src="hooks/your_script.js" />  

Once you've converted your scripts to the new format, you're ready to debug them!

Debugging Your Hook

It's as simple as executing Cordova using Node with the proper inspect parameters. Note that you'll need at least version 6 or newer of Node.js for these parameters.

For example, if you want to debug your after_prepare hook, you invoke the cordova prepare ios command like this:

$ node --inspect --inspect-brk ./node_modules/.bin/cordova prepare ios

Debugger listening on 127.0.0.1:9229.  
To start debugging, open the following URL in Chrome:  
    chrome-devtools://devtools/bundled/inspector.html?experiments=true&v8only=true&ws=127.0.0.1:9229/dc9010dd-f8b8-4ac5-a510-c1a114ec7d29

Navigate to the URL given, and it should be paused courtesy of the --inspect-brk parameter. At this point you should be able to locate your script in the sources panel, set breakpoints, and then resume execution once you are ready. Once Cordova reaches the build hook phase, your breakpoint should hit!

If you are having trouble setting a breakpoint, you can also place a debugger; statement as the first line of your exported function.

Author image
Northern California
A software geek who is into IoT devices, gaming, and Arcade restoration.