@nuxt/hints 0.0.0 → 1.0.0-alpha.10
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/LICENSE +21 -0
- package/README.md +140 -0
- package/dist/client/200.html +1 -0
- package/dist/client/404.html +1 -0
- package/dist/client/_nuxt/2EtD6e53.js +1 -0
- package/dist/client/_nuxt/32ctXXKs.js +1 -0
- package/dist/client/_nuxt/3e1v2bzS.js +1 -0
- package/dist/client/_nuxt/5X7smno1.js +1 -0
- package/dist/client/_nuxt/5i3qLPDT.js +1 -0
- package/dist/client/_nuxt/B0m2ddpp.js +1 -0
- package/dist/client/_nuxt/B1dDrJ26.js +1 -0
- package/dist/client/_nuxt/B5Mb093_.js +1 -0
- package/dist/client/_nuxt/B6aJPvgy.js +1 -0
- package/dist/client/_nuxt/B7mTdjB0.js +1 -0
- package/dist/client/_nuxt/BA47KaF1.js +1 -0
- package/dist/client/_nuxt/BD7vbABK.js +1 -0
- package/dist/client/_nuxt/BEDo0Tqx.js +1 -0
- package/dist/client/_nuxt/BGJmEYvX.js +1 -0
- package/dist/client/_nuxt/BIGW1oBm.js +1 -0
- package/dist/client/_nuxt/BLmx8bSh.js +1 -0
- package/dist/client/_nuxt/BLtJtn59.js +1 -0
- package/dist/client/_nuxt/BN7gUcg9.js +1 -0
- package/dist/client/_nuxt/BPQ3VLAy.js +1 -0
- package/dist/client/_nuxt/BUw7H-hv.js +1 -0
- package/dist/client/_nuxt/BXkSAIEj.js +1 -0
- package/dist/client/_nuxt/BchVSmrD.js +6 -0
- package/dist/client/_nuxt/BfHTSMKl.js +1 -0
- package/dist/client/_nuxt/BfjtVDDH.js +1 -0
- package/dist/client/_nuxt/BgDCqdQA.js +1 -0
- package/dist/client/_nuxt/Bkuqu6BP.js +1 -0
- package/dist/client/_nuxt/Bp3cYrEr.js +1 -0
- package/dist/client/_nuxt/Br6cN0cg.js +1 -0
- package/dist/client/_nuxt/BthQWCQV.js +1 -0
- package/dist/client/_nuxt/Buea-lGh.js +1 -0
- package/dist/client/_nuxt/Bw305WKR.js +1 -0
- package/dist/client/_nuxt/Bxupbja9.js +4 -0
- package/dist/client/_nuxt/BygCkY0G.js +1 -0
- package/dist/client/_nuxt/Byy-EI8A.js +1 -0
- package/dist/client/_nuxt/BzJJZx-M.js +1 -0
- package/dist/client/_nuxt/C39BiMTA.js +1 -0
- package/dist/client/_nuxt/C3Wv6jpd.js +1 -0
- package/dist/client/_nuxt/C3mMm8J8.js +1 -0
- package/dist/client/_nuxt/C4gqWexZ.js +1 -0
- package/dist/client/_nuxt/C8M2exoo.js +1 -0
- package/dist/client/_nuxt/C9dUb6Cb.js +1 -0
- package/dist/client/_nuxt/C9oPPf7i.js +1 -0
- package/dist/client/_nuxt/C9tS-k6U.js +1 -0
- package/dist/client/_nuxt/CD8AGNRT.js +1 -0
- package/dist/client/_nuxt/CDVJQ6XC.js +1 -0
- package/dist/client/_nuxt/CFHQjOhq.js +1 -0
- package/dist/client/_nuxt/CG6Dc4jp.js +1 -0
- package/dist/client/_nuxt/CH1njM8p.js +1 -0
- package/dist/client/_nuxt/CMTm3GFP.js +1 -0
- package/dist/client/_nuxt/COt5Ahok.js +1 -0
- package/dist/client/_nuxt/CS3Unz2-.js +1 -0
- package/dist/client/_nuxt/CTRr51gU.js +1 -0
- package/dist/client/_nuxt/CVO1_9PV.js +1 -0
- package/dist/client/_nuxt/CVdnzihN.js +1 -0
- package/dist/client/_nuxt/CW8IKDeL.js +1 -0
- package/dist/client/_nuxt/CXZktZb0.js +1 -0
- package/dist/client/_nuxt/CXtECtnM.js +1 -0
- package/dist/client/_nuxt/CYsAdtH9.js +1 -0
- package/dist/client/_nuxt/CafNBF8u.js +1 -0
- package/dist/client/_nuxt/CbfX1IO0.js +1 -0
- package/dist/client/_nuxt/Cc68jesL.js +1 -0
- package/dist/client/_nuxt/CfQXZHmo.js +1 -0
- package/dist/client/_nuxt/Cj5Yp3dK.js +1 -0
- package/dist/client/_nuxt/CkXjmgJE.js +1 -0
- package/dist/client/_nuxt/Cl0AqbOI.js +1 -0
- package/dist/client/_nuxt/Cm3UrAx6.js +1 -0
- package/dist/client/_nuxt/CmIQRyeF.js +1 -0
- package/dist/client/_nuxt/Cmh6b_Ma.js +1 -0
- package/dist/client/_nuxt/Cn-bp-IR.js +1 -0
- package/dist/client/_nuxt/CnnebwVN.js +1 -0
- package/dist/client/_nuxt/Cp-IABpG.js +1 -0
- package/dist/client/_nuxt/Csfq5Kiy.js +1 -0
- package/dist/client/_nuxt/CufHLc7y.js +1 -0
- package/dist/client/_nuxt/CuhuY25u.js +1 -0
- package/dist/client/_nuxt/Cuk6v7N8.js +1 -0
- package/dist/client/_nuxt/Cvjx9yec.js +1 -0
- package/dist/client/_nuxt/CxbxFI8M.js +1 -0
- package/dist/client/_nuxt/CyktbL80.js +1 -0
- package/dist/client/_nuxt/CylS5w8V.js +1 -0
- package/dist/client/_nuxt/D-2ljcwZ.js +1 -0
- package/dist/client/_nuxt/D0r3Knsf.js +1 -0
- package/dist/client/_nuxt/D2Qjm2dq.js +1 -0
- package/dist/client/_nuxt/D2ZA7i9S.js +1 -0
- package/dist/client/_nuxt/D4_iv3hh.js +1 -0
- package/dist/client/_nuxt/D4h5O-jR.js +1 -0
- package/dist/client/_nuxt/D5KoaKCx.js +1 -0
- package/dist/client/_nuxt/D7oLnXFd.js +1 -0
- package/dist/client/_nuxt/D87Tk5Gz.js +1 -0
- package/dist/client/_nuxt/DAi9KRSo.js +1 -0
- package/dist/client/_nuxt/DBKV2OwM.js +1 -0
- package/dist/client/_nuxt/DEthMvLe.js +1 -0
- package/dist/client/_nuxt/DFWUc33u.js +1 -0
- package/dist/client/_nuxt/DFlZdHUX.js +1 -0
- package/dist/client/_nuxt/DGP4VlC8.js +1 -0
- package/dist/client/_nuxt/DGztddWO.js +1 -0
- package/dist/client/_nuxt/DH5Ifo-i.js +1 -0
- package/dist/client/_nuxt/DHJKELXO.js +1 -0
- package/dist/client/_nuxt/DHQR4-dF.js +1 -0
- package/dist/client/_nuxt/DJjDtW9f.js +1 -0
- package/dist/client/_nuxt/DPfMkruS.js +1 -0
- package/dist/client/_nuxt/DQyhUUbL.js +1 -0
- package/dist/client/_nuxt/DRw_LuNl.js +1 -0
- package/dist/client/_nuxt/DSeZwD4N.js +1 -0
- package/dist/client/_nuxt/DU1UobuO.js +1 -0
- package/dist/client/_nuxt/DUszq2jm.js +1 -0
- package/dist/client/_nuxt/DVMEJ2y_.js +1 -0
- package/dist/client/_nuxt/DWedfzmr.js +1 -0
- package/dist/client/_nuxt/DXbdFlpD.js +1 -0
- package/dist/client/_nuxt/DYE7WIF3.js +1 -0
- package/dist/client/_nuxt/DZxFcAj9.js +1 -0
- package/dist/client/_nuxt/DaskW291.js +1 -0
- package/dist/client/_nuxt/DcaNXYhu.js +1 -0
- package/dist/client/_nuxt/Ddv68eIx.js +1 -0
- package/dist/client/_nuxt/Des-eS-w.js +1 -0
- package/dist/client/_nuxt/DgsIRcX7.js +1 -0
- package/dist/client/_nuxt/DnULxvSX.js +1 -0
- package/dist/client/_nuxt/DqQDbK_p.js +1 -0
- package/dist/client/_nuxt/DqwNpetd.js +1 -0
- package/dist/client/_nuxt/Dspwwk_N.js +1 -0
- package/dist/client/_nuxt/Dx-B1_4e.js +1 -0
- package/dist/client/_nuxt/DxNHbxmM.js +1 -0
- package/dist/client/_nuxt/DxSwrfjg.js +1 -0
- package/dist/client/_nuxt/E3gJ1_iC.js +1 -0
- package/dist/client/_nuxt/GsRaNv29.js +1 -0
- package/dist/client/_nuxt/L9t79GZl.js +1 -0
- package/dist/client/_nuxt/MzD3tlZU.js +1 -0
- package/dist/client/_nuxt/SCyfE3vN.js +1 -0
- package/dist/client/_nuxt/W9tJ9s81.js +1 -0
- package/dist/client/_nuxt/X0qVHnNL.js +1 -0
- package/dist/client/_nuxt/Yzrsuije.js +1 -0
- package/dist/client/_nuxt/bN70gL4F.js +1 -0
- package/dist/client/_nuxt/builds/latest.json +1 -0
- package/dist/client/_nuxt/builds/meta/988a741f-ba30-4645-9949-60dd86de74e2.json +1 -0
- package/dist/client/_nuxt/entry.bXb283Sw.css +1 -0
- package/dist/client/_nuxt/error-404.LspKb3Ne.css +1 -0
- package/dist/client/_nuxt/error-500.B_qDdXYW.css +1 -0
- package/dist/client/_nuxt/fuZLfV_i.js +1 -0
- package/dist/client/_nuxt/g9-lgVsj.js +1 -0
- package/dist/client/_nuxt/gufSdAgD.js +36 -0
- package/dist/client/_nuxt/hJgmCMqR.js +1 -0
- package/dist/client/_nuxt/hegEt444.js +1 -0
- package/dist/client/_nuxt/hydration.C8A3o8hr.css +1 -0
- package/dist/client/_nuxt/m17aaUwq.js +1 -0
- package/dist/client/_nuxt/qdsjHGoJ.js +1 -0
- package/dist/client/_nuxt/wDzz0qaB.js +1 -0
- package/dist/client/_nuxt/zVBI731p.js +9 -0
- package/dist/client/component-lazy-load/index.html +1 -0
- package/dist/client/hydration/index.html +1 -0
- package/dist/client/index.html +1 -0
- package/dist/client/third-party-scripts/index.html +1 -0
- package/dist/client/web-vitals/index.html +1 -0
- package/dist/module.d.mts +10 -0
- package/dist/module.json +9 -0
- package/dist/module.mjs +442 -0
- package/dist/runtime/core/components/nuxt-island.d.ts +2 -0
- package/dist/runtime/core/components/nuxt-island.js +15 -0
- package/dist/runtime/core/features.d.ts +4 -0
- package/dist/runtime/core/features.js +10 -0
- package/dist/runtime/core/plugins/features.client.d.ts +2 -0
- package/dist/runtime/core/plugins/features.client.js +16 -0
- package/dist/runtime/core/plugins/vue-tracer-state.client.d.ts +2 -0
- package/dist/runtime/core/plugins/vue-tracer-state.client.js +7 -0
- package/dist/runtime/core/server/sse.d.ts +2 -0
- package/dist/runtime/core/server/sse.js +16 -0
- package/dist/runtime/core/server/types.d.ts +12 -0
- package/dist/runtime/core/server/types.js +2 -0
- package/dist/runtime/core/types.d.ts +9 -0
- package/dist/runtime/core/types.js +0 -0
- package/dist/runtime/hydration/component.d.ts +3 -0
- package/dist/runtime/hydration/component.js +22 -0
- package/dist/runtime/hydration/composables.d.ts +5 -0
- package/dist/runtime/hydration/composables.js +45 -0
- package/dist/runtime/hydration/nitro.plugin.d.ts +2 -0
- package/dist/runtime/hydration/nitro.plugin.js +65 -0
- package/dist/runtime/hydration/plugin.client.d.ts +2 -0
- package/dist/runtime/hydration/plugin.client.js +11 -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 +4 -0
- package/dist/runtime/hydration/utils.js +26 -0
- package/dist/runtime/lazy-load/composables.d.ts +11 -0
- package/dist/runtime/lazy-load/composables.js +52 -0
- package/dist/runtime/lazy-load/nitro.plugin.d.ts +2 -0
- package/dist/runtime/lazy-load/nitro.plugin.js +59 -0
- package/dist/runtime/lazy-load/plugin.client.d.ts +2 -0
- package/dist/runtime/lazy-load/plugin.client.js +73 -0
- package/dist/runtime/lazy-load/schema.d.ts +28 -0
- package/dist/runtime/lazy-load/schema.js +16 -0
- package/dist/runtime/lazy-load/utils.d.ts +2 -0
- package/dist/runtime/lazy-load/utils.js +4 -0
- package/dist/runtime/logger.d.ts +3 -0
- package/dist/runtime/logger.js +8 -0
- package/dist/runtime/third-party-scripts/nitro.plugin.d.ts +2 -0
- package/dist/runtime/third-party-scripts/nitro.plugin.js +48 -0
- package/dist/runtime/third-party-scripts/plugin.client.d.ts +2 -0
- package/dist/runtime/third-party-scripts/plugin.client.js +93 -0
- package/dist/runtime/third-party-scripts/utils.d.ts +1 -0
- package/dist/runtime/third-party-scripts/utils.js +2 -0
- package/dist/runtime/types.d.ts +80 -0
- package/dist/runtime/web-vitals/plugin.client.d.ts +13 -0
- package/dist/runtime/web-vitals/plugin.client.js +138 -0
- package/dist/runtime/web-vitals/utils.d.ts +36 -0
- package/dist/runtime/web-vitals/utils.js +15 -0
- package/dist/types.d.mts +3 -0
- package/package.json +70 -2
- /package/dist/{.gitkeep → client/_nuxt/third-party-scripts.tn0RQdqM.css} +0 -0
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { createError, defineEventHandler, readBody, setResponseStatus } from "h3";
|
|
2
|
+
const hydrationMismatches = [];
|
|
3
|
+
export default function(nitroApp) {
|
|
4
|
+
const getHandler = defineEventHandler(() => {
|
|
5
|
+
return {
|
|
6
|
+
mismatches: hydrationMismatches
|
|
7
|
+
};
|
|
8
|
+
});
|
|
9
|
+
const postHandler = defineEventHandler(async (event) => {
|
|
10
|
+
const body = await readBody(event);
|
|
11
|
+
assertPayload(body);
|
|
12
|
+
const payload = {
|
|
13
|
+
id: crypto.randomUUID(),
|
|
14
|
+
htmlPreHydration: body.htmlPreHydration,
|
|
15
|
+
htmlPostHydration: body.htmlPostHydration,
|
|
16
|
+
componentName: body.componentName,
|
|
17
|
+
fileLocation: body.fileLocation
|
|
18
|
+
};
|
|
19
|
+
hydrationMismatches.push(payload);
|
|
20
|
+
if (hydrationMismatches.length > 20) {
|
|
21
|
+
hydrationMismatches.shift();
|
|
22
|
+
}
|
|
23
|
+
nitroApp.hooks.callHook("hints:hydration:mismatch", payload);
|
|
24
|
+
setResponseStatus(event, 201);
|
|
25
|
+
return payload;
|
|
26
|
+
});
|
|
27
|
+
const deleteHandler = defineEventHandler(async (event) => {
|
|
28
|
+
const body = await readBody(event);
|
|
29
|
+
if (!body || !Array.isArray(body.id)) {
|
|
30
|
+
throw createError({ statusCode: 400, statusMessage: "Invalid payload" });
|
|
31
|
+
}
|
|
32
|
+
for (const id of body.id) {
|
|
33
|
+
const index = hydrationMismatches.findIndex((m) => m.id === id);
|
|
34
|
+
if (index !== -1) {
|
|
35
|
+
hydrationMismatches.splice(index, 1);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
nitroApp.hooks.callHook("hints:hydration:cleared", { id: body.id });
|
|
39
|
+
setResponseStatus(event, 204);
|
|
40
|
+
});
|
|
41
|
+
nitroApp.router.add("/__nuxt_hints/hydration", getHandler, "get");
|
|
42
|
+
nitroApp.router.add("/__nuxt_hints/hydration", postHandler, "post");
|
|
43
|
+
nitroApp.router.add("/__nuxt_hints/hydration", deleteHandler, "delete");
|
|
44
|
+
nitroApp.hooks.hook("hints:sse:setup", (context) => {
|
|
45
|
+
context.unsubscribers.push(
|
|
46
|
+
nitroApp.hooks.hook("hints:hydration:mismatch", (mismatch) => {
|
|
47
|
+
context.eventStream.push({
|
|
48
|
+
data: JSON.stringify(mismatch),
|
|
49
|
+
event: "hints:hydration:mismatch"
|
|
50
|
+
});
|
|
51
|
+
}),
|
|
52
|
+
nitroApp.hooks.hook("hints:hydration:cleared", (payload) => {
|
|
53
|
+
context.eventStream.push({
|
|
54
|
+
data: JSON.stringify(payload.id),
|
|
55
|
+
event: "hints:hydration:cleared"
|
|
56
|
+
});
|
|
57
|
+
})
|
|
58
|
+
);
|
|
59
|
+
});
|
|
60
|
+
function assertPayload(body) {
|
|
61
|
+
if (typeof body !== "object" || body.htmlPreHydration !== void 0 && typeof body.htmlPreHydration !== "string" || body.htmlPostHydration !== void 0 && typeof body.htmlPostHydration !== "string" || typeof body.componentName !== "string" || typeof body.fileLocation !== "string") {
|
|
62
|
+
throw createError({ statusCode: 400, statusMessage: "Invalid payload" });
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { defineNuxtPlugin, useNuxtApp } from "#imports";
|
|
2
|
+
import { defu } from "defu";
|
|
3
|
+
export default defineNuxtPlugin({
|
|
4
|
+
name: "@nuxt/hints:hydration",
|
|
5
|
+
setup() {
|
|
6
|
+
const nuxtApp = useNuxtApp();
|
|
7
|
+
nuxtApp.payload.__hints = defu(nuxtApp.payload.__hints, {
|
|
8
|
+
hydration: []
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
});
|
|
@@ -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,26 @@
|
|
|
1
|
+
import { HINTS_ROUTE, HINTS_SSE_ROUTE } from "../core/server/types.js";
|
|
2
|
+
import { createHintsLogger } from "../logger.js";
|
|
3
|
+
export const logger = createHintsLogger("hydration");
|
|
4
|
+
export const HYDRATION_ROUTE = `${HINTS_ROUTE}/hydration`;
|
|
5
|
+
export const HYDRATION_SSE_ROUTE = HINTS_SSE_ROUTE;
|
|
6
|
+
export function formatHTML(html) {
|
|
7
|
+
if (!html) return "";
|
|
8
|
+
let formatted = "";
|
|
9
|
+
let indent = 0;
|
|
10
|
+
const tags = html.split(/(<\/?[^>]+>)/g);
|
|
11
|
+
for (const tag of tags) {
|
|
12
|
+
if (!tag.trim()) continue;
|
|
13
|
+
if (tag.startsWith("</")) {
|
|
14
|
+
indent--;
|
|
15
|
+
formatted += "\n" + " ".repeat(Math.max(0, indent)) + tag;
|
|
16
|
+
} else if (tag.startsWith("<") && !tag.endsWith("/>") && !tag.includes("<!")) {
|
|
17
|
+
formatted += "\n" + " ".repeat(Math.max(0, indent)) + tag;
|
|
18
|
+
indent++;
|
|
19
|
+
} else if (tag.startsWith("<")) {
|
|
20
|
+
formatted += "\n" + " ".repeat(Math.max(0, indent)) + tag;
|
|
21
|
+
} else {
|
|
22
|
+
formatted += "\n" + " ".repeat(Math.max(0, indent)) + tag.trim();
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return formatted.trim();
|
|
26
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { DefineComponent } from 'vue';
|
|
2
|
+
import type { DirectImportInfo } from './schema.js';
|
|
3
|
+
export declare function useLazyComponentTracking(components?: DirectImportInfo[]): any;
|
|
4
|
+
/**
|
|
5
|
+
* Wrap components definition like with defineComponent or defineNuxtComponent or just sfc exports
|
|
6
|
+
*/
|
|
7
|
+
export declare function __wrapMainComponent(component: DefineComponent, imports?: DirectImportInfo[]): DefineComponent;
|
|
8
|
+
/**
|
|
9
|
+
* Wrap imported components to track their usage.
|
|
10
|
+
*/
|
|
11
|
+
export declare function __wrapImportedComponent(component: DefineComponent, componentName: string, importSource: string, importedBy: string): DefineComponent;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { useNuxtApp } from "#imports";
|
|
2
|
+
import { defu } from "defu";
|
|
3
|
+
export function useLazyComponentTracking(components = []) {
|
|
4
|
+
const nuxtApp = useNuxtApp();
|
|
5
|
+
if (!nuxtApp.payload.__hints?.lazyHydrationState) {
|
|
6
|
+
nuxtApp.payload.__hints = defu(nuxtApp.payload.__hints, {
|
|
7
|
+
lazyHydrationState: {
|
|
8
|
+
directImports: /* @__PURE__ */ new Map(),
|
|
9
|
+
hasReported: false,
|
|
10
|
+
pageLoaded: false
|
|
11
|
+
}
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
const state = nuxtApp.payload.__hints.lazyHydrationState;
|
|
15
|
+
for (const comp of components) {
|
|
16
|
+
state.directImports.set(comp.componentName, comp);
|
|
17
|
+
}
|
|
18
|
+
return state;
|
|
19
|
+
}
|
|
20
|
+
export function __wrapMainComponent(component, imports = []) {
|
|
21
|
+
const originalSetup = component.setup;
|
|
22
|
+
component.setup = (props, ctx) => {
|
|
23
|
+
useLazyComponentTracking(imports);
|
|
24
|
+
return originalSetup ? originalSetup(props, ctx) : void 0;
|
|
25
|
+
};
|
|
26
|
+
return component;
|
|
27
|
+
}
|
|
28
|
+
export function __wrapImportedComponent(component, componentName, importSource, importedBy) {
|
|
29
|
+
if (component && component.name === "AsyncComponentWrapper") {
|
|
30
|
+
return component;
|
|
31
|
+
}
|
|
32
|
+
const originalSetup = component.setup;
|
|
33
|
+
component.setup = (props, ctx) => {
|
|
34
|
+
const state = useLazyComponentTracking();
|
|
35
|
+
if (state) {
|
|
36
|
+
if (!state.directImports.has(componentName)) {
|
|
37
|
+
state.directImports.set(componentName, {
|
|
38
|
+
componentName,
|
|
39
|
+
importSource,
|
|
40
|
+
importedBy,
|
|
41
|
+
rendered: false
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
const info = state.directImports.get(componentName);
|
|
45
|
+
if (info) {
|
|
46
|
+
info.rendered = true;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return originalSetup ? originalSetup(props, ctx) : void 0;
|
|
50
|
+
};
|
|
51
|
+
return component;
|
|
52
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { createError, defineEventHandler, setResponseStatus, readBody } from "h3";
|
|
2
|
+
import { ComponentLazyLoadDataSchema } from "./schema.js";
|
|
3
|
+
import { parse, ValiError } from "valibot";
|
|
4
|
+
import { LAZY_LOAD_ROUTE } from "./utils.js";
|
|
5
|
+
const data = [];
|
|
6
|
+
export default function(nitroApp) {
|
|
7
|
+
const getHandler = defineEventHandler(() => {
|
|
8
|
+
return data;
|
|
9
|
+
});
|
|
10
|
+
const postHandler = defineEventHandler(async (event) => {
|
|
11
|
+
const body = await readBody(event);
|
|
12
|
+
let parsed;
|
|
13
|
+
try {
|
|
14
|
+
parsed = parse(ComponentLazyLoadDataSchema, body);
|
|
15
|
+
} catch (error) {
|
|
16
|
+
if (error instanceof ValiError) {
|
|
17
|
+
setResponseStatus(event, 400);
|
|
18
|
+
return { error: "Validation failed", message: error.message };
|
|
19
|
+
}
|
|
20
|
+
throw error;
|
|
21
|
+
}
|
|
22
|
+
data.push(parsed);
|
|
23
|
+
nitroApp.hooks.callHook("hints:lazy-load:report", parsed);
|
|
24
|
+
setResponseStatus(event, 201);
|
|
25
|
+
});
|
|
26
|
+
const deleteHandler = defineEventHandler(async (event) => {
|
|
27
|
+
const id = event.context.params?.id;
|
|
28
|
+
if (!id) {
|
|
29
|
+
throw createError({ statusCode: 400, message: "ID is required" });
|
|
30
|
+
}
|
|
31
|
+
const index = data.findIndex((item) => item.id === id);
|
|
32
|
+
if (index !== -1) {
|
|
33
|
+
data.splice(index, 1);
|
|
34
|
+
} else {
|
|
35
|
+
throw createError({ statusCode: 404, message: "Entry not found" });
|
|
36
|
+
}
|
|
37
|
+
nitroApp.hooks.callHook("hints:lazy-load:cleared", { id });
|
|
38
|
+
setResponseStatus(event, 204);
|
|
39
|
+
});
|
|
40
|
+
nitroApp.router.add(LAZY_LOAD_ROUTE, getHandler, "get");
|
|
41
|
+
nitroApp.router.add(LAZY_LOAD_ROUTE, postHandler, "post");
|
|
42
|
+
nitroApp.router.add(`${LAZY_LOAD_ROUTE}/:id`, deleteHandler, "delete");
|
|
43
|
+
nitroApp.hooks.hook("hints:sse:setup", (context) => {
|
|
44
|
+
context.unsubscribers.push(
|
|
45
|
+
nitroApp.hooks.hook("hints:lazy-load:report", (payload) => {
|
|
46
|
+
context.eventStream.push({
|
|
47
|
+
data: JSON.stringify(payload),
|
|
48
|
+
event: "hints:lazy-load:report"
|
|
49
|
+
});
|
|
50
|
+
}),
|
|
51
|
+
nitroApp.hooks.hook("hints:lazy-load:cleared", (payload) => {
|
|
52
|
+
context.eventStream.push({
|
|
53
|
+
data: JSON.stringify(payload.id),
|
|
54
|
+
event: "hints:lazy-load:cleared"
|
|
55
|
+
});
|
|
56
|
+
})
|
|
57
|
+
);
|
|
58
|
+
});
|
|
59
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { defineNuxtPlugin, useNuxtApp, useRoute } from "#imports";
|
|
2
|
+
import { defu } from "defu";
|
|
3
|
+
import { useLazyComponentTracking } from "./composables.js";
|
|
4
|
+
import { logger, LAZY_LOAD_ROUTE } from "./utils.js";
|
|
5
|
+
import { isFeatureDevtoolsEnabled } from "../core/features.js";
|
|
6
|
+
export default defineNuxtPlugin({
|
|
7
|
+
name: "@nuxt/hints:lazy-load",
|
|
8
|
+
dependsOn: ["nuxt:router"],
|
|
9
|
+
setup() {
|
|
10
|
+
const nuxtApp = useNuxtApp();
|
|
11
|
+
nuxtApp.payload.__hints = defu(nuxtApp.payload.__hints, {
|
|
12
|
+
lazyComponents: []
|
|
13
|
+
});
|
|
14
|
+
if (import.meta.client) {
|
|
15
|
+
const state = useLazyComponentTracking();
|
|
16
|
+
if (!state) return;
|
|
17
|
+
nuxtApp.hook("app:suspense:resolve", () => {
|
|
18
|
+
if (state.hasReported || state.pageLoaded) return;
|
|
19
|
+
state.pageLoaded = true;
|
|
20
|
+
setTimeout(() => {
|
|
21
|
+
nuxtApp.runWithContext(() => checkAndReport(state));
|
|
22
|
+
}, 500);
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
function checkAndReport(state) {
|
|
28
|
+
if (state.hasReported) return;
|
|
29
|
+
state.hasReported = true;
|
|
30
|
+
const suggestions = [];
|
|
31
|
+
for (const [_, info] of state.directImports) {
|
|
32
|
+
if (!info.rendered) {
|
|
33
|
+
suggestions.push(info);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
if (suggestions.length > 0) {
|
|
37
|
+
reportSuggestions(suggestions);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
function reportSuggestions(suggestions) {
|
|
41
|
+
const route = useRoute();
|
|
42
|
+
const nuxtApp = useNuxtApp();
|
|
43
|
+
nuxtApp.payload.__hints.lazyComponents = suggestions;
|
|
44
|
+
logger.info(
|
|
45
|
+
`${suggestions.length} component has not been rendered in SSR nor rendered at hydration time. Consider lazy loading it:
|
|
46
|
+
`
|
|
47
|
+
);
|
|
48
|
+
for (const suggestion of suggestions) {
|
|
49
|
+
const lazyName = `Lazy${suggestion.componentName}`;
|
|
50
|
+
logger.info(
|
|
51
|
+
`${suggestion.componentName} \u2192 Use <${lazyName}> or \`defineAsyncComponent\` instead
|
|
52
|
+
Imported from: ${suggestion.importSource}
|
|
53
|
+
Used in: ${suggestion.importedBy}`
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
if (suggestions.length && isFeatureDevtoolsEnabled("lazyLoad")) {
|
|
57
|
+
const payload = {
|
|
58
|
+
id: `${encodeURIComponent(route.path)}-${Date.now()}`,
|
|
59
|
+
route: route.path,
|
|
60
|
+
state: {
|
|
61
|
+
pageLoaded: true,
|
|
62
|
+
hasReported: true,
|
|
63
|
+
directImports: suggestions
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
$fetch(LAZY_LOAD_ROUTE, {
|
|
67
|
+
method: "POST",
|
|
68
|
+
body: payload
|
|
69
|
+
}).catch((err) => {
|
|
70
|
+
logger.warn("Failed to send lazy-load data to server:", err);
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { InferOutput } from 'valibot';
|
|
2
|
+
export declare const ComponentLazyLoadImportSchema: import("valibot").ObjectSchema<{
|
|
3
|
+
readonly componentName: import("valibot").StringSchema<undefined>;
|
|
4
|
+
readonly importSource: import("valibot").StringSchema<undefined>;
|
|
5
|
+
readonly importedBy: import("valibot").StringSchema<undefined>;
|
|
6
|
+
readonly rendered: import("valibot").BooleanSchema<undefined>;
|
|
7
|
+
}, undefined>;
|
|
8
|
+
export type DirectImportInfo = InferOutput<typeof ComponentLazyLoadImportSchema>;
|
|
9
|
+
export declare const ComponentLazyLoadDataSchema: import("valibot").ObjectSchema<{
|
|
10
|
+
readonly id: import("valibot").StringSchema<undefined>;
|
|
11
|
+
readonly route: import("valibot").StringSchema<undefined>;
|
|
12
|
+
readonly state: import("valibot").ObjectSchema<{
|
|
13
|
+
readonly pageLoaded: import("valibot").BooleanSchema<undefined>;
|
|
14
|
+
readonly hasReported: import("valibot").BooleanSchema<undefined>;
|
|
15
|
+
readonly directImports: import("valibot").ArraySchema<import("valibot").ObjectSchema<{
|
|
16
|
+
readonly componentName: import("valibot").StringSchema<undefined>;
|
|
17
|
+
readonly importSource: import("valibot").StringSchema<undefined>;
|
|
18
|
+
readonly importedBy: import("valibot").StringSchema<undefined>;
|
|
19
|
+
readonly rendered: import("valibot").BooleanSchema<undefined>;
|
|
20
|
+
}, undefined>, undefined>;
|
|
21
|
+
}, undefined>;
|
|
22
|
+
}, undefined>;
|
|
23
|
+
export type ComponentLazyLoadData = InferOutput<typeof ComponentLazyLoadDataSchema>;
|
|
24
|
+
export type ComponentLazyLoadState = {
|
|
25
|
+
directImports: Map<string, DirectImportInfo>;
|
|
26
|
+
hasReported: boolean;
|
|
27
|
+
pageLoaded: boolean;
|
|
28
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { array, boolean, object, string } from "valibot";
|
|
2
|
+
export const ComponentLazyLoadImportSchema = object({
|
|
3
|
+
componentName: string(),
|
|
4
|
+
importSource: string(),
|
|
5
|
+
importedBy: string(),
|
|
6
|
+
rendered: boolean()
|
|
7
|
+
});
|
|
8
|
+
export const ComponentLazyLoadDataSchema = object({
|
|
9
|
+
id: string(),
|
|
10
|
+
route: string(),
|
|
11
|
+
state: object({
|
|
12
|
+
pageLoaded: boolean(),
|
|
13
|
+
hasReported: boolean(),
|
|
14
|
+
directImports: array(ComponentLazyLoadImportSchema)
|
|
15
|
+
})
|
|
16
|
+
});
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { createConsola } from "consola";
|
|
2
|
+
import { isFeatureLogsEnabled } from "./core/features.js";
|
|
3
|
+
export function createHintsLogger(feature) {
|
|
4
|
+
return createConsola({
|
|
5
|
+
level: isFeatureLogsEnabled(feature) ? void 0 : 0
|
|
6
|
+
}).withTag(`hints:${feature}`);
|
|
7
|
+
}
|
|
8
|
+
export const logger = createConsola().withTag("hints");
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
export default function(nitroApp) {
|
|
2
|
+
nitroApp.hooks.hook("render:html", ({ head }) => {
|
|
3
|
+
head.unshift(`
|
|
4
|
+
<script>
|
|
5
|
+
window.__hints_TPC_start_time = Date.now();
|
|
6
|
+
|
|
7
|
+
function __hints_TPC_saveTime(script, startTime) {
|
|
8
|
+
script.__hints_TPC_end_time = Date.now();
|
|
9
|
+
const scriptStartTime = startTime || script.__hints_TPC_start_time || window.__hints_TPC_start_time;
|
|
10
|
+
|
|
11
|
+
const resourceEntries = performance.getEntriesByName(script.src)
|
|
12
|
+
const scriptEntry = resourceEntries.find(entry => entry.name === script.src)
|
|
13
|
+
|
|
14
|
+
if (scriptEntry) {
|
|
15
|
+
// Calculate parse + execute time using modern API
|
|
16
|
+
const navigationEntry = performance.getEntriesByType('navigation')[0]
|
|
17
|
+
const navigationStart = navigationEntry ? performance.timeOrigin : performance.timeOrigin
|
|
18
|
+
|
|
19
|
+
script.requestTime = (scriptEntry.responseStart - scriptEntry.requestStart);
|
|
20
|
+
script.downloadTime = (scriptEntry.responseEnd - scriptEntry.responseStart);
|
|
21
|
+
script.totalNetworkTime = (scriptEntry.responseEnd - scriptEntry.startTime);
|
|
22
|
+
script.parseExecuteTime = script.__hints_TPC_end_time - (navigationStart + scriptEntry.responseEnd);
|
|
23
|
+
script.loaded = true;
|
|
24
|
+
console.log('[@nuxt/hints]: \u{1F4CA} Detailed timing for', script.src, {
|
|
25
|
+
'Request': script.requestTime.toFixed(2) + 'ms',
|
|
26
|
+
'Download': script.downloadTime.toFixed(2) + 'ms',
|
|
27
|
+
'Total Network': script.totalNetworkTime.toFixed(2) + 'ms',
|
|
28
|
+
'Parse + Execute': script.parseExecuteTime.toFixed(2) + 'ms'
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
<\/script>
|
|
33
|
+
`);
|
|
34
|
+
head.push(`
|
|
35
|
+
<script>
|
|
36
|
+
for (const script of document.scripts) {
|
|
37
|
+
if (script.src && !script.src.startsWith(window.location.origin)) {
|
|
38
|
+
script.__hints_TPC_start_time = window.__hints_TPC_start_time || Date.now();
|
|
39
|
+
script.addEventListener('load', () => {
|
|
40
|
+
__hints_TPC_saveTime(script, script.__hints_TPC_start_time);
|
|
41
|
+
})
|
|
42
|
+
__hints_TPC_saveTime(script, script.__hints_TPC_start_time);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
<\/script>
|
|
46
|
+
`);
|
|
47
|
+
});
|
|
48
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { defineNuxtPlugin, ref, useNuxtApp } from "#imports";
|
|
2
|
+
import { defu } from "defu";
|
|
3
|
+
import { logger } from "./utils.js";
|
|
4
|
+
const EXTENSIONS_SCHEMES_RE = /^(chrome-extension|moz-extension|safari-extension|ms-browser-extension):/;
|
|
5
|
+
function isExtensionScript(src) {
|
|
6
|
+
try {
|
|
7
|
+
const url = new URL(src, window.location.origin);
|
|
8
|
+
return EXTENSIONS_SCHEMES_RE.test(url.protocol);
|
|
9
|
+
} catch {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
function isSameOriginScript(src) {
|
|
14
|
+
try {
|
|
15
|
+
const url = new URL(src, window.location.origin);
|
|
16
|
+
return url.origin === window.location.origin;
|
|
17
|
+
} catch {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
function isIgnoredScript(src) {
|
|
22
|
+
return isSameOriginScript(src) || isExtensionScript(src);
|
|
23
|
+
}
|
|
24
|
+
export default defineNuxtPlugin({
|
|
25
|
+
name: "nuxt-hints:third-party-scripts",
|
|
26
|
+
setup() {
|
|
27
|
+
const nuxtApp = useNuxtApp();
|
|
28
|
+
nuxtApp.payload.__hints = defu(nuxtApp.payload.__hints, {
|
|
29
|
+
thirdPartyScripts: ref([])
|
|
30
|
+
});
|
|
31
|
+
const scripts = nuxtApp.payload.__hints.thirdPartyScripts;
|
|
32
|
+
const isUsingNuxtScripts = !!nuxtApp.$scripts;
|
|
33
|
+
nuxtApp.hook("hints:scripts:added", (script) => {
|
|
34
|
+
scripts.value.push({ element: script, loaded: false });
|
|
35
|
+
});
|
|
36
|
+
nuxtApp.hook("hints:scripts:loaded", (script) => {
|
|
37
|
+
const existingScript = scripts.value.find((s) => s.element === script);
|
|
38
|
+
if (existingScript) {
|
|
39
|
+
existingScript.loaded = true;
|
|
40
|
+
} else {
|
|
41
|
+
logger.warn(`Script loaded event received for a script not tracked: ${script.src}. Please open an issue with a minimal reproduction if you think this is a bug.`);
|
|
42
|
+
scripts.value.push({ element: script, loaded: true });
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
nuxtApp.hooks.hookOnce("app:mounted", () => {
|
|
46
|
+
let hasThirdPartyScript = false;
|
|
47
|
+
for (const script of document.scripts) {
|
|
48
|
+
if (script.src && !isIgnoredScript(script.src)) {
|
|
49
|
+
hasThirdPartyScript = true;
|
|
50
|
+
onScriptAdded(script);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
if (hasThirdPartyScript && !isUsingNuxtScripts) {
|
|
54
|
+
logger.info("Third-party scripts detected on page load: consider using @nuxt/scripts");
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
const observer = new MutationObserver((mutations) => {
|
|
58
|
+
for (const mutation of mutations) {
|
|
59
|
+
if (mutation.type === "childList") {
|
|
60
|
+
for (const node of mutation.addedNodes) {
|
|
61
|
+
if (isScript(node) && node.src && !isIgnoredScript(node.src)) {
|
|
62
|
+
onScriptAdded(node);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
observer.observe(document.documentElement, {
|
|
69
|
+
childList: true,
|
|
70
|
+
subtree: true
|
|
71
|
+
});
|
|
72
|
+
function onScriptAdded(script) {
|
|
73
|
+
if (!script.crossOrigin) {
|
|
74
|
+
logger.warn(`Third-party script "${script.src}" is missing crossorigin attribute. Consider adding crossorigin="anonymous" for better security and error reporting.`);
|
|
75
|
+
}
|
|
76
|
+
nuxtApp.callHook("hints:scripts:added", script).then(() => {
|
|
77
|
+
if (!script.loaded) {
|
|
78
|
+
script.addEventListener("load", () => {
|
|
79
|
+
window.__hints_TPC_saveTime(script, script.__hints_TPC_start_time);
|
|
80
|
+
nuxtApp.callHook("hints:scripts:loaded", script);
|
|
81
|
+
});
|
|
82
|
+
} else {
|
|
83
|
+
window.__hints_TPC_saveTime(script, script.__hints_TPC_start_time);
|
|
84
|
+
nuxtApp.callHook("hints:scripts:loaded", script);
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
logger.info(`Dynamically added third-party script detected: ${script.src}`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
function isScript(node) {
|
|
92
|
+
return node.nodeName === "SCRIPT";
|
|
93
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const logger: import("consola").ConsolaInstance;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import type { VNode, Ref } from 'vue'
|
|
2
|
+
import type { LCPMetricWithAttribution, INPMetricWithAttribution, CLSMetricWithAttribution } from 'web-vitals/attribution'
|
|
3
|
+
import type { HydrationMismatchPayload, LocalHydrationMismatch } from './hydration/types'
|
|
4
|
+
import type { DirectImportInfo, LazyHydrationState } from './lazy-load/composables'
|
|
5
|
+
import type { FeaturesName, FeatureFlags } from './core/types'
|
|
6
|
+
|
|
7
|
+
declare global {
|
|
8
|
+
interface Window {
|
|
9
|
+
__hints_TPC_start_time: number
|
|
10
|
+
__hints_TPC_saveTime: (script: HTMLScriptElement, startTime?: number) => void
|
|
11
|
+
}
|
|
12
|
+
interface HTMLScriptElement {
|
|
13
|
+
__hints_TPC_start_time?: number
|
|
14
|
+
__hints_TPC_end_time?: number
|
|
15
|
+
requestTime?: number
|
|
16
|
+
downloadTime?: number
|
|
17
|
+
totalNetworkTime?: number
|
|
18
|
+
parseExecuteTime?: number
|
|
19
|
+
loaded?: boolean
|
|
20
|
+
}
|
|
21
|
+
interface Element {
|
|
22
|
+
__vnode?: VNode
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
declare module '#app' {
|
|
27
|
+
interface RuntimeNuxtHooks {
|
|
28
|
+
'hints:scripts:added': (script: HTMLScriptElement) => void
|
|
29
|
+
'hints:scripts:loaded': (script: HTMLScriptElement) => void
|
|
30
|
+
|
|
31
|
+
'hints:webvitals:sync': (webvitals: NuxtPayload['__hints']['webvitals']) => void
|
|
32
|
+
'hints:webvitals:lcp': (metric: LCPMetricWithAttribution) => void
|
|
33
|
+
'hints:webvitals:inp': (metric: INPMetricWithAttribution) => void
|
|
34
|
+
'hints:webvitals:cls': (metric: CLSMetricWithAttribution) => void
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
interface NuxtApp {
|
|
38
|
+
__tracerOverlay: typeof import('vite-plugin-vue-tracer/client/overlay')
|
|
39
|
+
__tracerRecord: typeof import('vite-plugin-vue-tracer/client/record')
|
|
40
|
+
hints: {
|
|
41
|
+
config: {
|
|
42
|
+
features: Record<FeaturesName, FeatureFlags | boolean>
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
interface NuxtPayload {
|
|
48
|
+
__hints: {
|
|
49
|
+
lazyHydrationState?: LazyHydrationState
|
|
50
|
+
hydration: LocalHydrationMismatch[]
|
|
51
|
+
lazyComponents: DirectImportInfo[]
|
|
52
|
+
webvitals: {
|
|
53
|
+
lcp: Ref<LCPMetricWithAttribution[]>
|
|
54
|
+
inp: Ref<INPMetricWithAttribution[]>
|
|
55
|
+
cls: Ref<CLSMetricWithAttribution[]>
|
|
56
|
+
}
|
|
57
|
+
thirdPartyScripts: Ref<{
|
|
58
|
+
element: HTMLScriptElement
|
|
59
|
+
loaded: boolean
|
|
60
|
+
}[]>
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
declare module 'nitropack' {
|
|
66
|
+
interface NitroRuntimeHooks {
|
|
67
|
+
// Core hints hooks
|
|
68
|
+
'hints:sse:setup': (context: import('./core/server/types').HintsSseContext) => void
|
|
69
|
+
|
|
70
|
+
// Hydration hooks
|
|
71
|
+
'hints:hydration:mismatch': (payload: HydrationMismatchPayload) => void
|
|
72
|
+
'hints:hydration:cleared': (payload: { id: string[] }) => void
|
|
73
|
+
|
|
74
|
+
// Lazy-load hooks
|
|
75
|
+
'hints:lazy-load:report': (payload: import('./lazy-load/schema').ComponentLazyLoadData) => void
|
|
76
|
+
'hints:lazy-load:cleared': (payload: { id: string }) => void
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export {}
|