@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.
Files changed (76) hide show
  1. package/README.md +13 -0
  2. package/dist/client/200.html +1 -1
  3. package/dist/client/404.html +1 -1
  4. package/dist/client/_nuxt/-coei5WE.js +4 -0
  5. package/dist/client/_nuxt/{DxoRA_Jg.js → B1nHQOfq.js} +1 -1
  6. package/dist/client/_nuxt/{BOswn9ZA.js → BDdCTdUI.js} +1 -1
  7. package/dist/client/_nuxt/BR7nweas.js +1 -0
  8. package/dist/client/_nuxt/BUw7H-hv.js +1 -0
  9. package/dist/client/_nuxt/C3Wv6jpd.js +1 -0
  10. package/dist/client/_nuxt/C47S-Tmv.js +1 -0
  11. package/dist/client/_nuxt/{C-Jbm3Hp.js → C4gqWexZ.js} +1 -1
  12. package/dist/client/_nuxt/{DCjNVr8X.js → C7hBqjlR.js} +1 -1
  13. package/dist/client/_nuxt/CC58r8DQ.js +1 -0
  14. package/dist/client/_nuxt/{B5aFfd-r.js → CGrEsiZq.js} +1 -1
  15. package/dist/client/_nuxt/CMTm3GFP.js +1 -0
  16. package/dist/client/_nuxt/CMjwMIkn.js +1 -0
  17. package/dist/client/_nuxt/{DSNF90uQ.js → CO-t741Y.js} +1 -1
  18. package/dist/client/_nuxt/{DJRd5JwX.js → CPCqepq_.js} +1 -1
  19. package/dist/client/_nuxt/{B4xF9mB8.js → CTimJaOZ.js} +1 -1
  20. package/dist/client/_nuxt/CjoLj4QM.js +1 -0
  21. package/dist/client/_nuxt/{CPJ7wMZ4.js → DCmwhz07.js} +1 -1
  22. package/dist/client/_nuxt/DGBsmNPI.js +1 -0
  23. package/dist/client/_nuxt/DJjDtW9f.js +1 -0
  24. package/dist/client/_nuxt/De9_lo2O.js +1 -0
  25. package/dist/client/_nuxt/DeEbof0M.js +6 -0
  26. package/dist/client/_nuxt/{CmeNmt1M.js → DsF60Hh0.js} +1 -1
  27. package/dist/client/_nuxt/{C7PG24o2.js → GGTyZ2re.js} +1 -1
  28. package/dist/client/_nuxt/builds/latest.json +1 -1
  29. package/dist/client/_nuxt/builds/meta/fbd27eb3-33d2-4da5-874f-0d93f7752a53.json +1 -0
  30. package/dist/client/_nuxt/entry.DKSlCyYS.css +1 -0
  31. package/dist/client/_nuxt/error-404.CR9CpgUf.css +1 -0
  32. package/dist/client/_nuxt/error-500.CaOly-jC.css +1 -0
  33. package/dist/client/_nuxt/{CmBIQlQV.js → uOY9vQtj.js} +10 -10
  34. package/dist/client/component-lazy-load/index.html +1 -0
  35. package/dist/client/hydration/index.html +1 -1
  36. package/dist/client/index.html +1 -1
  37. package/dist/client/third-party-scripts/index.html +1 -1
  38. package/dist/client/web-vitals/index.html +1 -1
  39. package/dist/module.json +1 -1
  40. package/dist/module.mjs +185 -15
  41. package/dist/runtime/core/server/sse.js +16 -0
  42. package/dist/runtime/core/server/types.d.ts +12 -0
  43. package/dist/runtime/core/server/types.js +2 -0
  44. package/dist/runtime/hydration/composables.js +13 -11
  45. package/dist/runtime/hydration/nitro.plugin.d.ts +2 -0
  46. package/dist/runtime/hydration/nitro.plugin.js +65 -0
  47. package/dist/runtime/hydration/utils.d.ts +2 -2
  48. package/dist/runtime/hydration/utils.js +3 -2
  49. package/dist/runtime/lazy-load/composables.d.ts +7 -0
  50. package/dist/runtime/lazy-load/composables.js +52 -0
  51. package/dist/runtime/lazy-load/nitro.plugin.d.ts +2 -0
  52. package/dist/runtime/lazy-load/nitro.plugin.js +59 -0
  53. package/dist/runtime/lazy-load/plugin.client.d.ts +2 -0
  54. package/dist/runtime/lazy-load/plugin.client.js +73 -0
  55. package/dist/runtime/lazy-load/schema.d.ts +28 -0
  56. package/dist/runtime/lazy-load/schema.js +16 -0
  57. package/dist/runtime/lazy-load/utils.d.ts +1 -0
  58. package/dist/runtime/lazy-load/utils.js +2 -0
  59. package/dist/runtime/types.d.ts +14 -0
  60. package/package.json +29 -27
  61. package/dist/client/_nuxt/CGh86NWx.js +0 -4
  62. package/dist/client/_nuxt/COqnpOrt.js +0 -1
  63. package/dist/client/_nuxt/CgPyyo4O.js +0 -1
  64. package/dist/client/_nuxt/CmMr59Fi.js +0 -1
  65. package/dist/client/_nuxt/DIAcCAND.js +0 -6
  66. package/dist/client/_nuxt/PoHY5YXO.js +0 -1
  67. package/dist/client/_nuxt/Xqf5ue2O.js +0 -1
  68. package/dist/client/_nuxt/biRC-D3g.js +0 -1
  69. package/dist/client/_nuxt/builds/meta/320be0c4-177a-4724-8735-6b1a31ee8c22.json +0 -1
  70. package/dist/client/_nuxt/entry.I8MQ9pCy.css +0 -1
  71. package/dist/client/_nuxt/error-404.CTzDoZ55.css +0 -1
  72. package/dist/client/_nuxt/error-500.AUw9fuc1.css +0 -1
  73. package/dist/runtime/hydration/handler.nitro.d.ts +0 -5
  74. package/dist/runtime/hydration/handler.nitro.js +0 -52
  75. package/dist/runtime/hydration/sse.nitro.js +0 -22
  76. /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.I8MQ9pCy.css" crossorigin><link rel="modulepreload" as="script" crossorigin href="/__nuxt-hints/_nuxt/CGh86NWx.js"><script type="module" src="/__nuxt-hints/_nuxt/CGh86NWx.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:"320be0c4-177a-4724-8735-6b1a31ee8c22",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script><script type="application/json" data-nuxt-data="nuxt-hints-iframe" data-ssr="false" id="__NUXT_DATA__">[{"prerenderedAt":1,"serverRendered":2},1769545942714,false]</script></body></html>
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>
@@ -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.I8MQ9pCy.css" crossorigin><link rel="modulepreload" as="script" crossorigin href="/__nuxt-hints/_nuxt/CGh86NWx.js"><script type="module" src="/__nuxt-hints/_nuxt/CGh86NWx.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:"320be0c4-177a-4724-8735-6b1a31ee8c22",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script><script type="application/json" data-nuxt-data="nuxt-hints-iframe" data-ssr="false" id="__NUXT_DATA__">[{"prerenderedAt":1,"serverRendered":2},1769545942714,false]</script></body></html>
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.I8MQ9pCy.css" crossorigin><link rel="modulepreload" as="script" crossorigin href="/__nuxt-hints/_nuxt/CGh86NWx.js"><script type="module" src="/__nuxt-hints/_nuxt/CGh86NWx.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:"320be0c4-177a-4724-8735-6b1a31ee8c22",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script><script type="application/json" data-nuxt-data="nuxt-hints-iframe" data-ssr="false" id="__NUXT_DATA__">[{"prerenderedAt":1,"serverRendered":2},1769545942714,false]</script></body></html>
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.I8MQ9pCy.css" crossorigin><link rel="modulepreload" as="script" crossorigin href="/__nuxt-hints/_nuxt/CGh86NWx.js"><script type="module" src="/__nuxt-hints/_nuxt/CGh86NWx.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:"320be0c4-177a-4724-8735-6b1a31ee8c22",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script><script type="application/json" data-nuxt-data="nuxt-hints-iframe" data-ssr="false" id="__NUXT_DATA__">[{"prerenderedAt":1,"serverRendered":2},1769545942714,false]</script></body></html>
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
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@nuxt/hints",
3
3
  "configKey": "hints",
