@codeserk/forge-stats-web-vitals 0.4.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -10,7 +10,7 @@ npm install @codeserk/forge-stats-web-vitals
10
10
 
11
11
  ## Usage
12
12
 
13
- Captures LCP, INP, CLS, FCP and TTFB with `web-vitals`, plus the DOMContentLoaded (`domLoad`) and load (`pageLoad`) times, and tracks them as one `Performance` event per page load when the page is first hidden. `getRoute` returns the route pattern, not the raw pathname. A metric that did not happen is left out:
13
+ Captures LCP, INP, CLS, FCP and TTFB with `web-vitals`, plus the DOMContentLoaded (`domLoad`) and load (`pageLoad`) times, and tracks them as one `Performance` event per page load when the page is first hidden. `getRoute` returns the route pattern, not the raw pathname, and is read once at `init`, so the event belongs to the route the page loaded on even after client-side navigations. A metric that did not happen is left out:
14
14
 
15
15
  ```ts
16
16
  import { init, webVitals } from '@codeserk/forge-stats-web-vitals'
package/dist/index.cjs CHANGED
@@ -17,11 +17,13 @@ function webVitals(options) {
17
17
  };
18
18
  }
19
19
  /**
20
- * Tracks the web vitals through the client the first time the page is hidden, when INP and CLS are final.
20
+ * Tracks the web vitals of the route the page loaded on, the first time the page is hidden, when INP and CLS
21
+ * are final.
21
22
  * @param client
22
23
  * @param options
23
24
  */
24
25
  function captureWebVitals(client, { getRoute }) {
26
+ const route = getRoute();
25
27
  const metrics = {};
26
28
  const collect = (metric) => {
27
29
  metrics[metric.name.toLowerCase()] = metric.value;
@@ -36,7 +38,7 @@ function captureWebVitals(client, { getRoute }) {
36
38
  document.removeEventListener("visibilitychange", onVisibilityChange);
37
39
  client.track({
38
40
  type: PERFORMANCE_EVENT_TYPE,
39
- name: getRoute(),
41
+ name: route,
40
42
  data: {
41
43
  context: "web",
42
44
  ...metrics,
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":[],"sources":["../src/web-vitals.const.ts","../src/web-vitals.ts"],"sourcesContent":["export const PERFORMANCE_EVENT_TYPE = 'Performance'\nexport const WEB_CONTEXT = 'web'\nexport const WEB_VITALS_PLUGIN_NAME = 'web-vitals'\n","import type { Client, StatsPlugin } from '@codeserk/forge-stats'\nimport { type Metric, onCLS, onFCP, onINP, onLCP, onTTFB } from 'web-vitals'\n\nimport { PERFORMANCE_EVENT_TYPE, WEB_CONTEXT, WEB_VITALS_PLUGIN_NAME } from './web-vitals.const'\nimport type { WebVitalsOptions } from './web-vitals.types'\n\n/**\n * Returns the plugin that tracks the web vitals of the page load as one `Performance` event.\n * @param options\n * @returns the plugin for `init`\n */\nexport function webVitals(options: WebVitalsOptions): StatsPlugin {\n return {\n name: WEB_VITALS_PLUGIN_NAME,\n setup: (client) => captureWebVitals(client, options),\n }\n}\n\n/**\n * Tracks the web vitals through the client the first time the page is hidden, when INP and CLS are final.\n * @param client\n * @param options\n */\nfunction captureWebVitals(client: Client, { getRoute }: WebVitalsOptions): void {\n const metrics: Record<string, number> = {}\n const collect = (metric: Metric) => {\n metrics[metric.name.toLowerCase()] = metric.value\n }\n onLCP(collect)\n onINP(collect)\n onCLS(collect)\n onFCP(collect)\n onTTFB(collect)\n\n const onVisibilityChange = () => {\n if (document.visibilityState !== 'hidden') {\n return\n }\n\n document.removeEventListener('visibilitychange', onVisibilityChange)\n client.track({\n type: PERFORMANCE_EVENT_TYPE,\n name: getRoute(),\n data: { context: WEB_CONTEXT, ...metrics, ...loadTimes() },\n })\n }\n document.addEventListener('visibilitychange', onVisibilityChange)\n}\n\n/**\n * Returns the DOMContentLoaded and load times reached so far.\n * @returns the times in ms, as `domLoad` and `pageLoad`\n */\nfunction loadTimes(): Record<string, number> {\n const [navigation] = performance.getEntriesByType('navigation') as PerformanceNavigationTiming[]\n const times: Record<string, number> = {}\n if (navigation?.domContentLoadedEventEnd > 0) {\n times.domLoad = navigation.domContentLoadedEventEnd\n }\n if (navigation?.loadEventEnd > 0) {\n times.pageLoad = navigation.loadEventEnd\n }\n\n return times\n}\n"],"mappings":";;;AAAA,MAAa,yBAAyB;AAEtC,MAAa,yBAAyB;;;;;;;;ACStC,SAAgB,UAAU,SAAwC;AAChE,QAAO;EACL,MAAM;EACN,QAAQ,WAAW,iBAAiB,QAAQ,QAAQ;EACrD;;;;;;;AAQH,SAAS,iBAAiB,QAAgB,EAAE,YAAoC;CAC9E,MAAM,UAAkC,EAAE;CAC1C,MAAM,WAAW,WAAmB;AAClC,UAAQ,OAAO,KAAK,aAAa,IAAI,OAAO;;AAE9C,EAAA,GAAA,WAAA,OAAM,QAAQ;AACd,EAAA,GAAA,WAAA,OAAM,QAAQ;AACd,EAAA,GAAA,WAAA,OAAM,QAAQ;AACd,EAAA,GAAA,WAAA,OAAM,QAAQ;AACd,EAAA,GAAA,WAAA,QAAO,QAAQ;CAEf,MAAM,2BAA2B;AAC/B,MAAI,SAAS,oBAAoB,SAC/B;AAGF,WAAS,oBAAoB,oBAAoB,mBAAmB;AACpE,SAAO,MAAM;GACX,MAAM;GACN,MAAM,UAAU;GAChB,MAAM;IAAE,SAAA;IAAsB,GAAG;IAAS,GAAG,WAAW;IAAE;GAC3D,CAAC;;AAEJ,UAAS,iBAAiB,oBAAoB,mBAAmB;;;;;;AAOnE,SAAS,YAAoC;CAC3C,MAAM,CAAC,cAAc,YAAY,iBAAiB,aAAa;CAC/D,MAAM,QAAgC,EAAE;AACxC,KAAI,YAAY,2BAA2B,EACzC,OAAM,UAAU,WAAW;AAE7B,KAAI,YAAY,eAAe,EAC7B,OAAM,WAAW,WAAW;AAG9B,QAAO"}
1
+ {"version":3,"file":"index.cjs","names":[],"sources":["../src/web-vitals.const.ts","../src/web-vitals.ts"],"sourcesContent":["export const PERFORMANCE_EVENT_TYPE = 'Performance'\nexport const WEB_CONTEXT = 'web'\nexport const WEB_VITALS_PLUGIN_NAME = 'web-vitals'\n","import type { Client, StatsPlugin } from '@codeserk/forge-stats'\nimport { type Metric, onCLS, onFCP, onINP, onLCP, onTTFB } from 'web-vitals'\n\nimport { PERFORMANCE_EVENT_TYPE, WEB_CONTEXT, WEB_VITALS_PLUGIN_NAME } from './web-vitals.const'\nimport type { WebVitalsOptions } from './web-vitals.types'\n\n/**\n * Returns the plugin that tracks the web vitals of the page load as one `Performance` event.\n * @param options\n * @returns the plugin for `init`\n */\nexport function webVitals(options: WebVitalsOptions): StatsPlugin {\n return {\n name: WEB_VITALS_PLUGIN_NAME,\n setup: (client) => captureWebVitals(client, options),\n }\n}\n\n/**\n * Tracks the web vitals of the route the page loaded on, the first time the page is hidden, when INP and CLS\n * are final.\n * @param client\n * @param options\n */\nfunction captureWebVitals(client: Client, { getRoute }: WebVitalsOptions): void {\n const route = getRoute()\n const metrics: Record<string, number> = {}\n const collect = (metric: Metric) => {\n metrics[metric.name.toLowerCase()] = metric.value\n }\n onLCP(collect)\n onINP(collect)\n onCLS(collect)\n onFCP(collect)\n onTTFB(collect)\n\n const onVisibilityChange = () => {\n if (document.visibilityState !== 'hidden') {\n return\n }\n\n document.removeEventListener('visibilitychange', onVisibilityChange)\n client.track({\n type: PERFORMANCE_EVENT_TYPE,\n name: route,\n data: { context: WEB_CONTEXT, ...metrics, ...loadTimes() },\n })\n }\n document.addEventListener('visibilitychange', onVisibilityChange)\n}\n\n/**\n * Returns the DOMContentLoaded and load times reached so far.\n * @returns the times in ms, as `domLoad` and `pageLoad`\n */\nfunction loadTimes(): Record<string, number> {\n const [navigation] = performance.getEntriesByType('navigation') as PerformanceNavigationTiming[]\n const times: Record<string, number> = {}\n if (navigation?.domContentLoadedEventEnd > 0) {\n times.domLoad = navigation.domContentLoadedEventEnd\n }\n if (navigation?.loadEventEnd > 0) {\n times.pageLoad = navigation.loadEventEnd\n }\n\n return times\n}\n"],"mappings":";;;AAAA,MAAa,yBAAyB;AAEtC,MAAa,yBAAyB;;;;;;;;ACStC,SAAgB,UAAU,SAAwC;AAChE,QAAO;EACL,MAAM;EACN,QAAQ,WAAW,iBAAiB,QAAQ,QAAQ;EACrD;;;;;;;;AASH,SAAS,iBAAiB,QAAgB,EAAE,YAAoC;CAC9E,MAAM,QAAQ,UAAU;CACxB,MAAM,UAAkC,EAAE;CAC1C,MAAM,WAAW,WAAmB;AAClC,UAAQ,OAAO,KAAK,aAAa,IAAI,OAAO;;AAE9C,EAAA,GAAA,WAAA,OAAM,QAAQ;AACd,EAAA,GAAA,WAAA,OAAM,QAAQ;AACd,EAAA,GAAA,WAAA,OAAM,QAAQ;AACd,EAAA,GAAA,WAAA,OAAM,QAAQ;AACd,EAAA,GAAA,WAAA,QAAO,QAAQ;CAEf,MAAM,2BAA2B;AAC/B,MAAI,SAAS,oBAAoB,SAC/B;AAGF,WAAS,oBAAoB,oBAAoB,mBAAmB;AACpE,SAAO,MAAM;GACX,MAAM;GACN,MAAM;GACN,MAAM;IAAE,SAAA;IAAsB,GAAG;IAAS,GAAG,WAAW;IAAE;GAC3D,CAAC;;AAEJ,UAAS,iBAAiB,oBAAoB,mBAAmB;;;;;;AAOnE,SAAS,YAAoC;CAC3C,MAAM,CAAC,cAAc,YAAY,iBAAiB,aAAa;CAC/D,MAAM,QAAgC,EAAE;AACxC,KAAI,YAAY,2BAA2B,EACzC,OAAM,UAAU,WAAW;AAE7B,KAAI,YAAY,eAAe,EAC7B,OAAM,WAAW,WAAW;AAG9B,QAAO"}
package/dist/index.mjs CHANGED
@@ -17,11 +17,13 @@ function webVitals(options) {
17
17
  };
18
18
  }
19
19
  /**
20
- * Tracks the web vitals through the client the first time the page is hidden, when INP and CLS are final.
20
+ * Tracks the web vitals of the route the page loaded on, the first time the page is hidden, when INP and CLS
21
+ * are final.
21
22
  * @param client
22
23
  * @param options
23
24
  */
24
25
  function captureWebVitals(client, { getRoute }) {
26
+ const route = getRoute();
25
27
  const metrics = {};
26
28
  const collect = (metric) => {
27
29
  metrics[metric.name.toLowerCase()] = metric.value;
@@ -36,7 +38,7 @@ function captureWebVitals(client, { getRoute }) {
36
38
  document.removeEventListener("visibilitychange", onVisibilityChange);
37
39
  client.track({
38
40
  type: PERFORMANCE_EVENT_TYPE,
39
- name: getRoute(),
41
+ name: route,
40
42
  data: {
41
43
  context: "web",
42
44
  ...metrics,
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../src/web-vitals.const.ts","../src/web-vitals.ts"],"sourcesContent":["export const PERFORMANCE_EVENT_TYPE = 'Performance'\nexport const WEB_CONTEXT = 'web'\nexport const WEB_VITALS_PLUGIN_NAME = 'web-vitals'\n","import type { Client, StatsPlugin } from '@codeserk/forge-stats'\nimport { type Metric, onCLS, onFCP, onINP, onLCP, onTTFB } from 'web-vitals'\n\nimport { PERFORMANCE_EVENT_TYPE, WEB_CONTEXT, WEB_VITALS_PLUGIN_NAME } from './web-vitals.const'\nimport type { WebVitalsOptions } from './web-vitals.types'\n\n/**\n * Returns the plugin that tracks the web vitals of the page load as one `Performance` event.\n * @param options\n * @returns the plugin for `init`\n */\nexport function webVitals(options: WebVitalsOptions): StatsPlugin {\n return {\n name: WEB_VITALS_PLUGIN_NAME,\n setup: (client) => captureWebVitals(client, options),\n }\n}\n\n/**\n * Tracks the web vitals through the client the first time the page is hidden, when INP and CLS are final.\n * @param client\n * @param options\n */\nfunction captureWebVitals(client: Client, { getRoute }: WebVitalsOptions): void {\n const metrics: Record<string, number> = {}\n const collect = (metric: Metric) => {\n metrics[metric.name.toLowerCase()] = metric.value\n }\n onLCP(collect)\n onINP(collect)\n onCLS(collect)\n onFCP(collect)\n onTTFB(collect)\n\n const onVisibilityChange = () => {\n if (document.visibilityState !== 'hidden') {\n return\n }\n\n document.removeEventListener('visibilitychange', onVisibilityChange)\n client.track({\n type: PERFORMANCE_EVENT_TYPE,\n name: getRoute(),\n data: { context: WEB_CONTEXT, ...metrics, ...loadTimes() },\n })\n }\n document.addEventListener('visibilitychange', onVisibilityChange)\n}\n\n/**\n * Returns the DOMContentLoaded and load times reached so far.\n * @returns the times in ms, as `domLoad` and `pageLoad`\n */\nfunction loadTimes(): Record<string, number> {\n const [navigation] = performance.getEntriesByType('navigation') as PerformanceNavigationTiming[]\n const times: Record<string, number> = {}\n if (navigation?.domContentLoadedEventEnd > 0) {\n times.domLoad = navigation.domContentLoadedEventEnd\n }\n if (navigation?.loadEventEnd > 0) {\n times.pageLoad = navigation.loadEventEnd\n }\n\n return times\n}\n"],"mappings":";;;AAAA,MAAa,yBAAyB;AAEtC,MAAa,yBAAyB;;;;;;;;ACStC,SAAgB,UAAU,SAAwC;AAChE,QAAO;EACL,MAAM;EACN,QAAQ,WAAW,iBAAiB,QAAQ,QAAQ;EACrD;;;;;;;AAQH,SAAS,iBAAiB,QAAgB,EAAE,YAAoC;CAC9E,MAAM,UAAkC,EAAE;CAC1C,MAAM,WAAW,WAAmB;AAClC,UAAQ,OAAO,KAAK,aAAa,IAAI,OAAO;;AAE9C,OAAM,QAAQ;AACd,OAAM,QAAQ;AACd,OAAM,QAAQ;AACd,OAAM,QAAQ;AACd,QAAO,QAAQ;CAEf,MAAM,2BAA2B;AAC/B,MAAI,SAAS,oBAAoB,SAC/B;AAGF,WAAS,oBAAoB,oBAAoB,mBAAmB;AACpE,SAAO,MAAM;GACX,MAAM;GACN,MAAM,UAAU;GAChB,MAAM;IAAE,SAAA;IAAsB,GAAG;IAAS,GAAG,WAAW;IAAE;GAC3D,CAAC;;AAEJ,UAAS,iBAAiB,oBAAoB,mBAAmB;;;;;;AAOnE,SAAS,YAAoC;CAC3C,MAAM,CAAC,cAAc,YAAY,iBAAiB,aAAa;CAC/D,MAAM,QAAgC,EAAE;AACxC,KAAI,YAAY,2BAA2B,EACzC,OAAM,UAAU,WAAW;AAE7B,KAAI,YAAY,eAAe,EAC7B,OAAM,WAAW,WAAW;AAG9B,QAAO"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/web-vitals.const.ts","../src/web-vitals.ts"],"sourcesContent":["export const PERFORMANCE_EVENT_TYPE = 'Performance'\nexport const WEB_CONTEXT = 'web'\nexport const WEB_VITALS_PLUGIN_NAME = 'web-vitals'\n","import type { Client, StatsPlugin } from '@codeserk/forge-stats'\nimport { type Metric, onCLS, onFCP, onINP, onLCP, onTTFB } from 'web-vitals'\n\nimport { PERFORMANCE_EVENT_TYPE, WEB_CONTEXT, WEB_VITALS_PLUGIN_NAME } from './web-vitals.const'\nimport type { WebVitalsOptions } from './web-vitals.types'\n\n/**\n * Returns the plugin that tracks the web vitals of the page load as one `Performance` event.\n * @param options\n * @returns the plugin for `init`\n */\nexport function webVitals(options: WebVitalsOptions): StatsPlugin {\n return {\n name: WEB_VITALS_PLUGIN_NAME,\n setup: (client) => captureWebVitals(client, options),\n }\n}\n\n/**\n * Tracks the web vitals of the route the page loaded on, the first time the page is hidden, when INP and CLS\n * are final.\n * @param client\n * @param options\n */\nfunction captureWebVitals(client: Client, { getRoute }: WebVitalsOptions): void {\n const route = getRoute()\n const metrics: Record<string, number> = {}\n const collect = (metric: Metric) => {\n metrics[metric.name.toLowerCase()] = metric.value\n }\n onLCP(collect)\n onINP(collect)\n onCLS(collect)\n onFCP(collect)\n onTTFB(collect)\n\n const onVisibilityChange = () => {\n if (document.visibilityState !== 'hidden') {\n return\n }\n\n document.removeEventListener('visibilitychange', onVisibilityChange)\n client.track({\n type: PERFORMANCE_EVENT_TYPE,\n name: route,\n data: { context: WEB_CONTEXT, ...metrics, ...loadTimes() },\n })\n }\n document.addEventListener('visibilitychange', onVisibilityChange)\n}\n\n/**\n * Returns the DOMContentLoaded and load times reached so far.\n * @returns the times in ms, as `domLoad` and `pageLoad`\n */\nfunction loadTimes(): Record<string, number> {\n const [navigation] = performance.getEntriesByType('navigation') as PerformanceNavigationTiming[]\n const times: Record<string, number> = {}\n if (navigation?.domContentLoadedEventEnd > 0) {\n times.domLoad = navigation.domContentLoadedEventEnd\n }\n if (navigation?.loadEventEnd > 0) {\n times.pageLoad = navigation.loadEventEnd\n }\n\n return times\n}\n"],"mappings":";;;AAAA,MAAa,yBAAyB;AAEtC,MAAa,yBAAyB;;;;;;;;ACStC,SAAgB,UAAU,SAAwC;AAChE,QAAO;EACL,MAAM;EACN,QAAQ,WAAW,iBAAiB,QAAQ,QAAQ;EACrD;;;;;;;;AASH,SAAS,iBAAiB,QAAgB,EAAE,YAAoC;CAC9E,MAAM,QAAQ,UAAU;CACxB,MAAM,UAAkC,EAAE;CAC1C,MAAM,WAAW,WAAmB;AAClC,UAAQ,OAAO,KAAK,aAAa,IAAI,OAAO;;AAE9C,OAAM,QAAQ;AACd,OAAM,QAAQ;AACd,OAAM,QAAQ;AACd,OAAM,QAAQ;AACd,QAAO,QAAQ;CAEf,MAAM,2BAA2B;AAC/B,MAAI,SAAS,oBAAoB,SAC/B;AAGF,WAAS,oBAAoB,oBAAoB,mBAAmB;AACpE,SAAO,MAAM;GACX,MAAM;GACN,MAAM;GACN,MAAM;IAAE,SAAA;IAAsB,GAAG;IAAS,GAAG,WAAW;IAAE;GAC3D,CAAC;;AAEJ,UAAS,iBAAiB,oBAAoB,mBAAmB;;;;;;AAOnE,SAAS,YAAoC;CAC3C,MAAM,CAAC,cAAc,YAAY,iBAAiB,aAAa;CAC/D,MAAM,QAAgC,EAAE;AACxC,KAAI,YAAY,2BAA2B,EACzC,OAAM,UAAU,WAAW;AAE7B,KAAI,YAAY,eAAe,EAC7B,OAAM,WAAW,WAAW;AAG9B,QAAO"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codeserk/forge-stats-web-vitals",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "description": "Web vitals plugin for Forge Stats. Tracks the web performance of every page load as one Performance event.",
5
5
  "license": "MIT",
6
6
  "keywords": [