@vercel/speed-insights
Advanced tools
Comparing version 0.0.1-beta.2 to 0.0.1-beta.3
interface SpeedInsightsProps { | ||
token: string; | ||
token?: string; | ||
sampleRate?: number; | ||
beforeSend?: BeforeSendMiddleware; | ||
debug?: boolean; | ||
dynamicPath?: string; | ||
scriptSrc?: string; | ||
endpoint?: string; | ||
} | ||
declare function SpeedInsights({ token, sampleRate }: SpeedInsightsProps): null; | ||
type EventTypes = 'vital'; | ||
interface Event { | ||
type: EventTypes; | ||
url: string; | ||
} | ||
type BeforeSendMiddleware = (data: Event) => Event | null | undefined | false; | ||
interface Functions { | ||
beforeSend?: BeforeSendMiddleware; | ||
} | ||
interface SpeedInsights$1<T extends keyof Functions = keyof Functions> { | ||
queue: [T, Functions[T]][]; | ||
addAction: (action: T, data: Functions[T]) => void; | ||
} | ||
declare global { | ||
interface Window { | ||
/** Base interface to track events */ | ||
si?: SpeedInsights$1['addAction']; | ||
/** Queue for speed insights datapoints, before the library is loaded */ | ||
siq?: SpeedInsights$1['queue']; | ||
sil?: boolean; | ||
} | ||
} | ||
declare function SpeedInsights(props: Omit<SpeedInsightsProps, 'dynamicPath'>): JSX.Element; | ||
export { SpeedInsights }; |
"use client"; | ||
// src/nextjs/index.tsx | ||
import { useCallback, useEffect, useRef } from "react"; | ||
import React from "react"; | ||
// src/generic/index.ts | ||
import { | ||
onLCP, | ||
onFID, | ||
onCLS, | ||
onFCP, | ||
onINP, | ||
onTTFB | ||
} from "web-vitals/attribution"; | ||
// src/react/index.tsx | ||
import { useEffect, useRef } from "react"; | ||
// package.json | ||
var name = "@vercel/speed-insights"; | ||
var version = "0.0.1-beta.3"; | ||
// src/queue.ts | ||
var initQueue = () => { | ||
if (window.si) | ||
return; | ||
window.si = function a(...params) { | ||
(window.siq = window.siq || []).push(params); | ||
}; | ||
}; | ||
// src/utils.ts | ||
function getConnectionSpeed() { | ||
let speed = ""; | ||
if ("connection" in navigator) { | ||
const connection = navigator.connection; | ||
if (connection == null ? void 0 : connection.effectiveType) { | ||
speed = connection.effectiveType; | ||
} | ||
} | ||
return speed; | ||
function isBrowser() { | ||
return typeof window !== "undefined"; | ||
} | ||
var ENDPOINT = "https://vitals.vercel-insights.com/v2/vitals"; | ||
function sendBeacon(data) { | ||
const blob = new Blob([JSON.stringify(data)], { | ||
type: "text/plain" | ||
}); | ||
function detectEnvironment() { | ||
try { | ||
if ("keepalive" in Request.prototype) { | ||
void fetch(ENDPOINT, { | ||
method: "POST", | ||
body: blob, | ||
keepalive: true, | ||
mode: "no-cors", | ||
credentials: "omit" | ||
}); | ||
} else if ("sendBeacon" in navigator) { | ||
navigator.sendBeacon(ENDPOINT, blob); | ||
const env = process.env.NODE_ENV; | ||
if (env === "development" || env === "test") { | ||
return "development"; | ||
} | ||
} catch (e) { | ||
} | ||
return "production"; | ||
} | ||
function getDomTarget(metric) { | ||
if (metric.name === "CLS") { | ||
return metric.attribution.largestShiftTarget; | ||
function isDevelopment() { | ||
return detectEnvironment() === "development"; | ||
} | ||
// src/generic.ts | ||
var SCRIPT_URL = `/_vercel/speed-insights`; | ||
var SCRIPT_PROD_NAME = "script.js"; | ||
var SCRIPT_DEBUG_NAME = "script.debug.js"; | ||
function inject(props) { | ||
var _a; | ||
if (!isBrowser()) | ||
return null; | ||
initQueue(); | ||
if (props.beforeSend) { | ||
(_a = window.si) == null ? void 0 : _a.call(window, "beforeSend", props.beforeSend); | ||
} | ||
if (metric.name === "FID") { | ||
return metric.attribution.eventTarget; | ||
const src = props.scriptSrc || `${SCRIPT_URL}/${isDevelopment() ? SCRIPT_DEBUG_NAME : SCRIPT_PROD_NAME}`; | ||
if (document.head.querySelector(`script[src*="${src}"]`)) | ||
return null; | ||
const script = document.createElement("script"); | ||
script.src = src; | ||
script.defer = true; | ||
script.setAttribute("data-sdkn", name); | ||
script.setAttribute("data-sdkv", version); | ||
if (props.sampleRate) { | ||
script.setAttribute("data-sample-rate", props.sampleRate.toString()); | ||
} | ||
if (metric.name === "LCP") { | ||
return metric.attribution.element; | ||
if (props.dynamicPath) { | ||
script.setAttribute("data-dynamic-path", props.dynamicPath); | ||
} | ||
} | ||
function cutDecimal(number, decimals) { | ||
if (Number.isInteger(number)) { | ||
return number; | ||
if (props.endpoint) { | ||
script.setAttribute("data-endpoint", props.endpoint); | ||
} | ||
const multiplier = Math.pow(10, decimals); | ||
return Math.floor(number * multiplier) / multiplier; | ||
} | ||
function formatMetricValue(metric) { | ||
if (metric.name === "CLS") { | ||
return cutDecimal(metric.value, 4); | ||
if (props.token) { | ||
script.setAttribute("data-token", props.token); | ||
} | ||
if (metric.name === "FID") { | ||
return cutDecimal(metric.value, 2); | ||
if (isDevelopment() && props.debug === false) { | ||
script.setAttribute("data-debug", "false"); | ||
} | ||
return Math.round(metric.value); | ||
script.onerror = () => { | ||
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."; | ||
console.log( | ||
`[Vercel Speed Insights] Failed to load script from ${src}. ${errorMessage}` | ||
); | ||
}; | ||
document.head.appendChild(script); | ||
return { | ||
setDynamicPath: (path) => { | ||
script.dataset.dynamicPath = path; | ||
} | ||
}; | ||
} | ||
// src/generic/index.ts | ||
function sendVitals(metrics, dsn) { | ||
const speed = getConnectionSpeed(); | ||
if (metrics.length === 0) | ||
return; | ||
const payload = { | ||
dsn, | ||
speed, | ||
metrics: metrics.map((metric) => ({ | ||
id: metric.id, | ||
type: metric.name, | ||
value: formatMetricValue(metric), | ||
dynamicPath: metric.dynamicPath, | ||
href: window.location.href.replace("http://", "https://"), | ||
// TODO: remove this | ||
attribution: { | ||
target: getDomTarget(metric) | ||
} | ||
})) | ||
}; | ||
sendBeacon(payload); | ||
// src/react/index.tsx | ||
function SpeedInsights(props) { | ||
const scriptDynamicPath = useRef(null); | ||
useEffect(() => { | ||
const script = inject(props); | ||
scriptDynamicPath.current = (script == null ? void 0 : script.setDynamicPath) || null; | ||
}, []); | ||
useEffect(() => { | ||
if (props.dynamicPath && scriptDynamicPath.current) { | ||
scriptDynamicPath.current(props.dynamicPath); | ||
} | ||
}, [props.dynamicPath]); | ||
return null; | ||
} | ||
function watchMetrics(callback) { | ||
onCLS(callback); | ||
onFID(callback); | ||
onLCP(callback); | ||
onFCP(callback); | ||
onINP(callback); | ||
onTTFB(callback); | ||
} | ||
@@ -154,38 +152,9 @@ // src/nextjs/utils.ts | ||
// src/nextjs/index.tsx | ||
function SpeedInsights({ token, sampleRate }) { | ||
function SpeedInsights2(props) { | ||
const dynamicPath = useDynamicPath(); | ||
const vitals = useRef([]); | ||
const flush = useCallback(() => { | ||
if (vitals.current.length > 0) { | ||
if (sampleRate && Math.random() > sampleRate) { | ||
return; | ||
} | ||
const body = vitals.current; | ||
console.log("flushing", body); | ||
sendVitals(body, token); | ||
vitals.current = []; | ||
} | ||
}, [sampleRate, vitals.current]); | ||
useEffect(() => { | ||
addEventListener("visibilitychange", flush); | ||
addEventListener("pagehide", flush); | ||
return () => { | ||
removeEventListener("visibilitychange", flush); | ||
removeEventListener("pagehide", flush); | ||
}; | ||
}, [flush]); | ||
const reportVital = useCallback( | ||
(metric) => { | ||
vitals.current.push({ ...metric, dynamicPath }); | ||
}, | ||
[dynamicPath] | ||
); | ||
useEffect(() => { | ||
watchMetrics(reportVital); | ||
}, []); | ||
return null; | ||
return /* @__PURE__ */ React.createElement(SpeedInsights, { ...dynamicPath && { dynamicPath }, ...props }); | ||
} | ||
export { | ||
SpeedInsights | ||
SpeedInsights2 as SpeedInsights | ||
}; | ||
//# sourceMappingURL=index.js.map |
{ | ||
"name": "@vercel/speed-insights", | ||
"version": "0.0.1-beta.2", | ||
"version": "0.0.1-beta.3", | ||
"description": "Speed Insights is a tool for measuring web performance and providing suggestions for improvement.", | ||
@@ -43,5 +43,2 @@ "keywords": [ | ||
}, | ||
"dependencies": { | ||
"web-vitals": "^3.4.0" | ||
}, | ||
"devDependencies": { | ||
@@ -48,0 +45,0 @@ "@swc/core": "^1.3.82", |
@@ -1,12 +0,12 @@ | ||
/* eslint-disable -- We want to log here */ | ||
import fs from 'fs'; | ||
import path from 'path'; | ||
/* eslint-disable no-undef -- Allow the use `process` */ | ||
/* eslint-disable no-console -- Allow the use of `console` */ | ||
import fs from 'node:fs'; | ||
import path from 'node:path'; | ||
const customPath = process.argv[2]; | ||
const projectDir = customPath || path.resolve(process.cwd()); | ||
// Check .env.local for the presence of the analyticsId key | ||
function checkAnalyticsIdInEnv() { | ||
// Check .env files for the presence of the analyticsId key | ||
function findEnvFileWithAnalyticsId() { | ||
const files = ['.env.local', '.env.development.local', '.env']; | ||
const projectDir = customPath || path.resolve(process.cwd()); | ||
const envFile = files.find((file) => { | ||
@@ -26,6 +26,3 @@ const envPath = path.join(projectDir, file); | ||
function isAnalyticsIdInNextConfig() { | ||
const projectDir = customPath || path.resolve(process.cwd()); | ||
const jsConfigPath = path.join(projectDir, 'next.config.js'); | ||
const mjsConfigPath = path.join(projectDir, 'next.config.mjs'); | ||
function isSpeedInsightsInstalled() { | ||
const packageJsonPath = path.join(projectDir, 'package.json'); | ||
@@ -35,3 +32,3 @@ | ||
console.error('Error: package.json not found in the current directory.'); | ||
return; | ||
return false; | ||
} | ||
@@ -43,12 +40,11 @@ | ||
if (!packageJson.dependencies) { | ||
return; | ||
return false; | ||
} | ||
const hasSpeedInsightsInstalled = | ||
packageJson.dependencies['@vercel/speed-insights']; | ||
return Boolean(packageJson.dependencies['@vercel/speed-insights']); | ||
} | ||
if (!hasSpeedInsightsInstalled) { | ||
// Has no speed-insights installed, so no need to check for analyticsId | ||
return; | ||
} | ||
function isAnalyticsIdInNextConfig() { | ||
const jsConfigPath = path.join(projectDir, 'next.config.js'); | ||
const mjsConfigPath = path.join(projectDir, 'next.config.mjs'); | ||
@@ -70,16 +66,25 @@ let configFile; | ||
const isInConfig = isAnalyticsIdInNextConfig(); | ||
const envFile = checkAnalyticsIdInEnv(); | ||
function main() { | ||
if (!isSpeedInsightsInstalled()) { | ||
// No @vercel/speed-insights installed, we don't need to continue | ||
return; | ||
} | ||
if (isInConfig) { | ||
console.warn( | ||
'\x1b[31m', | ||
`Please remove 'analyticsId' from your next.config.js file.`, | ||
); | ||
const isInConfig = isAnalyticsIdInNextConfig(); | ||
const envFile = findEnvFileWithAnalyticsId(); | ||
if (isInConfig) { | ||
console.warn( | ||
'\x1b[31m', | ||
`Please remove 'analyticsId' from your next.config.js file.`, | ||
); | ||
} | ||
if (envFile) { | ||
console.log( | ||
'\x1b[31m', | ||
`Please remove 'VERCEL_ANALYTICS_ID' from your ${envFile} file.`, | ||
); | ||
} | ||
} | ||
if (envFile) { | ||
console.log( | ||
'\x1b[31m', | ||
`Please remove 'VERCEL_ANALYTICS_ID' from your ${envFile} file.`, | ||
); | ||
} | ||
main(); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
58078
0
0
494
3
- Removedweb-vitals@^3.4.0
- Removedweb-vitals@3.5.2(transitive)