4
- "version": "1.0.0-alpha.6",
4
+ "version": "1.0.0-alpha.7",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "1.0.2",
7
7
  "unbuild": "3.6.1"
package/dist/module.mjs CHANGED
@@ -1,11 +1,11 @@
1
- import { addDevServerHandler, defineNuxtModule, createResolver, addComponent, addPlugin, addBuildPlugin, addServerHandler, addServerPlugin } from '@nuxt/kit';
2
- import { HYDRATION_ROUTE, HYDRATION_SSE_ROUTE } from '../dist/runtime/hydration/utils.js';
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: HYDRATION_ROUTE,
201
- handler: resolver.resolve("./runtime/hydration/handler.nitro")
365
+ route: HINTS_SSE_ROUTE,
366
+ handler: resolver.resolve("./runtime/core/server/sse")
202
367
  });
203
- addServerHandler({
204
- route: HYDRATION_SSE_ROUTE,
205
- handler: resolver.resolve("./runtime/hydration/sse.nitro")
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";
@@ -0,0 +1,2 @@
1
+ export const HINTS_ROUTE = "/__nuxt_hints";
2
+ export 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 payload = {
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
- id: globalThis.crypto.randomUUID(),
22
- componentName: instance.type.name ?? instance.type.displayName ?? instance.type.__name,
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: payload
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 ${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.`);
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,2 @@
1
+ import type { NitroApp } from 'nitropack/types';
2
+ export default function (nitroApp: NitroApp): void;
@@ -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 = "/__nuxt_hydration";
2
- export declare const HYDRATION_SSE_ROUTE = "/__nuxt_hydration/sse";
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
- export const HYDRATION_ROUTE = "/__nuxt_hydration";
2
- export const HYDRATION_SSE_ROUTE = "/__nuxt_hydration/sse";
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,2 @@
1
+ import type { NitroApp } from 'nitropack/types';
2
+ export default function (nitroApp: NitroApp): void;
@@ -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,2 @@
1
+ declare const _default: any;
2
+ export default _default;
@@ -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
+ }