@vercel/speed-insights 0.0.1-beta.2 → 0.0.1-beta.5

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
@@ -1,4 +1,4 @@
1
- ![Speed Insights](https://github.com/vercel/analytics/blob/main/.github/banner.png)
1
+ ![Speed Insights](https://github.com/vercel/speed-insights/blob/main/.github/banner.png)
2
2
 
3
3
  <div align="center"><strong>Vercel Speed Insights</strong></div>
4
4
  <div align="center">Performance insights for your website</div>
@@ -1,12 +1,14 @@
1
1
  "use client";
2
2
  "use strict";
3
+ var __create = Object.create;
3
4
  var __defProp = Object.defineProperty;
4
5
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
6
  var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
6
8
  var __hasOwnProp = Object.prototype.hasOwnProperty;
7
9
  var __export = (target, all) => {
8
- for (var name in all)
9
- __defProp(target, name, { get: all[name], enumerable: true });
10
+ for (var name2 in all)
11
+ __defProp(target, name2, { get: all[name2], enumerable: true });
10
12
  };
11
13
  var __copyProps = (to, from, except, desc) => {
12
14
  if (from && typeof from === "object" || typeof from === "function") {
@@ -16,117 +18,58 @@ var __copyProps = (to, from, except, desc) => {
16
18
  }
17
19
  return to;
18
20
  };
21
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
22
+ // If the importer is in node compatibility mode or this is not an ESM
23
+ // file that has been converted to a CommonJS file using a Babel-
24
+ // compatible transform (i.e. "__esModule" has not been set), then set
25
+ // "default" to the CommonJS "module.exports" for node compatibility.
26
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
27
+ mod
28
+ ));
19
29
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
30
 
21
31
  // src/nextjs/index.tsx
22
32
  var nextjs_exports = {};
23
33
  __export(nextjs_exports, {
24
- SpeedInsights: () => SpeedInsights
34
+ SpeedInsights: () => SpeedInsights2
25
35
  });
26
36
  module.exports = __toCommonJS(nextjs_exports);
37
+ var import_react2 = __toESM(require("react"), 1);
38
+
39
+ // src/react/index.tsx
27
40
  var import_react = require("react");
28
41
 
29
- // src/generic/index.ts
30
- var import_attribution = require("web-vitals/attribution");
42
+ // package.json
43
+ var name = "@vercel/speed-insights";
44
+ var version = "0.0.1-beta.5";
45
+
46
+ // src/queue.ts
47
+ var initQueue = () => {
48
+ if (window.si)
49
+ return;
50
+ window.si = function a(...params) {
51
+ (window.siq = window.siq || []).push(params);
52
+ };
53
+ };
31
54
 
32
55
  // src/utils.ts
33
- function getConnectionSpeed() {
34
- let speed = "";
35
- if ("connection" in navigator) {
36
- const connection = navigator.connection;
37
- if (connection == null ? void 0 : connection.effectiveType) {
38
- speed = connection.effectiveType;
39
- }
40
- }
41
- return speed;
56
+ function isBrowser() {
57
+ return typeof window !== "undefined";
42
58
  }
43
- var ENDPOINT = "https://vitals.vercel-insights.com/v2/vitals";
44
- function sendBeacon(data) {
45
- const blob = new Blob([JSON.stringify(data)], {
46
- type: "text/plain"
47
- });
59
+ function detectEnvironment() {
48
60
  try {
49
- if ("keepalive" in Request.prototype) {
50
- void fetch(ENDPOINT, {
51
- method: "POST",
52
- body: blob,
53
- keepalive: true,
54
- mode: "no-cors",
55
- credentials: "omit"
56
- });
57
- } else if ("sendBeacon" in navigator) {
58
- navigator.sendBeacon(ENDPOINT, blob);
61
+ const env = process.env.NODE_ENV;
62
+ if (env === "development" || env === "test") {
63
+ return "development";
59
64
  }
60
65
  } catch (e) {
61
66
  }
67
+ return "production";
62
68
  }
63
- function getDomTarget(metric) {
64
- if (metric.name === "CLS") {
65
- return metric.attribution.largestShiftTarget;
66
- }
67
- if (metric.name === "FID") {
68
- return metric.attribution.eventTarget;
69
- }
70
- if (metric.name === "LCP") {
71
- return metric.attribution.element;
72
- }
69
+ function isDevelopment() {
70
+ return detectEnvironment() === "development";
73
71
  }
74
- function cutDecimal(number, decimals) {
75
- if (Number.isInteger(number)) {
76
- return number;
77
- }
78
- const multiplier = Math.pow(10, decimals);
79
- return Math.floor(number * multiplier) / multiplier;
80
- }
81
- function formatMetricValue(metric) {
82
- if (metric.name === "CLS") {
83
- return cutDecimal(metric.value, 4);
84
- }
85
- if (metric.name === "FID") {
86
- return cutDecimal(metric.value, 2);
87
- }
88
- return Math.round(metric.value);
89
- }
90
-
91
- // src/generic/index.ts
92
- function sendVitals(metrics, dsn) {
93
- const speed = getConnectionSpeed();
94
- if (metrics.length === 0)
95
- return;
96
- const payload = {
97
- dsn,
98
- speed,
99
- metrics: metrics.map((metric) => ({
100
- id: metric.id,
101
- type: metric.name,
102
- value: formatMetricValue(metric),
103
- dynamicPath: metric.dynamicPath,
104
- href: window.location.href.replace("http://", "https://"),
105
- // TODO: remove this
106
- attribution: {
107
- target: getDomTarget(metric)
108
- }
109
- }))
110
- };
111
- sendBeacon(payload);
112
- }
113
- function watchMetrics(callback) {
114
- (0, import_attribution.onCLS)(callback);
115
- (0, import_attribution.onFID)(callback);
116
- (0, import_attribution.onLCP)(callback);
117
- (0, import_attribution.onFCP)(callback);
118
- (0, import_attribution.onINP)(callback);
119
- (0, import_attribution.onTTFB)(callback);
120
- }
121
-
122
- // src/nextjs/utils.ts
123
- var import_navigation = require("next/navigation");
124
- var useDynamicPath = () => {
125
- const params = (0, import_navigation.useParams)();
126
- const path = (0, import_navigation.usePathname)();
127
- return computePathname(path, params);
128
- };
129
- function computePathname(pathname, pathParams) {
72
+ function computeRoute(pathname, pathParams) {
130
73
  if (pathname === null) {
131
74
  return null;
132
75
  }
@@ -166,40 +109,82 @@ function computePathname(pathname, pathParams) {
166
109
  return result;
167
110
  }
168
111
 
169
- // src/nextjs/index.tsx
170
- function SpeedInsights({ token, sampleRate }) {
171
- const dynamicPath = useDynamicPath();
172
- const vitals = (0, import_react.useRef)([]);
173
- const flush = (0, import_react.useCallback)(() => {
174
- if (vitals.current.length > 0) {
175
- if (sampleRate && Math.random() > sampleRate) {
176
- return;
177
- }
178
- const body = vitals.current;
179
- console.log("flushing", body);
180
- sendVitals(body, token);
181
- vitals.current = [];
112
+ // src/generic.ts
113
+ var DEV_SCRIPT_URL = `https://va.vercel-scripts.com/v1/speed-insights/script.debug.js`;
114
+ var SCRIPT_URL = `/_vercel/speed-insights/script.js`;
115
+ function inject(props) {
116
+ var _a;
117
+ if (!isBrowser())
118
+ return null;
119
+ initQueue();
120
+ if (props.beforeSend) {
121
+ (_a = window.si) == null ? void 0 : _a.call(window, "beforeSend", props.beforeSend);
122
+ }
123
+ const src = props.scriptSrc || (isDevelopment() ? DEV_SCRIPT_URL : SCRIPT_URL);
124
+ if (document.head.querySelector(`script[src*="${src}"]`))
125
+ return null;
126
+ const script = document.createElement("script");
127
+ script.src = src;
128
+ script.defer = true;
129
+ script.dataset.sdkn = name;
130
+ script.dataset.sdkv = version;
131
+ if (props.sampleRate) {
132
+ script.dataset.sampleRate = props.sampleRate.toString();
133
+ }
134
+ if (props.route) {
135
+ script.dataset.route = props.route;
136
+ }
137
+ if (props.endpoint) {
138
+ script.dataset.endpoint = props.endpoint;
139
+ }
140
+ if (props.token) {
141
+ script.dataset.token = props.token;
142
+ }
143
+ if (isDevelopment() && props.debug === false) {
144
+ script.dataset.debug = "false";
145
+ }
146
+ script.onerror = () => {
147
+ const errorMessage = isDevelopment() ? "Please check if any ad blockers are enabled and try again." : "Be sure to enable Speed Insights for your project and deploy again. See https://vercel.com/docs/speed-insights for more information.";
148
+ console.log(
149
+ `[Vercel Speed Insights] Failed to load script from ${src}. ${errorMessage}`
150
+ );
151
+ };
152
+ document.head.appendChild(script);
153
+ return {
154
+ setRoute: (route) => {
155
+ script.dataset.route = route;
182
156
  }
183
- }, [sampleRate, vitals.current]);
184
- (0, import_react.useEffect)(() => {
185
- addEventListener("visibilitychange", flush);
186
- addEventListener("pagehide", flush);
187
- return () => {
188
- removeEventListener("visibilitychange", flush);
189
- removeEventListener("pagehide", flush);
190
- };
191
- }, [flush]);
192
- const reportVital = (0, import_react.useCallback)(
193
- (metric) => {
194
- vitals.current.push({ ...metric, dynamicPath });
195
- },
196
- [dynamicPath]
197
- );
157
+ };
158
+ }
159
+
160
+ // src/react/index.tsx
161
+ function SpeedInsights(props) {
162
+ const setScriptRoute = (0, import_react.useRef)(null);
198
163
  (0, import_react.useEffect)(() => {
199
- watchMetrics(reportVital);
164
+ const script = inject(props);
165
+ setScriptRoute.current = (script == null ? void 0 : script.setRoute) || null;
200
166
  }, []);
167
+ (0, import_react.useEffect)(() => {
168
+ if (props.route && setScriptRoute.current) {
169
+ setScriptRoute.current(props.route);
170
+ }
171
+ }, [props.route]);
201
172
  return null;
202
173
  }
174
+
175
+ // src/nextjs/utils.ts
176
+ var import_navigation = require("next/navigation");
177
+ var useRoute = () => {
178
+ const params = (0, import_navigation.useParams)();
179
+ const path = (0, import_navigation.usePathname)();
180
+ return computeRoute(path, params);
181
+ };
182
+
183
+ // src/nextjs/index.tsx
184
+ function SpeedInsights2(props) {
185
+ const route = useRoute();
186
+ return /* @__PURE__ */ import_react2.default.createElement(SpeedInsights, { ...route && { route }, ...props });
187
+ }
203
188
  // Annotate the CommonJS export names for ESM import in node:
204
189
  0 && (module.exports = {
205
190
  SpeedInsights
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/nextjs/index.tsx","../../src/generic/index.ts","../../src/utils.ts","../../src/nextjs/utils.ts"],"sourcesContent":["import { useCallback, useEffect, useRef } from 'react';\nimport type { Metric, MetricWithAttribution } from 'web-vitals';\nimport { sendVitals, watchMetrics } from '../generic';\nimport type { CollectedMetric } from '../types';\nimport { useDynamicPath } from './utils';\n\ninterface SpeedInsightsProps {\n token: string;\n sampleRate?: number; // Only send a percentage of events to the server to reduce costs\n}\n\nexport function SpeedInsights({ token, sampleRate }: SpeedInsightsProps): null {\n const dynamicPath = useDynamicPath();\n const vitals = useRef<CollectedMetric[]>([]);\n\n const flush = useCallback(() => {\n if (vitals.current.length > 0) {\n if (sampleRate && Math.random() > sampleRate) {\n return;\n }\n const body = vitals.current;\n\n // eslint-disable-next-line no-console -- ok for now\n console.log('flushing', body);\n sendVitals(body, token);\n\n vitals.current = [];\n }\n }, [sampleRate, vitals.current]);\n\n useEffect(() => {\n addEventListener('visibilitychange', flush);\n addEventListener('pagehide', flush);\n return () => {\n removeEventListener('visibilitychange', flush);\n removeEventListener('pagehide', flush);\n };\n }, [flush]);\n\n const reportVital = useCallback(\n (metric: MetricWithAttribution): void => {\n vitals.current.push({ ...metric, dynamicPath });\n },\n [dynamicPath],\n );\n\n useEffect(() => {\n watchMetrics(reportVital as (metric: Metric) => void); // TODO: fix typing -- caused by not properly typed library\n }, []);\n\n return null;\n}\n","import {\n onLCP,\n onFID,\n onCLS,\n onFCP,\n onINP,\n onTTFB,\n} from 'web-vitals/attribution';\nimport type { Metric } from 'web-vitals';\nimport type { CollectedMetric, SpeedInsightsPayload } from '../types';\nimport {\n formatMetricValue,\n getConnectionSpeed,\n getDomTarget,\n sendBeacon,\n} from '../utils';\n\nexport function sendVitals(metrics: CollectedMetric[], dsn: string): void {\n const speed = getConnectionSpeed();\n\n if (metrics.length === 0) return;\n\n const payload: SpeedInsightsPayload = {\n dsn,\n speed,\n metrics: metrics.map((metric) => ({\n id: metric.id,\n type: metric.name,\n value: formatMetricValue(metric),\n dynamicPath: metric.dynamicPath,\n href: window.location.href.replace('http://', 'https://'), // TODO: remove this\n attribution: {\n target: getDomTarget(metric),\n },\n })),\n };\n sendBeacon(payload as never);\n}\n\nexport function watchMetrics(callback: (metric: Metric) => void): void {\n onCLS(callback);\n onFID(callback);\n onLCP(callback);\n onFCP(callback);\n onINP(callback);\n onTTFB(callback);\n}\n","import type { MetricWithAttribution } from 'web-vitals';\nimport type { CollectedMetric } from './types';\n\nexport function isBrowser(): boolean {\n return typeof window !== 'undefined';\n}\n\nexport function getConnectionSpeed(): string {\n let speed = '';\n if ('connection' in navigator) {\n const connection = navigator.connection as never as\n | {\n effectiveType?: string;\n }\n | undefined;\n if (connection?.effectiveType) {\n speed = connection.effectiveType;\n }\n }\n return speed;\n}\n\nconst ENDPOINT = 'https://vitals.vercel-insights.com/v2/vitals';\n\nexport function sendBeacon(\n data: Record<string, string | number> | URLSearchParams | undefined,\n): void {\n const blob = new Blob([JSON.stringify(data)], {\n type: 'text/plain',\n });\n try {\n if ('keepalive' in Request.prototype) {\n void fetch(ENDPOINT, {\n method: 'POST',\n body: blob,\n keepalive: true,\n mode: 'no-cors',\n credentials: 'omit',\n });\n } else if ('sendBeacon' in navigator) {\n // Use sendBeacon as a fallback\n navigator.sendBeacon(ENDPOINT, blob);\n }\n } catch (e) {\n /* empty */\n }\n}\n\nexport function getDomTarget(\n metric: MetricWithAttribution,\n): string | undefined {\n if (metric.name === 'CLS') {\n return metric.attribution.largestShiftTarget as string;\n }\n if (metric.name === 'FID') {\n return metric.attribution.eventTarget as string;\n }\n if (metric.name === 'LCP') {\n return metric.attribution.element as string;\n }\n}\n\nexport function cutDecimal(number: number, decimals: number): number {\n if (Number.isInteger(number)) {\n return number;\n }\n\n const multiplier = Math.pow(10, decimals);\n return Math.floor(number * multiplier) / multiplier;\n}\n\nexport function formatMetricValue(metric: CollectedMetric): number {\n if (metric.name === 'CLS') {\n return cutDecimal(metric.value, 4);\n }\n if (metric.name === 'FID') {\n return cutDecimal(metric.value, 2);\n }\n return Math.round(metric.value);\n}\n","'use client';\nimport { useParams, usePathname } from 'next/navigation';\n\nexport const useDynamicPath = (): string | null => {\n const params = useParams();\n const path = usePathname();\n\n return computePathname(path, params);\n};\n\n// Refined version from dvoytenko\n// https://github.com/vercel/front/pull/25076\nfunction computePathname(\n pathname: string | null,\n pathParams: Record<string, string | string[]> | null,\n): string | null {\n if (pathname === null) {\n return null;\n }\n if (pathname === '' || !pathParams) {\n return pathname;\n }\n let result = pathname;\n for (const [key, valueOrArray] of Object.entries(pathParams)) {\n let value: string;\n let expr: string;\n if (Array.isArray(valueOrArray)) {\n // An array-based segment, e.g. \"/[...slugs]\".\n expr = `...${key}`;\n value = valueOrArray.join('/');\n } else {\n // A single dynamic segment, e.g. \"/posts/[pid]\".\n expr = key;\n value = valueOrArray;\n }\n if (!value) {\n continue;\n }\n let start = 0;\n while (start !== -1) {\n start = result.indexOf(`/${value}`, start);\n if (start !== -1) {\n const end = start + value.length + 2;\n if (\n end >= result.length ||\n result[end] === '/' ||\n result[end] === '?' ||\n result[end] === '#'\n ) {\n result = `${result.substring(\n 0,\n start + 1,\n )}[${expr}]${result.substring(end)}`;\n break;\n }\n start += value.length + 1;\n }\n }\n }\n return result;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/nextjs/index.tsx","../../src/react/index.tsx","../../package.json","../../src/queue.ts","../../src/utils.ts","../../src/generic.ts","../../src/nextjs/utils.ts"],"sourcesContent":["import React from 'react';\nimport { SpeedInsights as SpeedInsightsScript } from '../react';\nimport type { SpeedInsightsProps } from '../types';\nimport { useRoute } from './utils';\n\nexport function SpeedInsights(\n props: Omit<SpeedInsightsProps, 'route'>,\n): JSX.Element {\n const route = useRoute();\n\n return <SpeedInsightsScript {...(route && { route })} {...props} />;\n}\n","'use client';\nimport { useEffect, useRef } from 'react';\nimport type { SpeedInsightsProps } from '../types';\nimport { inject } from '../generic';\n\nexport function SpeedInsights(props: SpeedInsightsProps): JSX.Element | null {\n const setScriptRoute = useRef<((path: string) => void) | null>(null);\n useEffect(() => {\n const script = inject(props);\n\n setScriptRoute.current = script?.setRoute || null;\n }, []);\n\n useEffect(() => {\n if (props.route && setScriptRoute.current) {\n setScriptRoute.current(props.route);\n }\n }, [props.route]);\n\n return null;\n}\n","{\n \"name\": \"@vercel/speed-insights\",\n \"version\": \"0.0.1-beta.5\",\n \"description\": \"Speed Insights is a tool for measuring web performance and providing suggestions for improvement.\",\n \"keywords\": [\n \"speed-insights\",\n \"vercel\"\n ],\n \"repository\": {\n \"url\": \"github:vercel/speed-insights\",\n \"directory\": \"packages/web\"\n },\n \"license\": \"MPL-2.0\",\n \"type\": \"module\",\n \"exports\": {\n \"./package.json\": \"./package.json\",\n \".\": {\n \"browser\": \"./dist/index.js\",\n \"import\": \"./dist/index.js\",\n \"require\": \"./dist/index.cjs\"\n },\n \"./next\": {\n \"browser\": \"./dist/next/index.js\",\n \"import\": \"./dist/next/index.js\",\n \"require\": \"./dist/next/index.cjs\"\n },\n \"./remix\": {\n \"browser\": \"./dist/remix/index.js\",\n \"import\": \"./dist/remix/index.js\",\n \"require\": \"./dist/remix/index.cjs\"\n }\n },\n \"main\": \"dist/index.js\",\n \"types\": \"dist/index.d.ts\",\n \"typesVersions\": {\n \"*\": {\n \"*\": [\n \"dist/index.d.ts\"\n ],\n \"react\": [\n \"dist/react/index.d.ts\"\n ],\n \"next\": [\n \"dist/next/index.d.ts\"\n ],\n \"remix\": [\n \"dist/remix/index.d.ts\"\n ]\n }\n },\n \"scripts\": {\n \"build\": \"tsup\",\n \"dev\": \"tsup --watch\",\n \"postinstall\": \"node scripts/postinstall.js\",\n \"lint\": \"eslint .\",\n \"lint-fix\": \"eslint . --fix\",\n \"test\": \"jest\",\n \"type-check\": \"tsc --noEmit\"\n },\n \"devDependencies\": {\n \"@remix-run/react\": \"^2.0.1\",\n \"@swc/core\": \"^1.3.82\",\n \"@swc/jest\": \"^0.2.29\",\n \"@testing-library/jest-dom\": \"^6.1.2\",\n \"@testing-library/react\": \"^14.0.0\",\n \"@types/jest\": \"^29.5.4\",\n \"@types/node\": \"^20.5.9\",\n \"@types/react\": \"^18.2.21\",\n \"jest\": \"^29.6.4\",\n \"jest-environment-jsdom\": \"^29.6.4\",\n \"next\": \"^13.4.19\",\n \"react\": \"^18.2.0\",\n \"react-dom\": \"^18.2.0\",\n \"tsup\": \"7.2.0\"\n }\n}\n","export const initQueue = (): void => {\n // initialize va until script is loaded\n if (window.si) return;\n\n window.si = function a(...params): void {\n (window.siq = window.siq || []).push(params);\n };\n};\n","export function isBrowser(): boolean {\n return typeof window !== 'undefined';\n}\n\nfunction detectEnvironment(): 'development' | 'production' {\n try {\n const env = process.env.NODE_ENV;\n if (env === 'development' || env === 'test') {\n return 'development';\n }\n } catch (e) {\n // do nothing, this is okay\n }\n return 'production';\n}\n\nexport function isProduction(): boolean {\n return detectEnvironment() === 'production';\n}\n\nexport function isDevelopment(): boolean {\n return detectEnvironment() === 'development';\n}\n\nexport function computeRoute(\n pathname: string | null,\n pathParams: Record<string, string | string[]> | null,\n): string | null {\n if (pathname === null) {\n return null;\n }\n if (pathname === '' || !pathParams) {\n return pathname;\n }\n let result = pathname;\n for (const [key, valueOrArray] of Object.entries(pathParams)) {\n let value: string;\n let expr: string;\n if (Array.isArray(valueOrArray)) {\n // An array-based segment, e.g. \"/[...slugs]\".\n expr = `...${key}`;\n value = valueOrArray.join('/');\n } else {\n // A single dynamic segment, e.g. \"/posts/[pid]\".\n expr = key;\n value = valueOrArray;\n }\n if (!value) {\n continue;\n }\n let start = 0;\n while (start !== -1) {\n start = result.indexOf(`/${value}`, start);\n if (start !== -1) {\n const end = start + value.length + 2;\n if (\n end >= result.length ||\n result[end] === '/' ||\n result[end] === '?' ||\n result[end] === '#'\n ) {\n result = `${result.substring(\n 0,\n start + 1,\n )}[${expr}]${result.substring(end)}`;\n break;\n }\n start += value.length + 1;\n }\n }\n }\n return result;\n}\n","import { name as packageName, version } from '../package.json';\nimport { initQueue } from './queue';\nimport type { SpeedInsightsProps } from './types';\nimport { isBrowser, isDevelopment } from './utils';\n\nconst DEV_SCRIPT_URL = `https://va.vercel-scripts.com/v1/speed-insights/script.debug.js`;\nconst SCRIPT_URL = `/_vercel/speed-insights/script.js`;\n\n/**\n * Injects the Vercel Speed Insights script into the page head and starts tracking page views. Read more in our [documentation](https://vercel.com/docs/speed-insights).\n * @param [props] - Speed Insights options.\n * @param [props.debug] - Whether to enable debug logging in development. Defaults to `true`.\n * @param [props.beforeSend] - A middleware function to modify events before they are sent. Should return the event object or `null` to cancel the event.\n */\nfunction inject(props: SpeedInsightsProps): {\n setRoute: (route: string) => void;\n} | null {\n if (!isBrowser()) return null;\n\n initQueue();\n\n if (props.beforeSend) {\n window.si?.('beforeSend', props.beforeSend);\n }\n const src =\n props.scriptSrc || (isDevelopment() ? DEV_SCRIPT_URL : SCRIPT_URL);\n\n if (document.head.querySelector(`script[src*=\"${src}\"]`)) return null;\n\n const script = document.createElement('script');\n script.src = src;\n script.defer = true;\n script.dataset.sdkn = packageName;\n script.dataset.sdkv = version;\n\n if (props.sampleRate) {\n script.dataset.sampleRate = props.sampleRate.toString();\n }\n if (props.route) {\n script.dataset.route = props.route;\n }\n if (props.endpoint) {\n script.dataset.endpoint = props.endpoint;\n }\n if (props.token) {\n script.dataset.token = props.token;\n }\n if (isDevelopment() && props.debug === false) {\n script.dataset.debug = 'false';\n }\n\n script.onerror = (): void => {\n const errorMessage = isDevelopment()\n ? 'Please check if any ad blockers are enabled and try again.'\n : 'Be sure to enable Speed Insights for your project and deploy again. See https://vercel.com/docs/speed-insights for more information.';\n\n // eslint-disable-next-line no-console -- Logging is okay here\n console.log(\n `[Vercel Speed Insights] Failed to load script from ${src}. ${errorMessage}`,\n );\n };\n\n document.head.appendChild(script);\n\n return {\n setRoute: (route: string): void => {\n script.dataset.route = route;\n },\n };\n}\n\nexport { inject };\nexport type { SpeedInsightsProps };\n\n// eslint-disable-next-line import/no-default-export -- Allow default export\nexport default {\n inject,\n};\n","'use client';\nimport { useParams, usePathname } from 'next/navigation';\nimport { computeRoute } from '../utils';\n\nexport const useRoute = (): string | null => {\n const params = useParams();\n const path = usePathname();\n\n return computeRoute(path, params);\n};\n"],"mappings":"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","names":["SpeedInsights","import_react","SpeedInsights","React"]}
@@ -1,7 +1,35 @@
1
1
  interface SpeedInsightsProps {
2
- token: string;
2
+ token?: string;
3
3
  sampleRate?: number;
4
+ route?: string;
5
+ beforeSend?: BeforeSendMiddleware;
6
+ debug?: boolean;
7
+ scriptSrc?: string;
8
+ endpoint?: string;
4
9
  }
5
- declare function SpeedInsights({ token, sampleRate }: SpeedInsightsProps): null;
10
+ type EventTypes = 'vital';
11
+ interface Event {
12
+ type: EventTypes;
13
+ url: string;
14
+ }
15
+ type BeforeSendMiddleware = (data: Event) => Event | null | undefined | false;
16
+ interface Functions {
17
+ beforeSend?: BeforeSendMiddleware;
18
+ }
19
+ interface SpeedInsights$1<T extends keyof Functions = keyof Functions> {
20
+ queue: [T, Functions[T]][];
21
+ addAction: (action: T, data: Functions[T]) => void;
22
+ }
23
+ declare global {
24
+ interface Window {
25
+ /** Base interface to track events */
26
+ si?: SpeedInsights$1['addAction'];
27
+ /** Queue for speed insights datapoints, before the library is loaded */
28
+ siq?: SpeedInsights$1['queue'];
29
+ sil?: boolean;
30
+ }
31
+ }
32
+
33
+ declare function SpeedInsights(props: Omit<SpeedInsightsProps, 'route'>): JSX.Element;
6
34
 
7
35
  export { SpeedInsights };
@@ -1,7 +1,35 @@
1
1
  interface SpeedInsightsProps {
2
- token: string;
2
+ token?: string;
3
3
  sampleRate?: number;
4
+ route?: string;
5
+ beforeSend?: BeforeSendMiddleware;
6
+ debug?: boolean;
7
+ scriptSrc?: string;
8
+ endpoint?: string;
4
9
  }
5
- declare function SpeedInsights({ token, sampleRate }: SpeedInsightsProps): null;
10
+ type EventTypes = 'vital';
11
+ interface Event {
12
+ type: EventTypes;
13
+ url: string;
14
+ }
15
+ type BeforeSendMiddleware = (data: Event) => Event | null | undefined | false;
16
+ interface Functions {
17
+ beforeSend?: BeforeSendMiddleware;
18
+ }
19
+ interface SpeedInsights$1<T extends keyof Functions = keyof Functions> {
20
+ queue: [T, Functions[T]][];
21
+ addAction: (action: T, data: Functions[T]) => void;
22
+ }
23
+ declare global {
24
+ interface Window {
25
+ /** Base interface to track events */
26
+ si?: SpeedInsights$1['addAction'];
27
+ /** Queue for speed insights datapoints, before the library is loaded */
28
+ siq?: SpeedInsights$1['queue'];
29
+ sil?: boolean;
30
+ }
31
+ }
32
+
33
+ declare function SpeedInsights(props: Omit<SpeedInsightsProps, 'route'>): JSX.Element;
6
34
 
7
35
  export { SpeedInsights };
@@ -1,116 +1,42 @@
1
1
  "use client";
2
2
 
3
3
  // src/nextjs/index.tsx
4
- import { useCallback, useEffect, useRef } from "react";
4
+ import React from "react";
5
5
 
6
- // src/generic/index.ts
7
- import {
8
- onLCP,
9
- onFID,
10
- onCLS,
11
- onFCP,
12
- onINP,
13
- onTTFB
14
- } from "web-vitals/attribution";
6
+ // src/react/index.tsx
7
+ import { useEffect, useRef } from "react";
8
+
9
+ // package.json
10
+ var name = "@vercel/speed-insights";
11
+ var version = "0.0.1-beta.5";
12
+
13
+ // src/queue.ts
14
+ var initQueue = () => {
15
+ if (window.si)
16
+ return;
17
+ window.si = function a(...params) {
18
+ (window.siq = window.siq || []).push(params);
19
+ };
20
+ };
15
21
 
16
22
  // src/utils.ts
17
- function getConnectionSpeed() {
18
- let speed = "";
19
- if ("connection" in navigator) {
20
- const connection = navigator.connection;
21
- if (connection == null ? void 0 : connection.effectiveType) {
22
- speed = connection.effectiveType;
23
- }
24
- }
25
- return speed;
23
+ function isBrowser() {
24
+ return typeof window !== "undefined";
26
25
  }
27
- var ENDPOINT = "https://vitals.vercel-insights.com/v2/vitals";
28
- function sendBeacon(data) {
29
- const blob = new Blob([JSON.stringify(data)], {
30
- type: "text/plain"
31
- });
26
+ function detectEnvironment() {
32
27
  try {
33
- if ("keepalive" in Request.prototype) {
34
- void fetch(ENDPOINT, {
35
- method: "POST",
36
- body: blob,
37
- keepalive: true,
38
- mode: "no-cors",
39
- credentials: "omit"
40
- });
41
- } else if ("sendBeacon" in navigator) {
42
- navigator.sendBeacon(ENDPOINT, blob);
28
+ const env = process.env.NODE_ENV;
29
+ if (env === "development" || env === "test") {
30
+ return "development";
43
31
  }
44
32
  } catch (e) {
45
33
  }
34
+ return "production";
46
35
  }
47
- function getDomTarget(metric) {
48
- if (metric.name === "CLS") {
49
- return metric.attribution.largestShiftTarget;
50
- }
51
- if (metric.name === "FID") {
52
- return metric.attribution.eventTarget;
53
- }
54
- if (metric.name === "LCP") {
55
- return metric.attribution.element;
56
- }
36
+ function isDevelopment() {
37
+ return detectEnvironment() === "development";
57
38
  }
58
- function cutDecimal(number, decimals) {
59
- if (Number.isInteger(number)) {
60
- return number;
61
- }
62
- const multiplier = Math.pow(10, decimals);
63
- return Math.floor(number * multiplier) / multiplier;
64
- }
65
- function formatMetricValue(metric) {
66
- if (metric.name === "CLS") {
67
- return cutDecimal(metric.value, 4);
68
- }
69
- if (metric.name === "FID") {
70
- return cutDecimal(metric.value, 2);
71
- }
72
- return Math.round(metric.value);
73
- }
74
-
75
- // src/generic/index.ts
76
- function sendVitals(metrics, dsn) {
77
- const speed = getConnectionSpeed();
78
- if (metrics.length === 0)
79
- return;
80
- const payload = {
81
- dsn,
82
- speed,
83
- metrics: metrics.map((metric) => ({
84
- id: metric.id,
85
- type: metric.name,
86
- value: formatMetricValue(metric),
87
- dynamicPath: metric.dynamicPath,
88
- href: window.location.href.replace("http://", "https://"),
89
- // TODO: remove this
90
- attribution: {
91
- target: getDomTarget(metric)
92
- }
93
- }))
94
- };
95
- sendBeacon(payload);
96
- }
97
- function watchMetrics(callback) {
98
- onCLS(callback);
99
- onFID(callback);
100
- onLCP(callback);
101
- onFCP(callback);
102
- onINP(callback);
103
- onTTFB(callback);
104
- }
105
-
106
- // src/nextjs/utils.ts
107
- import { useParams, usePathname } from "next/navigation";
108
- var useDynamicPath = () => {
109
- const params = useParams();
110
- const path = usePathname();
111
- return computePathname(path, params);
112
- };
113
- function computePathname(pathname, pathParams) {
39
+ function computeRoute(pathname, pathParams) {
114
40
  if (pathname === null) {
115
41
  return null;
116
42
  }
@@ -150,41 +76,83 @@ function computePathname(pathname, pathParams) {
150
76
  return result;
151
77
  }
152
78
 
153
- // src/nextjs/index.tsx
154
- function SpeedInsights({ token, sampleRate }) {
155
- const dynamicPath = useDynamicPath();
156
- const vitals = useRef([]);
157
- const flush = useCallback(() => {
158
- if (vitals.current.length > 0) {
159
- if (sampleRate && Math.random() > sampleRate) {
160
- return;
161
- }
162
- const body = vitals.current;
163
- console.log("flushing", body);
164
- sendVitals(body, token);
165
- vitals.current = [];
79
+ // src/generic.ts
80
+ var DEV_SCRIPT_URL = `https://va.vercel-scripts.com/v1/speed-insights/script.debug.js`;
81
+ var SCRIPT_URL = `/_vercel/speed-insights/script.js`;
82
+ function inject(props) {
83
+ var _a;
84
+ if (!isBrowser())
85
+ return null;
86
+ initQueue();
87
+ if (props.beforeSend) {
88
+ (_a = window.si) == null ? void 0 : _a.call(window, "beforeSend", props.beforeSend);
89
+ }
90
+ const src = props.scriptSrc || (isDevelopment() ? DEV_SCRIPT_URL : SCRIPT_URL);
91
+ if (document.head.querySelector(`script[src*="${src}"]`))
92
+ return null;
93
+ const script = document.createElement("script");
94
+ script.src = src;
95
+ script.defer = true;
96
+ script.dataset.sdkn = name;
97
+ script.dataset.sdkv = version;
98
+ if (props.sampleRate) {
99
+ script.dataset.sampleRate = props.sampleRate.toString();
100
+ }
101
+ if (props.route) {
102
+ script.dataset.route = props.route;
103
+ }
104
+ if (props.endpoint) {
105
+ script.dataset.endpoint = props.endpoint;
106
+ }
107
+ if (props.token) {
108
+ script.dataset.token = props.token;
109
+ }
110
+ if (isDevelopment() && props.debug === false) {
111
+ script.dataset.debug = "false";
112
+ }
113
+ script.onerror = () => {
114
+ const errorMessage = isDevelopment() ? "Please check if any ad blockers are enabled and try again." : "Be sure to enable Speed Insights for your project and deploy again. See https://vercel.com/docs/speed-insights for more information.";
115
+ console.log(
116
+ `[Vercel Speed Insights] Failed to load script from ${src}. ${errorMessage}`
117
+ );
118
+ };
119
+ document.head.appendChild(script);
120
+ return {
121
+ setRoute: (route) => {
122
+ script.dataset.route = route;
166
123
  }
167
- }, [sampleRate, vitals.current]);
168
- useEffect(() => {
169
- addEventListener("visibilitychange", flush);
170
- addEventListener("pagehide", flush);
171
- return () => {
172
- removeEventListener("visibilitychange", flush);
173
- removeEventListener("pagehide", flush);
174
- };
175
- }, [flush]);
176
- const reportVital = useCallback(
177
- (metric) => {
178
- vitals.current.push({ ...metric, dynamicPath });
179
- },
180
- [dynamicPath]
181
- );
124
+ };
125
+ }
126
+
127
+ // src/react/index.tsx
128
+ function SpeedInsights(props) {
129
+ const setScriptRoute = useRef(null);
182
130
  useEffect(() => {
183
- watchMetrics(reportVital);
131
+ const script = inject(props);
132
+ setScriptRoute.current = (script == null ? void 0 : script.setRoute) || null;
184
133
  }, []);
134
+ useEffect(() => {
135
+ if (props.route && setScriptRoute.current) {
136
+ setScriptRoute.current(props.route);
137
+ }
138
+ }, [props.route]);
185
139
  return null;
186
140
  }
141
+
142
+ // src/nextjs/utils.ts
143
+ import { useParams, usePathname } from "next/navigation";
144
+ var useRoute = () => {
145
+ const params = useParams();
146
+ const path = usePathname();
147
+ return computeRoute(path, params);
148
+ };
149
+
150
+ // src/nextjs/index.tsx
151
+ function SpeedInsights2(props) {
152
+ const route = useRoute();
153
+ return /* @__PURE__ */ React.createElement(SpeedInsights, { ...route && { route }, ...props });
154
+ }
187
155
  export {
188
- SpeedInsights
156
+ SpeedInsights2 as SpeedInsights
189
157
  };
190
158
  //# sourceMappingURL=index.js.map