How I fixed a bug with Prettier
I recently encountered a Rube Goldberg machine type of system to generate PDFs and CSV reports. The main application is a php api. A php process that shell_exec
's a command that calls a node script. This node script uses puppeteer to launch Chromium navigate to the main web app, and generates a PDF of the page or clicks a button that downloads a CSV, then emails this report to some recipients.
Something like this.
shell_exec("npx cross-env DOCUMENT_TYPE=\"csv\" TARGET_URL=\"$targetUrl\" node /app/generate-report.js");
This process hasn't changed in years. You know the saying, if it ain't broke, don't fix it. Well...it broke after a recent frontend(react) and backend(php) release. The mysterious part was that nothing related to these reports being generated changed.
Luckily, the app has sufficient logs that I could view so I was able to grab the exact command being shell_exec
'd to run a report.
I navigated to the TARGET_URL
directly in my browser and saw that the app was behaving as expected there. I was hoping maybe just that page of the app was crashing and it'd be a simple fix there. No luck.
Next, I ssh'd into the testing/development server and manually executed the shell command and encountered the same issue. No CSV file was being created. This ruled out the problem being in the backend php code.
Then, on the server I copied the existing generate-report.js
script to a generate-report-debug.js
file and added a bunch of logging into that. Notably this:
page.on('pageerror', error => {
console.log('Page error:', error.message);
console.log('Stack trace:', error.stack || '(No stack trace available)');
});
After running it, I was seeing this logged:
Page error: SyntaxError: Unexpected token '='
Stack trace: (No stack trace available)
After discovering this syntax error, but not knowing where the heck is was coming from I wanted to test if PDF reports worked. It was initially reported that PDF still worked because there were PDFs being generated. I ran a PDF version of the command above and a PDF was created but after downloading it locally and opening, it was just a blank white document. Both PDF and CSV reports were borked.
I couldn't figure out how to get any more information about the SyntaxError
on the server so I went local. I ran the puppeteer script in normal mode(not headless) so Chromium would actually launch and I could poke around. I set the target url to the staging app and I was able to reproduce the same error. The error was coming from a minified javascript build file but it was so big I couldn't get Chromium to pretty print it to actually discover where this error was coming from.
I decided to build the frontend locally and pointed the node script at that and was able to reproduce it there as well. I took the offending minified javascript file and pasted it into the prettier playground to have it nicely formatted and replaced my local version with that.
Side note: I was super impressed the prettier playground/Chrome was able to handle the gigantic file I threw at it.
I re-ran the script to launch chromium and discovered it was erroring on this code.
The null-coalescing assignment syntax. This is in the most recent version of react-redux which got upgraded in the release(intentionally).
The problem was that the version of Chromium that came with puppeteer was using Chromium v80. (I told you this thing has been around and working for a while...) This new syntax wasn't supported until v85.
The app was just crashing because of this. Hence, the blank PDF document being generated. It was generating a PDF of the crashed app.
On the testing server, I created a new little npm project and tried to use the latest puppeteer version(which comes with Chromium) but I couldn't get the newer version of Chromium to work on the server. There were dependencies missing that I was not authorized to update/install. Instead, I figured out the oldest version of puppeteer that uses Chromium >= 85 and installed that. Ran my test script and it everything worked. 🎉
What a ride that was. I never would have thought the Prettier playground would ever help me fix a bug but here we are! Another bug bites the dust. 🪦
Categories: React, Javascript, dev-ops, PHP