@nuxt/hints 1.0.0-alpha.3 → 1.0.0-alpha.4
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/dist/client/200.html +1 -1
- package/dist/client/404.html +1 -1
- package/dist/client/_nuxt/6YZAjlve.js +1 -0
- package/dist/client/_nuxt/BXSELIT7.js +1 -0
- package/dist/client/_nuxt/BgVA9H9k.js +1 -0
- package/dist/client/_nuxt/BuasPzSQ.js +21 -0
- package/dist/client/_nuxt/By0zDdDR.js +6 -0
- package/dist/client/_nuxt/{CeyKylGo.js → C4-GUK1K.js} +3 -3
- package/dist/client/_nuxt/{DE7yhJ9n.js → CHRGnUwv.js} +1 -1
- package/dist/client/_nuxt/{3uZvltmj.js → CIn0yCh1.js} +1 -1
- package/dist/client/_nuxt/CeAnYTQ5.js +1 -0
- package/dist/client/_nuxt/{DyZ7ilof.js → Chg59sI4.js} +1 -1
- package/dist/client/_nuxt/CjPw6jm5.js +1 -0
- package/dist/client/_nuxt/GrcSzlUJ.js +1 -0
- package/dist/client/_nuxt/{BTIAbEX4.js → P-pLD3_d.js} +1 -1
- package/dist/client/_nuxt/{BYW8DJWC.js → Y-og_wyR.js} +1 -1
- package/dist/client/_nuxt/{DxmC8vYz.js → YA1k0SOY.js} +1 -1
- package/dist/client/_nuxt/builds/latest.json +1 -1
- package/dist/client/_nuxt/builds/meta/17377e6a-4112-4616-a57e-0db49b9956bf.json +1 -0
- package/dist/client/_nuxt/error-404.Db9gmKof.css +1 -0
- package/dist/client/_nuxt/error-500.BSnPHzYt.css +1 -0
- package/dist/client/_nuxt/hydration.Dg0tHOnZ.css +1 -0
- package/dist/client/_nuxt/sTshF0tC.js +1 -0
- package/dist/client/hydration/index.html +1 -1
- package/dist/client/index.html +1 -1
- package/dist/client/third-party-scripts/index.html +1 -1
- package/dist/client/web-vitals/index.html +1 -1
- package/dist/module.d.mts +1 -3
- package/dist/module.json +1 -1
- package/dist/module.mjs +60 -24
- package/dist/runtime/core/components/nuxt-island.d.ts +1 -136
- package/dist/runtime/core/plugins/vue-tracer-state.client.d.ts +1 -1
- package/dist/runtime/hydration/component.d.ts +1 -1
- package/dist/runtime/hydration/component.js +1 -2
- package/dist/runtime/hydration/composables.js +16 -26
- package/dist/runtime/hydration/handler.nitro.d.ts +5 -0
- package/dist/runtime/hydration/handler.nitro.js +52 -0
- package/dist/runtime/hydration/plugin.client.d.ts +1 -1
- package/dist/runtime/hydration/sse.nitro.d.ts +2 -0
- package/dist/runtime/hydration/sse.nitro.js +22 -0
- package/dist/runtime/hydration/types.d.ts +29 -0
- package/dist/runtime/hydration/types.js +0 -0
- package/dist/runtime/hydration/utils.d.ts +3 -0
- package/dist/runtime/hydration/utils.js +23 -0
- package/dist/runtime/third-party-scripts/nitro.plugin.js +2 -2
- package/dist/runtime/third-party-scripts/plugin.client.d.ts +1 -1
- package/dist/runtime/third-party-scripts/plugin.client.js +2 -2
- package/dist/runtime/types.d.ts +11 -2
- package/dist/runtime/web-vitals/plugin.client.d.ts +1 -1
- package/package.json +4 -4
- package/dist/client/_nuxt/BAIAvlAa.js +0 -1
- package/dist/client/_nuxt/Ckm7x3qc.js +0 -6
- package/dist/client/_nuxt/CsLEpyV7.js +0 -1
- package/dist/client/_nuxt/CzzNqrSg.js +0 -1
- package/dist/client/_nuxt/DBrXuSAZ.js +0 -1
- package/dist/client/_nuxt/DDotc1jX.js +0 -21
- package/dist/client/_nuxt/REBTOKr5.js +0 -1
- package/dist/client/_nuxt/builds/meta/b0fc6608-9102-4a88-9842-0a2ed6526798.json +0 -1
- package/dist/client/_nuxt/error-404.MLlw4bJt.css +0 -1
- package/dist/client/_nuxt/error-500.CBQQ1PSP.css +0 -1
- package/dist/client/_nuxt/hydration.B5wxUWyr.css +0 -1
- package/dist/client/_nuxt/s2_R2YM5.js +0 -1
|
@@ -1,26 +1,6 @@
|
|
|
1
1
|
import { getCurrentInstance, onMounted } from "vue";
|
|
2
2
|
import { useNuxtApp } from "#imports";
|
|
3
|
-
|
|
4
|
-
if (!html) return "";
|
|
5
|
-
let formatted = "";
|
|
6
|
-
let indent = 0;
|
|
7
|
-
const tags = html.split(/(<\/?[^>]+>)/g);
|
|
8
|
-
for (const tag of tags) {
|
|
9
|
-
if (!tag.trim()) continue;
|
|
10
|
-
if (tag.startsWith("</")) {
|
|
11
|
-
indent--;
|
|
12
|
-
formatted += "\n" + " ".repeat(Math.max(0, indent)) + tag;
|
|
13
|
-
} else if (tag.startsWith("<") && !tag.endsWith("/>") && !tag.includes("<!")) {
|
|
14
|
-
formatted += "\n" + " ".repeat(Math.max(0, indent)) + tag;
|
|
15
|
-
indent++;
|
|
16
|
-
} else if (tag.startsWith("<")) {
|
|
17
|
-
formatted += "\n" + " ".repeat(Math.max(0, indent)) + tag;
|
|
18
|
-
} else {
|
|
19
|
-
formatted += "\n" + " ".repeat(Math.max(0, indent)) + tag.trim();
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
return formatted.trim();
|
|
23
|
-
}
|
|
3
|
+
import { HYDRATION_ROUTE, formatHTML } from "./utils.js";
|
|
24
4
|
export function useHydrationCheck() {
|
|
25
5
|
if (import.meta.server) return;
|
|
26
6
|
const nuxtApp = useNuxtApp();
|
|
@@ -29,16 +9,26 @@ export function useHydrationCheck() {
|
|
|
29
9
|
}
|
|
30
10
|
const instance = getCurrentInstance();
|
|
31
11
|
if (!instance) return;
|
|
32
|
-
const
|
|
12
|
+
const htmlPreHydration = formatHTML(instance.vnode.el?.outerHTML);
|
|
33
13
|
const vnodePrehydration = instance.vnode;
|
|
34
14
|
onMounted(() => {
|
|
35
15
|
const htmlPostHydration = formatHTML(instance.vnode.el?.outerHTML);
|
|
36
|
-
if (
|
|
16
|
+
if (htmlPreHydration !== htmlPostHydration) {
|
|
17
|
+
const payload = {
|
|
18
|
+
htmlPreHydration,
|
|
19
|
+
htmlPostHydration,
|
|
20
|
+
id: globalThis.crypto.randomUUID(),
|
|
21
|
+
componentName: instance.type.name ?? instance.type.displayName ?? instance.type.__name,
|
|
22
|
+
fileLocation: instance.type.__file ?? "unknown"
|
|
23
|
+
};
|
|
37
24
|
nuxtApp.__hints.hydration.push({
|
|
25
|
+
...payload,
|
|
38
26
|
instance,
|
|
39
|
-
vnode: vnodePrehydration
|
|
40
|
-
|
|
41
|
-
|
|
27
|
+
vnode: vnodePrehydration
|
|
28
|
+
});
|
|
29
|
+
$fetch(new URL(HYDRATION_ROUTE, window.location.origin).href, {
|
|
30
|
+
method: "POST",
|
|
31
|
+
body: payload
|
|
42
32
|
});
|
|
43
33
|
console.warn(`[nuxt/hints:hydration] Component ${instance.type.name ?? instance.type.displayName ?? instance.type.__name ?? instance.type.__file} seems to have different html pre and post-hydration. Please make sure you don't have any hydration issue.`);
|
|
44
34
|
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { createError, defineEventHandler, readBody, setResponseStatus } from "h3";
|
|
2
|
+
import { useNitroApp } from "nitropack/runtime";
|
|
3
|
+
const hydrationMismatches = [];
|
|
4
|
+
export default defineEventHandler((event) => {
|
|
5
|
+
switch (event.method) {
|
|
6
|
+
case "GET":
|
|
7
|
+
return getHandler();
|
|
8
|
+
case "POST":
|
|
9
|
+
return postHandler(event);
|
|
10
|
+
case "DELETE":
|
|
11
|
+
return deleteHandler(event);
|
|
12
|
+
default:
|
|
13
|
+
throw createError({ statusCode: 405, statusMessage: "Method Not Allowed" });
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
function getHandler() {
|
|
17
|
+
return {
|
|
18
|
+
mismatches: hydrationMismatches
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
async function postHandler(event) {
|
|
22
|
+
const body = await readBody(event);
|
|
23
|
+
assertPayload(body);
|
|
24
|
+
const nitro = useNitroApp();
|
|
25
|
+
const payload = { id: body.id, htmlPreHydration: body.htmlPreHydration, htmlPostHydration: body.htmlPostHydration, componentName: body.componentName, fileLocation: body.fileLocation };
|
|
26
|
+
hydrationMismatches.push(payload);
|
|
27
|
+
if (hydrationMismatches.length > 20) {
|
|
28
|
+
hydrationMismatches.shift();
|
|
29
|
+
}
|
|
30
|
+
nitro.hooks.callHook("hints:hydration:mismatch", payload);
|
|
31
|
+
setResponseStatus(event, 201);
|
|
32
|
+
}
|
|
33
|
+
async function deleteHandler(event) {
|
|
34
|
+
const nitro = useNitroApp();
|
|
35
|
+
const body = await readBody(event);
|
|
36
|
+
if (!body || !Array.isArray(body.id)) {
|
|
37
|
+
throw createError({ statusCode: 400, statusMessage: "Invalid payload" });
|
|
38
|
+
}
|
|
39
|
+
for (const id of body.id) {
|
|
40
|
+
const index = hydrationMismatches.findIndex((m) => m.id === id);
|
|
41
|
+
if (index !== -1) {
|
|
42
|
+
hydrationMismatches.splice(index, 1);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
nitro.hooks.callHook("hints:hydration:cleared", { id: body.id });
|
|
46
|
+
setResponseStatus(event, 204);
|
|
47
|
+
}
|
|
48
|
+
function assertPayload(body) {
|
|
49
|
+
if (typeof body !== "object" || typeof body.id !== "string" || body.htmlPreHydration !== void 0 && typeof body.htmlPreHydration !== "string" || body.htmlPostHydration !== void 0 && typeof body.htmlPostHydration !== "string" || typeof body.componentName !== "string" || typeof body.fileLocation !== "string") {
|
|
50
|
+
throw createError({ statusCode: 400, statusMessage: "Invalid payload" });
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
declare const _default:
|
|
1
|
+
declare const _default: any;
|
|
2
2
|
export default _default;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { createEventStream, defineEventHandler } from "h3";
|
|
2
|
+
import { useNitroApp } from "nitropack/runtime";
|
|
3
|
+
export default defineEventHandler((event) => {
|
|
4
|
+
const nitro = useNitroApp();
|
|
5
|
+
const eventStream = createEventStream(event);
|
|
6
|
+
const unsubs = [nitro.hooks.hook("hints:hydration:mismatch", (mismatch) => {
|
|
7
|
+
eventStream.push({
|
|
8
|
+
data: JSON.stringify(mismatch),
|
|
9
|
+
event: "hints:hydration:mismatch"
|
|
10
|
+
});
|
|
11
|
+
}), nitro.hooks.hook("hints:hydration:cleared", async (payload) => {
|
|
12
|
+
eventStream.push({
|
|
13
|
+
data: JSON.stringify(payload.id),
|
|
14
|
+
event: "hints:hydration:cleared"
|
|
15
|
+
});
|
|
16
|
+
})];
|
|
17
|
+
eventStream.onClosed(async () => {
|
|
18
|
+
unsubs.forEach((unsub) => unsub());
|
|
19
|
+
await eventStream.close();
|
|
20
|
+
});
|
|
21
|
+
return eventStream.send();
|
|
22
|
+
});
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { EventStreamMessage } from 'h3';
|
|
2
|
+
import type { ComponentInternalInstance, VNode } from 'vue';
|
|
3
|
+
export interface HydrationMismatchPayload {
|
|
4
|
+
id: string;
|
|
5
|
+
componentName?: string;
|
|
6
|
+
fileLocation: string;
|
|
7
|
+
htmlPreHydration: string;
|
|
8
|
+
htmlPostHydration: string;
|
|
9
|
+
}
|
|
10
|
+
export interface LocalHydrationMismatch extends HydrationMismatchPayload {
|
|
11
|
+
instance: ComponentInternalInstance;
|
|
12
|
+
vnode: VNode;
|
|
13
|
+
}
|
|
14
|
+
export interface HydrationMismatchResponse {
|
|
15
|
+
mismatches: HydrationMismatchPayload[];
|
|
16
|
+
}
|
|
17
|
+
export interface HydrationDeleteSSE extends EventStreamMessage {
|
|
18
|
+
event: 'hydration:cleared';
|
|
19
|
+
data: string;
|
|
20
|
+
}
|
|
21
|
+
export interface HydrationNewSSE extends EventStreamMessage {
|
|
22
|
+
event: 'hydration:mismatch';
|
|
23
|
+
/**
|
|
24
|
+
* Stringified HydrationMismatchPayload
|
|
25
|
+
* @see HydrationMismatchPayload
|
|
26
|
+
*/
|
|
27
|
+
data: string;
|
|
28
|
+
}
|
|
29
|
+
export type HydrationSSEPayload = HydrationDeleteSSE | HydrationNewSSE;
|
|
File without changes
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export const HYDRATION_ROUTE = "/__nuxt_hydration";
|
|
2
|
+
export const HYDRATION_SSE_ROUTE = "/__nuxt_hydration/sse";
|
|
3
|
+
export function formatHTML(html) {
|
|
4
|
+
if (!html) return "";
|
|
5
|
+
let formatted = "";
|
|
6
|
+
let indent = 0;
|
|
7
|
+
const tags = html.split(/(<\/?[^>]+>)/g);
|
|
8
|
+
for (const tag of tags) {
|
|
9
|
+
if (!tag.trim()) continue;
|
|
10
|
+
if (tag.startsWith("</")) {
|
|
11
|
+
indent--;
|
|
12
|
+
formatted += "\n" + " ".repeat(Math.max(0, indent)) + tag;
|
|
13
|
+
} else if (tag.startsWith("<") && !tag.endsWith("/>") && !tag.includes("<!")) {
|
|
14
|
+
formatted += "\n" + " ".repeat(Math.max(0, indent)) + tag;
|
|
15
|
+
indent++;
|
|
16
|
+
} else if (tag.startsWith("<")) {
|
|
17
|
+
formatted += "\n" + " ".repeat(Math.max(0, indent)) + tag;
|
|
18
|
+
} else {
|
|
19
|
+
formatted += "\n" + " ".repeat(Math.max(0, indent)) + tag.trim();
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return formatted.trim();
|
|
23
|
+
}
|
|
@@ -36,9 +36,9 @@ function __hints_TPC_saveTime(script, startTime) {
|
|
|
36
36
|
for (const script of document.scripts) {
|
|
37
37
|
if (script.src && !script.src.startsWith(window.location.origin)) {
|
|
38
38
|
script.__hints_TPC_start_time = window.__hints_TPC_start_time || Date.now();
|
|
39
|
-
script.
|
|
39
|
+
script.addEventListener('load', () => {
|
|
40
40
|
__hints_TPC_saveTime(script, script.__hints_TPC_start_time);
|
|
41
|
-
}
|
|
41
|
+
})
|
|
42
42
|
__hints_TPC_saveTime(script, script.__hints_TPC_start_time);
|
|
43
43
|
}
|
|
44
44
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
declare const _default:
|
|
1
|
+
declare const _default: any;
|
|
2
2
|
export default _default;
|
|
@@ -70,10 +70,10 @@ export default defineNuxtPlugin({
|
|
|
70
70
|
}
|
|
71
71
|
nuxtApp.callHook("hints:scripts:added", script).then(() => {
|
|
72
72
|
if (!script.loaded) {
|
|
73
|
-
script.
|
|
73
|
+
script.addEventListener("load", () => {
|
|
74
74
|
window.__hints_TPC_saveTime(script, script.__hints_TPC_start_time);
|
|
75
75
|
nuxtApp.callHook("hints:scripts:loaded", script);
|
|
76
|
-
};
|
|
76
|
+
});
|
|
77
77
|
} else {
|
|
78
78
|
window.__hints_TPC_saveTime(script, script.__hints_TPC_start_time);
|
|
79
79
|
nuxtApp.callHook("hints:scripts:loaded", script);
|
package/dist/runtime/types.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { VNode, Ref } from 'vue'
|
|
2
2
|
import type { LCPMetricWithAttribution, INPMetricWithAttribution, CLSMetricWithAttribution } from 'web-vitals/attribution'
|
|
3
|
+
import type { HydrationMismatchPayload, LocalHydrationMismatch } from './hydration/types'
|
|
3
4
|
|
|
4
5
|
declare global {
|
|
5
6
|
interface Window {
|
|
@@ -19,6 +20,7 @@ declare global {
|
|
|
19
20
|
__vnode?: VNode
|
|
20
21
|
}
|
|
21
22
|
}
|
|
23
|
+
|
|
22
24
|
declare module '#app' {
|
|
23
25
|
interface RuntimeNuxtHooks {
|
|
24
26
|
'hints:scripts:added': (script: HTMLScriptElement) => void
|
|
@@ -33,7 +35,7 @@ declare module '#app' {
|
|
|
33
35
|
interface NuxtApp {
|
|
34
36
|
__hints_tpc: Ref<{ element: HTMLScriptElement, loaded: boolean }[]>
|
|
35
37
|
__hints: {
|
|
36
|
-
hydration:
|
|
38
|
+
hydration: LocalHydrationMismatch[]
|
|
37
39
|
webvitals: {
|
|
38
40
|
lcp: Ref<LCPMetricWithAttribution[]>
|
|
39
41
|
inp: Ref<INPMetricWithAttribution[]>
|
|
@@ -45,4 +47,11 @@ declare module '#app' {
|
|
|
45
47
|
}
|
|
46
48
|
}
|
|
47
49
|
|
|
50
|
+
declare module 'nitropack' {
|
|
51
|
+
interface NitroRuntimeHooks {
|
|
52
|
+
'hints:hydration:mismatch': (payload: HydrationMismatchPayload) => void
|
|
53
|
+
'hints:hydration:cleared': (payload: { id: string[] }) => void
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
48
57
|
export {}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nuxt/hints",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.4",
|
|
4
4
|
"description": "Nuxt module that shows hints for aspects of your application such as Performance, Security, and more!",
|
|
5
5
|
"repository": "https://github.com/nuxt/hints",
|
|
6
6
|
"homepage": "https://github.com/nuxt/hints",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"knitwork": "^1.3.0",
|
|
28
28
|
"magic-string": "^0.30.19",
|
|
29
29
|
"nitropack": "^2.12.6",
|
|
30
|
-
"oxc-parser": "^0.
|
|
30
|
+
"oxc-parser": "^0.103.0",
|
|
31
31
|
"shiki": "^3.13.0",
|
|
32
32
|
"sirv": "^3.0.2",
|
|
33
33
|
"unplugin": "^2.3.10",
|
|
@@ -48,11 +48,11 @@
|
|
|
48
48
|
"diff": "^8.0.2",
|
|
49
49
|
"eslint": "^9.36.0",
|
|
50
50
|
"happy-dom": "^20.0.10",
|
|
51
|
-
"pkg-pr-new": "0.0.
|
|
51
|
+
"pkg-pr-new": "0.0.62",
|
|
52
52
|
"rimraf": "^6.0.1",
|
|
53
53
|
"sass-embedded": "^1.93.3",
|
|
54
54
|
"vitest": "^4.0.0",
|
|
55
|
-
"@nuxt/hints": "^1.0.0-alpha.
|
|
55
|
+
"@nuxt/hints": "^1.0.0-alpha.4"
|
|
56
56
|
},
|
|
57
57
|
"scripts": {
|
|
58
58
|
"client:build": "nuxi generate client",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import g from"./CeyKylGo.js";import{_ as h,c as f,o,r as k,g as w,j as N,b as e,w as s,a as t,k as m,l as u,m as n,d as p,t as x}from"./Ckm7x3qc.js";import{u as C,a as V,_ as $}from"./CzzNqrSg.js";import{_ as B}from"./s2_R2YM5.js";import{_ as S}from"./REBTOKr5.js";const j={},H={class:"n-badge"};function L(d,r){return o(),f("span",H,[k(d.$slots,"default")])}const z=Object.assign(h(j,[["render",L]]),{__name:"NBadge"}),I={class:"grid grid-cols-1 md:grid-cols-3 gap-3 p-4"},P={class:"flex items-center gap-3 min-w-0"},T={class:"flex items-center gap-3 min-w-0"},R=w({__name:"index",setup(d){const{allMetrics:r}=C(),{hydration:b}=V(),_=N(()=>b.length||0);return(W,a)=>{const l=g,v=z,c=$,i=B,y=S;return o(),f("div",I,[e(i,{to:"/web-vitals",class:"block"},{default:s(()=>[e(c,{class:"flex items-center justify-between p-4 hover:border-neutral-400 dark:hover:border-neutral-500"},{default:s(()=>[t("div",P,[e(l,{name:"material-symbols:monitoring",class:"text-xl text-blue-500"}),a[0]||(a[0]=t("div",{class:"min-w-0"},[t("div",{class:"text-sm font-medium truncate"}," Web Vitals "),t("div",{class:"text-xs text-neutral-500"}," LCP / INP / CLS ")],-1))]),n(r).length?(o(),m(v,{key:0},{default:s(()=>[p(x(n(r).length)+" issues ",1)]),_:1})):u("",!0)]),_:1})]),_:1}),e(i,{to:"/hydration",class:"block"},{default:s(()=>[e(c,{class:"flex items-center justify-between p-4 hover:border-neutral-400 dark:hover:border-neutral-500"},{default:s(()=>[t("div",T,[e(l,{name:"material-symbols:water-full",class:"text-xl text-cyan-500"}),a[1]||(a[1]=t("div",{class:"min-w-0"},[t("div",{class:"text-sm font-medium truncate"}," Hydration "),t("div",{class:"text-xs text-neutral-500"}," SSR vs client diffs ")],-1))]),n(_)?(o(),m(y,{key:0,size:"small",type:"error",bordered:!1},{default:s(()=>[p(x(n(_))+" issues ",1)]),_:1})):u("",!0)]),_:1})]),_:1}),e(i,{to:"/third-party-scripts",class:"block"},{default:s(()=>[e(c,{class:"p-4 flex items-center gap-3 hover:border-neutral-400 dark:hover:border-neutral-500"},{default:s(()=>[e(l,{name:"material-symbols:extension",class:"text-xl text-violet-500"}),a[2]||(a[2]=t("div",{class:"min-w-0"},[t("div",{class:"text-sm font-medium truncate"}," Third party scripts "),t("div",{class:"text-xs text-neutral-500"}," Analyze third-party scripts speed. ")],-1))]),_:1})]),_:1})])}}});export{R as default};
|