sa_pageview(path, callback) only called the callback from the pixel's
load or error handler, so a skipped pageview (a repeated path or a path
excluded by ignore-pages) never ran it and code waiting for it hung.
Call the callback on that early return as well, so it runs once per
call, and cover repeated, ignored and namespaced calls in the unit
tests.
Sent pageviews keep calling the callback once from the pixel. The call
is limited to builds with manual pageviews, so light.js is unchanged;
the other scripts grow by 10 bytes minified and 1 to 2 bytes gzip.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Summary
Fixes #130
Targets
v12(#40).sa_pageview(path, callback)only ran the callback from the pixel'sonload/onerror. When the pageview was skipped, because the path repeated or matcheddata-ignore-pages, the callback never ran, so code waiting for it hung. Both cases return early at the same spot inpageview(). That early return now calls the callback, assa_eventalready does for skipped events. A passed callback now runs exactly once per call:sa_pageview("/a", cb)(sent)sa_pageview("/a", cb)again (repeated)sa_pageview("/ignored", cb)/(path, metadata, cb)ba_pageview(...)Sent pageviews still get the callback only from the pixel, so it can't run twice. Automatic pageviews (load,
pushState,popstate,hashchange) pass no callback and send the same requests as before. No other early return in the pageview path skips a passed callback.The call is wrapped in the existing
/** if (or spa hash) **/flag, the same one that definessa_pageview. Without it,light.js(which has nosa_pageview) would have grown by 27 bytes, because uglify would no longer drop the unused callback setup.Size:
latest.js9189 → 9199 bytes minified (+10) and 4614 → 4617 gzip (+3,gzip -9 -n). The other event builds grow by +10 minified and 0 to +2 gzip.light.js,custom/light.jsandauto-events.jsare byte-identical.Effect on customers: sites send the same requests as before. Only sites that pass a callback to
sa_pageview(new in v12) see a change: their callback now also runs for skipped pageviews.Only
src/and tests change.dist/is rebuilt separately.Security implications
Testing
test/unit/pageview-callback.test.jscover a repeated path, an ignored path with metadata, and the namespacedba_pageview, and count calls for a sent pageview. The three skip tests failed before the fix (callbacks ran 0 times) and pass after it.pnpm install --frozen-lockfile,pnpm run buildandpnpm run test:unit(59 passing). Prettier 3.9.10--checkon the changed files andgit diff --checkpass. ESLint shows three errors that also exist onv12, none in changed lines.latest.jsin jsdom withnamespace: "ba"andignorePages: "/ignore". Calls:ba_pageview("/same"),sa_pageview("/same"),ba_pageview("/ignore", metadata),ba_pageview("/other"). Callback calls went from[1, 0, 0, 1]to[1, 1, 1, 1]. Both builds sent the same two requests (/same,/other).sa_pageview. It confirmed one callback for sent and skipped pageviews, including image errors, delayed loads, and client hints that resolve, reject or throw. Automatic navigation payloads and counts were unchanged. Shorter variants it tried were no smaller after gzip.Open workspace in Conductor
Summary by CodeRabbit