Using Chromium instead of STDIN for interactive Node.js batch jobs
I am building a Node.js semi-automatic data migration script where the user is prompted when missing data is encountered, my objective for this script is to
- Show the user with an excerpt from the record with missing data.
- Request feedback from the user synchronously and wait for user’s input.
Obviously, the easiest solution is good ol’ stdin/stdout, using async/await make waiting for user input a trivial matter. Here is some stripped-down code that uses Node’s readline to achieve this (there is no error or corner case handling for simplicity).
This works perfectly for most cases, it will also work well in a text-only terminal. But it isn’t good enough for my use case because I am dealing with non-latin character-sets and this introduces some problems like
- If the character-set is not supported by the terminal, this user will see garbage instead of text.
- Even if the character set is supported, simply putting glyphs side-by-side will not work for language like Arabic, the terminal must have a shaping engine to process the text.
This may not be a problem in a well-configured Linux box, however, I am running this on Windows and I also wanted to give the user a rich preview of the data, notice that we have latitude and longitude fields, wouldn’t it be nicer to show the user a map of the location instead of textual longitudes and latitudes?
So why not bring a browser into the equation? It may help. Obviously downside to this is that we can no longer run this batch jobs in text terminals which is not a problem for my purpose.
Being lazy, I wanted this to be a drop-in solution, I wanted the browser to show the user the data excerpt, wait for his input and report back to the calling function with the user input. Puppeteer is perfectly suited for that, what is Puppeteer?
Puppeteer is a Node library which provides a high-level API to control headless Chrome over the DevTools Protocol. It can also be configured to use full (non-headless) Chrome.
So let’s get back to work, we want to change the code above to make it
- Open up a chrome window and navigate to Google maps website and center on the latitude and longitude of the record in question.
- Show the user the record description in a prompt.
- Wait for the user response.
- Take the user response back to the script and continue with the next record.
Below is the modified getUserInput() function
That it is! The code above does exactly what we want and here it is in action
The code can be modified to overlay some DOM elements on the webpage to allow for more interactivity, you can also write your own HTML page to have as much interactivity as you need. Anyway, the code for this demo is available here.
Disclaimer: I am not sure if this use-case violates Google maps terms of service or not, I just thought it would be cool to try it out.