Next.js Manual Web Vitals
Can't solve a problem until you know it exists!
Only way to know if problems exist is if you either do extensive testing, or extensive logging, and I decided to go with logging! Gefore I shared this very site with the world I needed to ensure I could collect data to know when things started to catestrophycailly fail: welcome Web Vitals.
As I was not hosting on Vercel, I had to handle the collection and storage of these vitals manually, which should be simple, just grab the vitals, send them to a function, and save them somewhere!
Thanks to Next.js, I only needed to define a export function reportWebVitals(metric: NextWebVitalsMetric)
function, then call my reporting function accordingly - and add the vitals to a queue if the reporting function was not yet determined.
Sending Vitals
Well that's where my first roadblock happened, I went the recommended route and used navigator.sendBeacon()
to send the information to my function, yet it wasn't working. I saw nothing in the server logs, or in the frontend network requests, until after a few minutes of messing around I decided to disable my uBlock Origin extension and it started to work!
After realizing it was being blocked, I changed the path name from analytics
to vitals
and it appeared in the console as blocked, progress! Next I fell back to using classic fetch()
and nothing was being blocked, and this is where I could've stopped, but I didn't! I wanted to use the navigator.sendBeacon()
when possible, and then fallback to using fetch()
when it failed.
So I created another endpoint specifically for detecting if the navigator.sendBeacon()
had been received, and I used it by making an initial request, and then using fetch()
to essentially ask if the server had received the previous request from this client, and based on that response using either navigator.sendBeacon()
or fetch()
.
Storing Vitals
Since I was hosting on my own VPS, I went with the simplest data storage approach: rotating JSON files.
Of course I was not implementing the logic for the rotating logic myself, that was left to the rotating-file-stream
NPM library.