import type { MiddlewareHandler } from 'astro'; /** * Middleware which adds the web vitals `` tag to each page’s ``. * * @example * */ export const onRequest: MiddlewareHandler = async ({ params, url }, next) => { const response = await next(); const contentType = response.headers.get('Content-Type'); if (contentType !== 'text/html') return response; const webVitalsMetaTag = getMetaTag(url, params); return new Response( response.body ?.pipeThrough(new TextDecoderStream()) .pipeThrough(HeadInjectionTransformStream(webVitalsMetaTag)) .pipeThrough(new TextEncoderStream()), response ); }; /** TransformStream which injects the passed HTML just before the closing tag. */ function HeadInjectionTransformStream(htmlToInject: string) { let hasInjected = false; return new TransformStream({ transform: (chunk, controller) => { if (!hasInjected) { const headCloseIndex = chunk.indexOf(''); if (headCloseIndex > -1) { chunk = chunk.slice(0, headCloseIndex) + htmlToInject + chunk.slice(headCloseIndex); hasInjected = true; } } controller.enqueue(chunk); }, }); } /** Get a `` tag to identify the current Astro route. */ function getMetaTag(url: URL, params: Record) { let route = url.pathname; for (const [key, value] of Object.entries(params)) { if (value) route = route.replace(value, `[${key}]`); } route = miniEncodeAttribute(stripTrailingSlash(route)); return ``; } function stripTrailingSlash(str: string) { return str.length > 1 && str.at(-1) === '/' ? str.slice(0, -1) : str; } function miniEncodeAttribute(str: string) { return str .replaceAll('&', '&') .replaceAll('<', '<') .replaceAll('>', '>') .replaceAll('"', '"'); }