From d51d4ab44933291e970bdb8514ead409b785ae41 Mon Sep 17 00:00:00 2001 From: Richard Towers Date: Fri, 10 Jan 2025 11:24:26 +0000 Subject: [PATCH 1/2] Pull custom RUM code into its own module It's a bit surprising to have a bunch of our code tacked on to the end of a vendored file. Our docs say the lux-measurer file "shouldn't ever change", but that feels like a bit of a shaky assumption. In any case, it feels much cleaner to have our code in its own file, instead of muddling it with vendored code. I've use script type=module for two reasons: 1) Like the design system, we can use it as a check that we're in a modern browser, which means we can use const / arrow functions and functions like `.some()` which might not be present in old browsers. For the same reason, we can simplify a lot of the checks around whether the performance API will be there, and whether it will work correctly. 2) It defers the execution of the script, so we'll automatically wait for the HTML to be fully parsed before our code runs. Although we're not interacting with the HTML, I think this should more or less guarantee that (a) the nextHopProtocol timing property is available and (b) the LUX global will already have been defined by lux-measurer.js Just in case (b) isn't always true, I've checked that LUX is defined before attempting to use it. I'm also removing the try / catch code - it doesn't seem like it's doing anything useful even if there is an error, and running as a module the code shouldn't have any reference errors / surprisingly undefined APIs. --- .../rum-custom-data.js | 12 ++++++ .../vendor/lux/lux-measurer.js | 37 ------------------- .../components/_layout_for_public.html.erb | 1 + spec/support/jasmine-browser.json | 1 + 4 files changed, 14 insertions(+), 37 deletions(-) create mode 100644 app/assets/javascripts/govuk_publishing_components/rum-custom-data.js diff --git a/app/assets/javascripts/govuk_publishing_components/rum-custom-data.js b/app/assets/javascripts/govuk_publishing_components/rum-custom-data.js new file mode 100644 index 0000000000..0ee386153e --- /dev/null +++ b/app/assets/javascripts/govuk_publishing_components/rum-custom-data.js @@ -0,0 +1,12 @@ +(function () { + /* global LUX, performance */ + if (typeof LUX === 'undefined') { return } + + const navigationPerformance = performance.getEntriesByType('navigation')[0] + if (!navigationPerformance) { return } + + // As per RFC 147[1], this adds in monitoring of the type of HTTP protocol that + // is used when a browser loads a page. + // [1]: https://github.com/alphagov/govuk-rfcs/pull/148 + LUX.addData('http-protocol', navigationPerformance.nextHopProtocol) +}()) diff --git a/app/assets/javascripts/govuk_publishing_components/vendor/lux/lux-measurer.js b/app/assets/javascripts/govuk_publishing_components/vendor/lux/lux-measurer.js index 60e769f7a7..66be7f8290 100644 --- a/app/assets/javascripts/govuk_publishing_components/vendor/lux/lux-measurer.js +++ b/app/assets/javascripts/govuk_publishing_components/vendor/lux/lux-measurer.js @@ -157,40 +157,3 @@ if ( LongTaskObserver.observe({ type: ["longtask"] }); } catch (e) {} } - -// As per RFC 147[1], this adds in monitoring of the type of HTTP protocol that -// is used when a browser loads a page. -// -// The User Timing API (aka window.performance) is used to record the data - to -// avoid the use of this from breaking the JavaScript for the small number of -// browsers that don't support it, it's been wrapped in a try/catch block plus a -// couple of checks to prevent "is not defined" errors. -// -// Because the `nextHopProtocol` isn't immediately available - it seems to need -// a request to be made before it's populated - we need to wait for the -// `DOMContentReady` event before we can see what the HTTP version is. -// -// [1]: https://github.com/alphagov/govuk-rfcs/pull/148 - -var measureHTTPProtocol = function () { - var getEntriesByType = performance.getEntriesByType('navigation') - - if (typeof getEntriesByType !== 'undefined' && getEntriesByType.length > 0) { - var httpProtocol = getEntriesByType[0].nextHopProtocol - LUX.addData("http-protocol", httpProtocol) - } -} - -try { - if (typeof performance !== 'undefined' && typeof performance.getEntriesByType !== 'undefined') { - if (document.readyState === 'complete') { - measureHTTPProtocol() - } else { - window.addEventListener('load', function() { - measureHTTPProtocol() - }) - } - } -} catch (e) { - console.error('Error in LUX reporting the HTTP protocol (%s):', window.location, e) -} diff --git a/app/views/govuk_publishing_components/components/_layout_for_public.html.erb b/app/views/govuk_publishing_components/components/_layout_for_public.html.erb index ed0969f24b..a983ea10db 100644 --- a/app/views/govuk_publishing_components/components/_layout_for_public.html.erb +++ b/app/views/govuk_publishing_components/components/_layout_for_public.html.erb @@ -65,6 +65,7 @@ <%= title %> <%= javascript_include_tag "govuk_publishing_components/vendor/lux/lux-measurer", { async: true } %> + <%= javascript_include_tag "govuk_publishing_components/rum-custom-data", type: "module" %> <%= javascript_include_tag "govuk_publishing_components/rum-loader", { async: true, diff --git a/spec/support/jasmine-browser.json b/spec/support/jasmine-browser.json index eb443a0898..abbbc6c196 100644 --- a/spec/support/jasmine-browser.json +++ b/spec/support/jasmine-browser.json @@ -7,6 +7,7 @@ "govuk_publishing_components/analytics-*.js", "govuk_publishing_components/load-analytics-*.js", "govuk_publishing_components/vendor/lux/lux-measurer-*.js", + "govuk_publishing_components/rum-custom-data-*.js", "component_guide/accessibility-test-*.js", "component_guide/filter-components-*.js", "component_guide/audit-filter-*.js" From 792ab7967d59f60cf5118689a5deaf0590a2d62e Mon Sep 17 00:00:00 2001 From: Richard Towers Date: Fri, 10 Jan 2025 11:33:59 +0000 Subject: [PATCH 2/2] Report cache status to RUM We added the cache state to the Server-Timing header in alphagov/govuk-fastly#130 This uses the browser's performance API to check if there's a cacheHit / cacheMiss value in the Server-Timing header, and if there is, report it to RUM. This will allow us to separate the performance of GOV.UK for cache hits from cache misses, which will give us some useful insights into how much the cache speeds things up, and how many requests are actually cached in --- CHANGELOG.md | 1 + .../govuk_publishing_components/rum-custom-data.js | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index bb997705a8..33c189f80c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ ## Unreleased +* Report cache status to RUM ([PR #4537](https://github.com/alphagov/govuk_publishing_components/pull/4537)) * Add type option to component wrapper helper ([PR #4536](https://github.com/alphagov/govuk_publishing_components/pull/4536)) * **BREAKING** Change devolved nations component type option ([PR #4535](https://github.com/alphagov/govuk_publishing_components/pull/4535)) * **BREAKING** Add component wrapper helper to intervention component ([PR #4378](https://github.com/alphagov/govuk_publishing_components/pull/4378)) diff --git a/app/assets/javascripts/govuk_publishing_components/rum-custom-data.js b/app/assets/javascripts/govuk_publishing_components/rum-custom-data.js index 0ee386153e..907311f74b 100644 --- a/app/assets/javascripts/govuk_publishing_components/rum-custom-data.js +++ b/app/assets/javascripts/govuk_publishing_components/rum-custom-data.js @@ -9,4 +9,10 @@ // is used when a browser loads a page. // [1]: https://github.com/alphagov/govuk-rfcs/pull/148 LUX.addData('http-protocol', navigationPerformance.nextHopProtocol) + + const serverTiming = navigationPerformance.serverTiming + if (serverTiming) { + const cacheState = serverTiming.find(entry => ['cacheHit', 'cacheMiss'].includes(entry.name)) + if (cacheState) { LUX.addData('cache', cacheState.name) } + } }())