@nuxt/hints 1.0.0-alpha.6 → 1.0.0-alpha.7
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 +13 -0
- package/dist/client/200.html +1 -1
- package/dist/client/404.html +1 -1
- package/dist/client/_nuxt/-coei5WE.js +4 -0
- package/dist/client/_nuxt/{DxoRA_Jg.js → B1nHQOfq.js} +1 -1
- package/dist/client/_nuxt/{BOswn9ZA.js → BDdCTdUI.js} +1 -1
- package/dist/client/_nuxt/BR7nweas.js +1 -0
- package/dist/client/_nuxt/BUw7H-hv.js +1 -0
- package/dist/client/_nuxt/C3Wv6jpd.js +1 -0
- package/dist/client/_nuxt/C47S-Tmv.js +1 -0
- package/dist/client/_nuxt/{C-Jbm3Hp.js → C4gqWexZ.js} +1 -1
- package/dist/client/_nuxt/{DCjNVr8X.js → C7hBqjlR.js} +1 -1
- package/dist/client/_nuxt/CC58r8DQ.js +1 -0
- package/dist/client/_nuxt/{B5aFfd-r.js → CGrEsiZq.js} +1 -1
- package/dist/client/_nuxt/CMTm3GFP.js +1 -0
- package/dist/client/_nuxt/CMjwMIkn.js +1 -0
- package/dist/client/_nuxt/{DSNF90uQ.js → CO-t741Y.js} +1 -1
- package/dist/client/_nuxt/{DJRd5JwX.js → CPCqepq_.js} +1 -1
- package/dist/client/_nuxt/{B4xF9mB8.js → CTimJaOZ.js} +1 -1
- package/dist/client/_nuxt/CjoLj4QM.js +1 -0
- package/dist/client/_nuxt/{CPJ7wMZ4.js → DCmwhz07.js} +1 -1
- package/dist/client/_nuxt/DGBsmNPI.js +1 -0
- package/dist/client/_nuxt/DJjDtW9f.js +1 -0
- package/dist/client/_nuxt/De9_lo2O.js +1 -0
- package/dist/client/_nuxt/DeEbof0M.js +6 -0
- package/dist/client/_nuxt/{CmeNmt1M.js → DsF60Hh0.js} +1 -1
- package/dist/client/_nuxt/{C7PG24o2.js → GGTyZ2re.js} +1 -1
- package/dist/client/_nuxt/builds/latest.json +1 -1
- package/dist/client/_nuxt/builds/meta/fbd27eb3-33d2-4da5-874f-0d93f7752a53.json +1 -0
- package/dist/client/_nuxt/entry.DKSlCyYS.css +1 -0
- package/dist/client/_nuxt/error-404.CR9CpgUf.css +1 -0
- package/dist/client/_nuxt/error-500.CaOly-jC.css +1 -0
- package/dist/client/_nuxt/{CmBIQlQV.js → uOY9vQtj.js} +10 -10
- package/dist/client/component-lazy-load/index.html +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.json +1 -1
- package/dist/module.mjs +185 -15
- 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/hydration/composables.js +13 -11
- package/dist/runtime/hydration/nitro.plugin.d.ts +2 -0
- package/dist/runtime/hydration/nitro.plugin.js +65 -0
- package/dist/runtime/hydration/utils.d.ts +2 -2
- package/dist/runtime/hydration/utils.js +3 -2
- package/dist/runtime/lazy-load/composables.d.ts +7 -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 +1 -0
- package/dist/runtime/lazy-load/utils.js +2 -0
- package/dist/runtime/types.d.ts +14 -0
- package/package.json +29 -27
- package/dist/client/_nuxt/CGh86NWx.js +0 -4
- package/dist/client/_nuxt/COqnpOrt.js +0 -1
- package/dist/client/_nuxt/CgPyyo4O.js +0 -1
- package/dist/client/_nuxt/CmMr59Fi.js +0 -1
- package/dist/client/_nuxt/DIAcCAND.js +0 -6
- package/dist/client/_nuxt/PoHY5YXO.js +0 -1
- package/dist/client/_nuxt/Xqf5ue2O.js +0 -1
- package/dist/client/_nuxt/biRC-D3g.js +0 -1
- package/dist/client/_nuxt/builds/meta/320be0c4-177a-4724-8735-6b1a31ee8c22.json +0 -1
- package/dist/client/_nuxt/entry.I8MQ9pCy.css +0 -1
- package/dist/client/_nuxt/error-404.CTzDoZ55.css +0 -1
- package/dist/client/_nuxt/error-500.AUw9fuc1.css +0 -1
- package/dist/runtime/hydration/handler.nitro.d.ts +0 -5
- package/dist/runtime/hydration/handler.nitro.js +0 -52
- package/dist/runtime/hydration/sse.nitro.js +0 -22
- /package/dist/runtime/{hydration/sse.nitro.d.ts → core/server/sse.d.ts} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><link rel="stylesheet" href="/__nuxt-hints/_nuxt/entry.DKSlCyYS.css" crossorigin><link rel="modulepreload" as="script" crossorigin href="/__nuxt-hints/_nuxt/-coei5WE.js"><script type="module" src="/__nuxt-hints/_nuxt/-coei5WE.js" crossorigin></script></head><body><div id="__nuxt"></div><div id="teleports"></div><script>window.__NUXT__={};window.__NUXT__.config={public:{},app:{baseURL:"/__nuxt-hints",buildId:"fbd27eb3-33d2-4da5-874f-0d93f7752a53",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script><script type="application/json" data-nuxt-data="nuxt-hints-iframe" data-ssr="false" id="__NUXT_DATA__">[{"prerenderedAt":1,"serverRendered":2},1771447980710,false]</script></body></html>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
<!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><link rel="stylesheet" href="/__nuxt-hints/_nuxt/entry.
|
|
1
|
+
<!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><link rel="stylesheet" href="/__nuxt-hints/_nuxt/entry.DKSlCyYS.css" crossorigin><link rel="modulepreload" as="script" crossorigin href="/__nuxt-hints/_nuxt/-coei5WE.js"><script type="module" src="/__nuxt-hints/_nuxt/-coei5WE.js" crossorigin></script></head><body><div id="__nuxt"></div><div id="teleports"></div><script>window.__NUXT__={};window.__NUXT__.config={public:{},app:{baseURL:"/__nuxt-hints",buildId:"fbd27eb3-33d2-4da5-874f-0d93f7752a53",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script><script type="application/json" data-nuxt-data="nuxt-hints-iframe" data-ssr="false" id="__NUXT_DATA__">[{"prerenderedAt":1,"serverRendered":2},1771447980709,false]</script></body></html>
|
package/dist/client/index.html
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
<!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><link rel="stylesheet" href="/__nuxt-hints/_nuxt/entry.
|
|
1
|
+
<!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><link rel="stylesheet" href="/__nuxt-hints/_nuxt/entry.DKSlCyYS.css" crossorigin><link rel="modulepreload" as="script" crossorigin href="/__nuxt-hints/_nuxt/-coei5WE.js"><script type="module" src="/__nuxt-hints/_nuxt/-coei5WE.js" crossorigin></script></head><body><div id="__nuxt"></div><div id="teleports"></div><script>window.__NUXT__={};window.__NUXT__.config={public:{},app:{baseURL:"/__nuxt-hints",buildId:"fbd27eb3-33d2-4da5-874f-0d93f7752a53",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script><script type="application/json" data-nuxt-data="nuxt-hints-iframe" data-ssr="false" id="__NUXT_DATA__">[{"prerenderedAt":1,"serverRendered":2},1771447980710,false]</script></body></html>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
<!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><link rel="stylesheet" href="/__nuxt-hints/_nuxt/entry.
|
|
1
|
+
<!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><link rel="stylesheet" href="/__nuxt-hints/_nuxt/entry.DKSlCyYS.css" crossorigin><link rel="modulepreload" as="script" crossorigin href="/__nuxt-hints/_nuxt/-coei5WE.js"><script type="module" src="/__nuxt-hints/_nuxt/-coei5WE.js" crossorigin></script></head><body><div id="__nuxt"></div><div id="teleports"></div><script>window.__NUXT__={};window.__NUXT__.config={public:{},app:{baseURL:"/__nuxt-hints",buildId:"fbd27eb3-33d2-4da5-874f-0d93f7752a53",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script><script type="application/json" data-nuxt-data="nuxt-hints-iframe" data-ssr="false" id="__NUXT_DATA__">[{"prerenderedAt":1,"serverRendered":2},1771447980710,false]</script></body></html>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
<!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><link rel="stylesheet" href="/__nuxt-hints/_nuxt/entry.
|
|
1
|
+
<!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><link rel="stylesheet" href="/__nuxt-hints/_nuxt/entry.DKSlCyYS.css" crossorigin><link rel="modulepreload" as="script" crossorigin href="/__nuxt-hints/_nuxt/-coei5WE.js"><script type="module" src="/__nuxt-hints/_nuxt/-coei5WE.js" crossorigin></script></head><body><div id="__nuxt"></div><div id="teleports"></div><script>window.__NUXT__={};window.__NUXT__.config={public:{},app:{baseURL:"/__nuxt-hints",buildId:"fbd27eb3-33d2-4da5-874f-0d93f7752a53",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script><script type="application/json" data-nuxt-data="nuxt-hints-iframe" data-ssr="false" id="__NUXT_DATA__">[{"prerenderedAt":1,"serverRendered":2},1771447980710,false]</script></body></html>
|
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { addDevServerHandler, defineNuxtModule, createResolver, addComponent, addPlugin,
|
|
2
|
-
import {
|
|
1
|
+
import { addDevServerHandler, defineNuxtModule, createResolver, addComponent, addPlugin, addServerHandler, addBuildPlugin, addServerPlugin } from '@nuxt/kit';
|
|
2
|
+
import { HINTS_SSE_ROUTE } from '../dist/runtime/core/server/types.js';
|
|
3
3
|
import { existsSync } from 'node:fs';
|
|
4
4
|
import { eventHandler, proxyRequest } from 'h3';
|
|
5
5
|
import { genImport } from 'knitwork';
|
|
6
6
|
import MagicString from 'magic-string';
|
|
7
|
-
import { dirname, resolve } from 'node:path';
|
|
8
|
-
import { parseSync } from 'oxc-parser';
|
|
7
|
+
import { dirname, resolve, basename } from 'node:path';
|
|
8
|
+
import { parseSync, Visitor } from 'oxc-parser';
|
|
9
9
|
import { createUnplugin } from 'unplugin';
|
|
10
10
|
import { fileURLToPath } from 'node:url';
|
|
11
11
|
|
|
@@ -47,10 +47,10 @@ function setupDevToolsUI(nuxt, resolver) {
|
|
|
47
47
|
const distDir = dirname(fileURLToPath(import.meta.url));
|
|
48
48
|
|
|
49
49
|
const INCLUDE_VUE_RE = /\.vue$/;
|
|
50
|
-
const EXCLUDE_NODE_MODULES = /node_modules/;
|
|
50
|
+
const EXCLUDE_NODE_MODULES$1 = /node_modules/;
|
|
51
51
|
const DEFINE_COMPONENT_RE = /defineComponent/;
|
|
52
52
|
const DEFINE_NUXT_COMPONENT_RE = /defineNuxtComponent/;
|
|
53
|
-
const skipPath = normalizePath(resolve(distDir, "runtime/hydration/component.ts"));
|
|
53
|
+
const skipPath$1 = normalizePath$1(resolve(distDir, "runtime/hydration/component.ts"));
|
|
54
54
|
const InjectHydrationPlugin = createUnplugin(() => {
|
|
55
55
|
return [
|
|
56
56
|
{
|
|
@@ -60,7 +60,7 @@ const InjectHydrationPlugin = createUnplugin(() => {
|
|
|
60
60
|
filter: {
|
|
61
61
|
id: {
|
|
62
62
|
include: /.(vue|ts|js|tsx|jsx)$/,
|
|
63
|
-
exclude: [skipPath, EXCLUDE_NODE_MODULES]
|
|
63
|
+
exclude: [skipPath$1, EXCLUDE_NODE_MODULES$1]
|
|
64
64
|
},
|
|
65
65
|
code: {
|
|
66
66
|
include: [DEFINE_COMPONENT_RE, DEFINE_NUXT_COMPONENT_RE]
|
|
@@ -123,7 +123,7 @@ const InjectHydrationPlugin = createUnplugin(() => {
|
|
|
123
123
|
filter: {
|
|
124
124
|
id: {
|
|
125
125
|
include: INCLUDE_VUE_RE,
|
|
126
|
-
exclude: [skipPath, EXCLUDE_NODE_MODULES]
|
|
126
|
+
exclude: [skipPath$1, EXCLUDE_NODE_MODULES$1]
|
|
127
127
|
},
|
|
128
128
|
code: {
|
|
129
129
|
exclude: [DEFINE_COMPONENT_RE, DEFINE_NUXT_COMPONENT_RE]
|
|
@@ -168,9 +168,176 @@ function findImportSpecifier(importDecl, importedName, pkgNames, callback) {
|
|
|
168
168
|
return match.spec;
|
|
169
169
|
}
|
|
170
170
|
}
|
|
171
|
+
function normalizePath$1(path) {
|
|
172
|
+
return path.replace(/\\/g, "/");
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function findDefineComponentCalls(program) {
|
|
176
|
+
const imports = program.body.filter(
|
|
177
|
+
(node) => node.type === "ImportDeclaration"
|
|
178
|
+
);
|
|
179
|
+
const defineComponentImport = findImport("defineComponent", imports);
|
|
180
|
+
const defineComponentNames = /* @__PURE__ */ new Set(["defineNuxtComponent"]);
|
|
181
|
+
if (defineComponentImport) {
|
|
182
|
+
for (const specifier of defineComponentImport.specifiers) {
|
|
183
|
+
if (specifier.type === "ImportSpecifier" && specifier.imported.type === "Identifier") {
|
|
184
|
+
defineComponentNames.add(specifier.local.name);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
const defineComponentNodes = [];
|
|
189
|
+
const visitor = new Visitor({
|
|
190
|
+
CallExpression(node) {
|
|
191
|
+
if (node.callee.type === "Identifier" && defineComponentNames.has(node.callee.name)) {
|
|
192
|
+
defineComponentNodes.push(node);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
visitor.visit(program);
|
|
197
|
+
return defineComponentNodes;
|
|
198
|
+
}
|
|
199
|
+
function findImport(name, imports) {
|
|
200
|
+
return imports.find((imp) => {
|
|
201
|
+
return imp.specifiers.some((specifier) => {
|
|
202
|
+
if (specifier.type === "ImportSpecifier" && specifier.imported.type === "Identifier") {
|
|
203
|
+
return specifier.imported.name === name;
|
|
204
|
+
}
|
|
205
|
+
return false;
|
|
206
|
+
});
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
const INCLUDE_FILES = /\.(vue|tsx?|jsx?)$/;
|
|
211
|
+
const EXCLUDE_NODE_MODULES = /node_modules/;
|
|
212
|
+
const skipPath = normalizePath(resolve(distDir, "runtime/lazy-load"));
|
|
213
|
+
const LazyLoadHintPlugin = createUnplugin(() => {
|
|
214
|
+
return {
|
|
215
|
+
name: "@nuxt/hints:lazy-load-plugin",
|
|
216
|
+
enforce: "post",
|
|
217
|
+
transform: {
|
|
218
|
+
filter: {
|
|
219
|
+
id: {
|
|
220
|
+
include: INCLUDE_FILES,
|
|
221
|
+
exclude: [skipPath, EXCLUDE_NODE_MODULES]
|
|
222
|
+
}
|
|
223
|
+
},
|
|
224
|
+
handler(code, id) {
|
|
225
|
+
const m = new MagicString(code);
|
|
226
|
+
const { program } = parseSync(id, code);
|
|
227
|
+
const imports = program.body.filter(
|
|
228
|
+
(node) => node.type === "ImportDeclaration"
|
|
229
|
+
);
|
|
230
|
+
const directComponentImports = [];
|
|
231
|
+
for (const importDecl of imports) {
|
|
232
|
+
const source = importDecl.source.value;
|
|
233
|
+
if (!source.endsWith(".vue")) continue;
|
|
234
|
+
if (importDecl.importKind === "type") continue;
|
|
235
|
+
for (const specifier of importDecl.specifiers ?? []) {
|
|
236
|
+
if (specifier.type === "ImportDefaultSpecifier" || specifier.type === "ImportSpecifier") {
|
|
237
|
+
const localName = specifier.local.name;
|
|
238
|
+
directComponentImports.push({
|
|
239
|
+
name: localName,
|
|
240
|
+
source,
|
|
241
|
+
start: importDecl.start,
|
|
242
|
+
end: importDecl.end,
|
|
243
|
+
specifier
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
if (directComponentImports.length === 0) {
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
m.prepend(genImport(
|
|
252
|
+
"@nuxt/hints/runtime/lazy-load/composables",
|
|
253
|
+
["__wrapImportedComponent", "__wrapMainComponent"]
|
|
254
|
+
) + "\n" + genImport(
|
|
255
|
+
"@nuxt/hints/runtime/lazy-load/composables",
|
|
256
|
+
["useLazyComponentTracking"]
|
|
257
|
+
) + "\n");
|
|
258
|
+
const wrapperStatements = directComponentImports.map((imp) => {
|
|
259
|
+
const originalName = `__original_${imp.name}`;
|
|
260
|
+
return `const ${imp.name} = __wrapImportedComponent(${originalName}, '${imp.name}', '${imp.source}', '${normalizePath(id)}')`;
|
|
261
|
+
}).join("\n");
|
|
262
|
+
for (const imp of directComponentImports) {
|
|
263
|
+
const specifier = imp.specifier;
|
|
264
|
+
const localName = specifier.local.name;
|
|
265
|
+
const newName = `__original_${localName}`;
|
|
266
|
+
if (specifier.type === "ImportDefaultSpecifier") {
|
|
267
|
+
m.overwrite(
|
|
268
|
+
specifier.local.start,
|
|
269
|
+
specifier.local.end,
|
|
270
|
+
newName
|
|
271
|
+
);
|
|
272
|
+
} else if (specifier.type === "ImportSpecifier" && specifier.imported.type === "Identifier" && specifier.imported.name !== specifier.local.name) {
|
|
273
|
+
m.overwrite(
|
|
274
|
+
specifier.local.start,
|
|
275
|
+
specifier.local.end,
|
|
276
|
+
newName
|
|
277
|
+
);
|
|
278
|
+
} else {
|
|
279
|
+
m.overwrite(
|
|
280
|
+
specifier.local.start,
|
|
281
|
+
specifier.local.end,
|
|
282
|
+
`${localName} as ${newName}`
|
|
283
|
+
);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
if (code.includes("_sfc_main")) {
|
|
287
|
+
const wrappedComponents = directComponentImports.map((imp) => {
|
|
288
|
+
if (imp.name.startsWith("__nuxt")) {
|
|
289
|
+
return `{ componentName: '${basename(imp.source)}', importSource: '${imp.source}', importedBy: '${normalizePath(id)}', rendered: false }`;
|
|
290
|
+
}
|
|
291
|
+
return `{ componentName: '${imp.name}', importSource: '${imp.source}', importedBy: '${normalizePath(id)}', rendered: false }`;
|
|
292
|
+
}).join(", ");
|
|
293
|
+
m.replace("export default _sfc_main", `const _sfc_main_wrapped = __wrapMainComponent(_sfc_main, [${wrappedComponents}]);
|
|
294
|
+
export default _sfc_main_wrapped`);
|
|
295
|
+
}
|
|
296
|
+
const components = findDefineComponentCalls(program);
|
|
297
|
+
if (components && components.length > 0) {
|
|
298
|
+
for (const comp of components) {
|
|
299
|
+
injectUseLazyComponentTrackingInComponentSetup(comp, m, directComponentImports, id);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
m.prepend(wrapperStatements + "\n");
|
|
303
|
+
if (m.hasChanged()) {
|
|
304
|
+
return {
|
|
305
|
+
code: m.toString(),
|
|
306
|
+
map: m.generateMap({ hires: true })
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
};
|
|
312
|
+
});
|
|
171
313
|
function normalizePath(path) {
|
|
172
314
|
return path.replace(/\\/g, "/");
|
|
173
315
|
}
|
|
316
|
+
function injectUseLazyComponentTrackingInComponentSetup(node, magicString, directComponentImports, id) {
|
|
317
|
+
if (node.arguments.length === 1) {
|
|
318
|
+
const arg = node.arguments[0];
|
|
319
|
+
if (arg?.type === "ObjectExpression") {
|
|
320
|
+
const properties = arg.properties;
|
|
321
|
+
const setupProp = properties.find(
|
|
322
|
+
(prop) => prop.type === "Property" && prop.key.type === "Identifier" && prop.key.name === "setup"
|
|
323
|
+
);
|
|
324
|
+
if (setupProp && setupProp.type === "Property") {
|
|
325
|
+
const setupFunc = setupProp.value;
|
|
326
|
+
if (setupFunc.type === "FunctionExpression" || setupFunc.type === "ArrowFunctionExpression") {
|
|
327
|
+
const insertPos = (setupFunc.body?.start ?? 0) + 1;
|
|
328
|
+
const componentsArray = directComponentImports.map((imp) => {
|
|
329
|
+
const componentName = imp.name.startsWith("__nuxt") ? basename(imp.source) : imp.name;
|
|
330
|
+
return `{ componentName: '${componentName}', importSource: '${imp.source}', importedBy: '${normalizePath(id)}', rendered: false }`;
|
|
331
|
+
}).join(", ");
|
|
332
|
+
const injectionCode = `
|
|
333
|
+
const lazyHydrationState = useLazyComponentTracking([${componentsArray}]);
|
|
334
|
+
`;
|
|
335
|
+
magicString.appendLeft(insertPos, injectionCode);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
}
|
|
174
341
|
|
|
175
342
|
const moduleName = "@nuxt/hints";
|
|
176
343
|
const module$1 = defineNuxtModule({
|
|
@@ -194,15 +361,18 @@ const module$1 = defineNuxtModule({
|
|
|
194
361
|
priority: 1e3
|
|
195
362
|
});
|
|
196
363
|
addPlugin(resolver.resolve("./runtime/web-vitals/plugin.client"));
|
|
197
|
-
addPlugin(resolver.resolve("./runtime/hydration/plugin.client"));
|
|
198
|
-
addBuildPlugin(InjectHydrationPlugin);
|
|
199
364
|
addServerHandler({
|
|
200
|
-
route:
|
|
201
|
-
handler: resolver.resolve("./runtime/
|
|
365
|
+
route: HINTS_SSE_ROUTE,
|
|
366
|
+
handler: resolver.resolve("./runtime/core/server/sse")
|
|
202
367
|
});
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
368
|
+
addPlugin(resolver.resolve("./runtime/hydration/plugin.client"));
|
|
369
|
+
addBuildPlugin(InjectHydrationPlugin);
|
|
370
|
+
addServerPlugin(resolver.resolve("./runtime/hydration/nitro.plugin"));
|
|
371
|
+
addPlugin(resolver.resolve("./runtime/lazy-load/plugin.client"));
|
|
372
|
+
addServerPlugin(resolver.resolve("./runtime/lazy-load/nitro.plugin"));
|
|
373
|
+
nuxt.hook("modules:done", () => {
|
|
374
|
+
addBuildPlugin(LazyLoadHintPlugin, { client: false });
|
|
375
|
+
addBuildPlugin(LazyLoadHintPlugin, { server: false });
|
|
206
376
|
});
|
|
207
377
|
addPlugin(resolver.resolve("./runtime/third-party-scripts/plugin.client"));
|
|
208
378
|
addServerPlugin(resolver.resolve("./runtime/third-party-scripts/nitro.plugin"));
|
|
@@ -0,0 +1,16 @@
|
|
|
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 context = {
|
|
7
|
+
eventStream,
|
|
8
|
+
unsubscribers: []
|
|
9
|
+
};
|
|
10
|
+
nitro.hooks.callHook("hints:sse:setup", context);
|
|
11
|
+
eventStream.onClosed(async () => {
|
|
12
|
+
context.unsubscribers.forEach((unsub) => unsub());
|
|
13
|
+
await eventStream.close();
|
|
14
|
+
});
|
|
15
|
+
return eventStream.send();
|
|
16
|
+
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { EventHandler, EventStream, H3Event } from 'h3';
|
|
2
|
+
export interface HintsApiContext {
|
|
3
|
+
event: H3Event;
|
|
4
|
+
path: string;
|
|
5
|
+
handler?: EventHandler;
|
|
6
|
+
}
|
|
7
|
+
export interface HintsSseContext {
|
|
8
|
+
eventStream: EventStream;
|
|
9
|
+
unsubscribers: (() => void)[];
|
|
10
|
+
}
|
|
11
|
+
export declare const HINTS_ROUTE = "/__nuxt_hints";
|
|
12
|
+
export declare const HINTS_SSE_ROUTE = "/__nuxt_hints/sse";
|
|
@@ -15,23 +15,25 @@ export function useHydrationCheck() {
|
|
|
15
15
|
onMounted(() => {
|
|
16
16
|
const htmlPostHydration = formatHTML(instance.vnode.el?.outerHTML);
|
|
17
17
|
if (htmlPreHydration !== htmlPostHydration) {
|
|
18
|
-
const
|
|
18
|
+
const componentName = instance.type.name ?? instance.type.displayName ?? instance.type.__name;
|
|
19
|
+
const fileLocation = instance.type.__file ?? "unknown";
|
|
20
|
+
const body = {
|
|
19
21
|
htmlPreHydration,
|
|
20
22
|
htmlPostHydration,
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
fileLocation: instance.type.__file ?? "unknown"
|
|
23
|
+
componentName,
|
|
24
|
+
fileLocation
|
|
24
25
|
};
|
|
25
|
-
nuxtApp.__hints.hydration.push({
|
|
26
|
-
...payload,
|
|
27
|
-
instance,
|
|
28
|
-
vnode: vnodePrehydration
|
|
29
|
-
});
|
|
30
26
|
$fetch(new URL(HYDRATION_ROUTE, window.location.origin).href, {
|
|
31
27
|
method: "POST",
|
|
32
|
-
body
|
|
28
|
+
body
|
|
29
|
+
}).then((payload) => {
|
|
30
|
+
nuxtApp.__hints.hydration.push({
|
|
31
|
+
...payload,
|
|
32
|
+
instance,
|
|
33
|
+
vnode: vnodePrehydration
|
|
34
|
+
});
|
|
33
35
|
});
|
|
34
|
-
logger.warn(`[hydration] Component ${
|
|
36
|
+
logger.warn(`[hydration] Component ${componentName ?? instance.type.__file} seems to have different html pre and post-hydration. Please make sure you don't have any hydration issue.`);
|
|
35
37
|
}
|
|
36
38
|
});
|
|
37
39
|
}
|
|
@@ -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
|
+
}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export declare const HYDRATION_ROUTE = "/
|
|
2
|
-
export declare const HYDRATION_SSE_ROUTE = "/
|
|
1
|
+
export declare const HYDRATION_ROUTE = "/__nuxt_hints/hydration";
|
|
2
|
+
export declare const HYDRATION_SSE_ROUTE = "/__nuxt_hints/sse";
|
|
3
3
|
export declare function formatHTML(html: string | undefined): string;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
export const
|
|
1
|
+
import { HINTS_ROUTE, HINTS_SSE_ROUTE } from "../core/server/types.js";
|
|
2
|
+
export const HYDRATION_ROUTE = `${HINTS_ROUTE}/hydration`;
|
|
3
|
+
export const HYDRATION_SSE_ROUTE = HINTS_SSE_ROUTE;
|
|
3
4
|
export function formatHTML(html) {
|
|
4
5
|
if (!html) return "";
|
|
5
6
|
let formatted = "";
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type DefineComponent } from 'vue';
|
|
2
|
+
import type { DirectImportInfo } from './schema.js';
|
|
3
|
+
export declare function useLazyComponentTracking(components?: DirectImportInfo[]): any;
|
|
4
|
+
export declare function __wrapMainComponent(component: DefineComponent, imports?: DirectImportInfo[]): DefineComponent;
|
|
5
|
+
export declare function __wrapImportedComponent(component: DefineComponent, componentName: string, importSource: string, importedBy: string): DefineComponent | DefineComponent<{}, () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
|
|
6
|
+
[key: string]: any;
|
|
7
|
+
}>, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { defineComponent, h } from "vue";
|
|
2
|
+
import { useNuxtApp } from "#imports";
|
|
3
|
+
export function useLazyComponentTracking(components = []) {
|
|
4
|
+
const nuxtApp = useNuxtApp();
|
|
5
|
+
if (!nuxtApp.payload._lazyHydrationState) {
|
|
6
|
+
nuxtApp.payload._lazyHydrationState = {
|
|
7
|
+
directImports: /* @__PURE__ */ new Map(),
|
|
8
|
+
hasReported: false,
|
|
9
|
+
pageLoaded: false
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
const state = nuxtApp.payload._lazyHydrationState;
|
|
13
|
+
for (const comp of components) {
|
|
14
|
+
state.directImports.set(comp.componentName, comp);
|
|
15
|
+
}
|
|
16
|
+
return state;
|
|
17
|
+
}
|
|
18
|
+
export function __wrapMainComponent(component, imports = []) {
|
|
19
|
+
const originalSetup = component.setup;
|
|
20
|
+
component.setup = (props, ctx) => {
|
|
21
|
+
useLazyComponentTracking(imports);
|
|
22
|
+
return originalSetup ? originalSetup(props, ctx) : void 0;
|
|
23
|
+
};
|
|
24
|
+
return component;
|
|
25
|
+
}
|
|
26
|
+
export function __wrapImportedComponent(component, componentName, importSource, importedBy) {
|
|
27
|
+
if (component && component.name === "AsyncComponentWrapper") {
|
|
28
|
+
return component;
|
|
29
|
+
}
|
|
30
|
+
const wrapper = defineComponent({
|
|
31
|
+
name: `LazyTracker_${componentName}`,
|
|
32
|
+
setup(_, { slots, attrs }) {
|
|
33
|
+
const state = useLazyComponentTracking();
|
|
34
|
+
if (state) {
|
|
35
|
+
if (!state.directImports.has(componentName)) {
|
|
36
|
+
state.directImports.set(componentName, {
|
|
37
|
+
componentName,
|
|
38
|
+
importSource,
|
|
39
|
+
importedBy,
|
|
40
|
+
rendered: false
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
const info = state.directImports.get(componentName);
|
|
44
|
+
if (info) {
|
|
45
|
+
info.rendered = true;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return () => h(component, attrs, slots);
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
return wrapper;
|
|
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 } from "../logger.js";
|
|
5
|
+
import { LAZY_LOAD_ROUTE } from "./utils.js";
|
|
6
|
+
export default defineNuxtPlugin({
|
|
7
|
+
name: "@nuxt/hints:lazy-load",
|
|
8
|
+
dependsOn: ["nuxt:router"],
|
|
9
|
+
setup() {
|
|
10
|
+
const nuxtApp = useNuxtApp();
|
|
11
|
+
nuxtApp.__hints = defu(nuxtApp.__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.__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) {
|
|
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
|
+
}
|