vite-plugin-smart-prefetch 0.1.0

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.
@@ -0,0 +1,645 @@
1
+ // src/runtime/prefetch-manager.ts
2
+ var PrefetchManager = class {
3
+ constructor(strategy = "hybrid", debug = false) {
4
+ this.config = null;
5
+ this.prefetched = /* @__PURE__ */ new Set();
6
+ this.observer = null;
7
+ this.currentSegment = null;
8
+ this.fallbackToDefault = true;
9
+ this.strategy = strategy;
10
+ this.debug = debug;
11
+ }
12
+ /**
13
+ * Initialize the prefetch manager
14
+ * Loads configuration and sets up observers
15
+ */
16
+ async init() {
17
+ if (this.debug) {
18
+ console.log("\u{1F680} Smart Prefetch Manager - Initializing...");
19
+ console.log(" Strategy:", this.strategy);
20
+ console.log(" Debug mode: enabled");
21
+ }
22
+ try {
23
+ if (this.debug) {
24
+ console.log("\u{1F4E5} Fetching prefetch-config.json...");
25
+ }
26
+ const response = await fetch("/prefetch-config.json");
27
+ if (!response.ok) {
28
+ if (response.status === 404) {
29
+ if (this.debug) {
30
+ console.warn("\u26A0\uFE0F Prefetch config not found (404)");
31
+ console.log(" This is expected if:");
32
+ console.log(" 1. You haven't built the app yet (run `pnpm build`)");
33
+ console.log(" 2. The plugin failed to generate the config during build");
34
+ console.log(" Prefetch manager will be inactive until config is available");
35
+ }
36
+ return;
37
+ }
38
+ throw new Error(`Failed to load prefetch config: ${response.statusText}`);
39
+ }
40
+ this.config = await response.json();
41
+ if (this.debug && this.config) {
42
+ console.log("\u2705 Config loaded successfully");
43
+ console.log(` Routes with prefetch rules: ${Object.keys(this.config.routes).length} ${typeof this.config.routes}`);
44
+ console.log(` Environment: ${this.config.environment}`);
45
+ console.log(` Config version: ${this.config.version || "N/A"}`);
46
+ console.groupCollapsed("\u{1F4CB} Available prefetch rules:");
47
+ Object.entries(this.config.routes).forEach(([source, data]) => {
48
+ console.log(
49
+ `${source} \u2192 ${data.prefetch.length} target(s)`,
50
+ data.prefetch.map((t) => t.route)
51
+ );
52
+ });
53
+ console.groupEnd();
54
+ }
55
+ if (this.strategy === "visible" || this.strategy === "hybrid") {
56
+ this.initIntersectionObserver();
57
+ if (this.debug) {
58
+ console.log("\u{1F441}\uFE0F IntersectionObserver initialized for visibility-based prefetching");
59
+ }
60
+ }
61
+ if (this.debug) {
62
+ console.log("\u2705 Prefetch Manager fully initialized");
63
+ console.log("\u{1F4A1} Run window.__PREFETCH_DEBUG__() to see current state");
64
+ window.__PREFETCH_DEBUG__ = () => this.logDebugInfo();
65
+ }
66
+ } catch (error) {
67
+ if (this.debug) {
68
+ console.error("\u274C Failed to initialize Prefetch Manager:", error);
69
+ }
70
+ }
71
+ }
72
+ /**
73
+ * Set the user segment for segment-based prefetch rules
74
+ * @param segment - The user's segment (e.g., 'premium', 'free', 'admin')
75
+ * @param fallbackToDefault - Use default rules if segment rules unavailable
76
+ */
77
+ setSegment(segment, fallbackToDefault = true) {
78
+ this.currentSegment = segment;
79
+ this.fallbackToDefault = fallbackToDefault;
80
+ if (this.debug) {
81
+ console.log(`\u{1F504} Segment updated: ${segment || "(none)"}`);
82
+ console.log(` Fallback to default: ${fallbackToDefault}`);
83
+ }
84
+ }
85
+ /**
86
+ * Get the current segment
87
+ */
88
+ getSegment() {
89
+ return this.currentSegment;
90
+ }
91
+ /**
92
+ * Prefetch routes based on current route
93
+ */
94
+ prefetch(currentRoute) {
95
+ const cleanRoute = currentRoute.split("?")[0].split("#")[0];
96
+ if (this.debug) {
97
+ console.log(`\u{1F4CD} Checking prefetch for route: ${currentRoute}`);
98
+ if (currentRoute !== cleanRoute) {
99
+ console.log(` Clean route: ${cleanRoute}`);
100
+ }
101
+ }
102
+ if (!this.config) {
103
+ if (this.debug) {
104
+ console.warn("\u26A0\uFE0F Config not loaded yet - cannot prefetch");
105
+ console.log(" Make sure the app was built with the plugin enabled");
106
+ }
107
+ return;
108
+ }
109
+ if (!this.shouldPrefetch()) {
110
+ if (this.debug) {
111
+ console.log("\u23ED\uFE0F Skipping prefetch due to network conditions");
112
+ }
113
+ return;
114
+ }
115
+ let routeConfig = this.config.routes[cleanRoute] || this.config.routes[currentRoute];
116
+ const matchedRoute = routeConfig ? this.config.routes[cleanRoute] ? cleanRoute : currentRoute : null;
117
+ if (!routeConfig) {
118
+ if (this.debug) {
119
+ console.warn(`\u26A0\uFE0F No prefetch rules configured for route: ${cleanRoute}`);
120
+ console.groupCollapsed("Available routes in config:");
121
+ Object.keys(this.config.routes).forEach((route) => {
122
+ const targets = this.config.routes[route].prefetch;
123
+ console.log(` ${route} \u2192 ${targets.length} target(s)`, targets.map((t) => t.route));
124
+ });
125
+ console.groupEnd();
126
+ console.log(`\u{1F4A1} Tip: Make sure your manualRules key matches exactly: "${cleanRoute}"`);
127
+ }
128
+ return;
129
+ }
130
+ let prefetchTargets = routeConfig.prefetch;
131
+ let ruleSource = "default";
132
+ if (this.currentSegment && routeConfig.segments?.[this.currentSegment]) {
133
+ prefetchTargets = routeConfig.segments[this.currentSegment];
134
+ ruleSource = `segment (${this.currentSegment})`;
135
+ } else if (this.currentSegment && !routeConfig.segments?.[this.currentSegment] && !this.fallbackToDefault) {
136
+ if (this.debug) {
137
+ console.warn(`\u26A0\uFE0F No prefetch rules for segment "${this.currentSegment}" and fallback disabled`);
138
+ }
139
+ return;
140
+ }
141
+ console.log(`\u2705 Found prefetch rule for: ${matchedRoute}`);
142
+ console.log(` Total targets to prefetch: ${prefetchTargets.length}`);
143
+ console.log(` Using: ${ruleSource} rules`);
144
+ console.log(` Strategy: ${this.strategy}`);
145
+ if (this.debug) {
146
+ console.groupCollapsed(`\u{1F4CA} Prefetch Rules for: ${matchedRoute} (${ruleSource})`);
147
+ prefetchTargets.forEach((target, index) => {
148
+ console.log(` ${index + 1}. ${target.route} (${target.priority} priority, ${(target.probability * 100).toFixed(1)}%)`);
149
+ });
150
+ console.groupEnd();
151
+ }
152
+ prefetchTargets.forEach((target) => {
153
+ this.prefetchTarget(target);
154
+ });
155
+ }
156
+ /**
157
+ * Prefetch a specific target
158
+ */
159
+ prefetchTarget(target) {
160
+ if (this.prefetched.has(target.route)) {
161
+ console.log(` \u23ED\uFE0F Already prefetched: ${target.route}`);
162
+ return;
163
+ }
164
+ console.log(` \u{1F517} Prefetch target: ${target.route}, chunk: ${target.chunk}`);
165
+ try {
166
+ switch (this.strategy) {
167
+ case "auto":
168
+ this.injectPrefetchLink(target);
169
+ break;
170
+ case "hover":
171
+ break;
172
+ case "visible":
173
+ break;
174
+ case "idle":
175
+ this.prefetchOnIdle(target);
176
+ break;
177
+ case "hybrid":
178
+ this.prefetchHybrid(target);
179
+ break;
180
+ default:
181
+ console.warn(`\u26A0\uFE0F Unknown strategy: ${this.strategy}`);
182
+ }
183
+ } catch (error) {
184
+ console.error(`\u274C Error prefetching ${target.route}:`, error);
185
+ }
186
+ }
187
+ /**
188
+ * Hybrid strategy: prioritize based on probability
189
+ * FOR TESTING: Fetch all priorities to verify chunks are correct
190
+ */
191
+ prefetchHybrid(target) {
192
+ if (target.priority === "high" || target.probability >= 0.7) {
193
+ console.log(` \u26A1 High priority (${(target.probability * 100).toFixed(1)}%) - Prefetching immediately`);
194
+ this.injectPrefetchLink(target);
195
+ } else if (target.priority === "medium" || target.probability >= 0.4) {
196
+ console.log(` \u23F1\uFE0F Medium priority (${(target.probability * 100).toFixed(1)}%) - Fetching immediately (TESTING MODE)`);
197
+ this.injectPrefetchLink(target);
198
+ } else {
199
+ console.log(` \u{1F514} Low priority (${(target.probability * 100).toFixed(1)}%) - Fetching immediately (TESTING MODE)`);
200
+ this.injectPrefetchLink(target);
201
+ }
202
+ }
203
+ /**
204
+ * Prefetch during idle time
205
+ */
206
+ prefetchOnIdle(target) {
207
+ if ("requestIdleCallback" in window) {
208
+ requestIdleCallback(() => {
209
+ this.injectPrefetchLink(target);
210
+ });
211
+ } else {
212
+ setTimeout(() => {
213
+ this.injectPrefetchLink(target);
214
+ }, 1e3);
215
+ }
216
+ }
217
+ /**
218
+ * Resolve chunk path for the current environment
219
+ * In production: chunks are built with hashes (e.g., chunks/Privacy-D5qJZu-O.js or js/index-CJMMxcQV.js)
220
+ * In dev mode: need to resolve to the actual module or use a proxy
221
+ */
222
+ resolveChunkPath(chunkPath, route) {
223
+ const isDev = window.location.hostname === "localhost" || window.location.hostname === "127.0.0.1";
224
+ if (!isDev) {
225
+ return `/${chunkPath}`;
226
+ }
227
+ let componentName = null;
228
+ const match1 = chunkPath.match(/\/([A-Z][a-zA-Z]*)-[a-zA-Z0-9_-]+\.js$/);
229
+ if (match1) {
230
+ componentName = match1[1];
231
+ }
232
+ const match2 = chunkPath.match(/\/(index)-[a-zA-Z0-9_-]+\.js$/);
233
+ if (match2) {
234
+ componentName = match2[1];
235
+ }
236
+ if (componentName) {
237
+ const sourceFile = componentName === "index" ? "/src/main.tsx" : `/src/pages/${componentName}.tsx`;
238
+ if (this.debug) {
239
+ console.log(` \u{1F4CD} Dev mode: Resolved ${chunkPath} \u2192 ${sourceFile}`);
240
+ }
241
+ return sourceFile;
242
+ }
243
+ if (this.debug) {
244
+ console.log(` \u26A0\uFE0F Dev mode: Could not extract component name from ${chunkPath}, using as-is`);
245
+ }
246
+ return `/${chunkPath}`;
247
+ }
248
+ /**
249
+ * Inject prefetch link into DOM
250
+ */
251
+ injectPrefetchLink(target) {
252
+ if (this.prefetched.has(target.route)) {
253
+ if (this.debug) {
254
+ console.log(` \u23ED\uFE0F Already prefetched: ${target.route}`);
255
+ }
256
+ return;
257
+ }
258
+ const chunkPath = this.resolveChunkPath(target.chunk, target.route);
259
+ const link = document.createElement("link");
260
+ link.rel = "modulepreload";
261
+ link.href = chunkPath;
262
+ link.setAttribute("data-prefetch-route", target.route);
263
+ link.setAttribute("data-prefetch-priority", target.priority);
264
+ link.setAttribute("data-prefetch-probability", target.probability.toString());
265
+ console.groupCollapsed(`\u{1F517} PREFETCH: ${target.route}`);
266
+ console.log(` \u{1F4C4} Page/Route: ${target.route}`);
267
+ console.log(` \u{1F4E6} Main Chunk: ${target.chunk}`);
268
+ console.log(` \u{1F310} Resolved URL: ${window.location.origin}${chunkPath}`);
269
+ console.log(` \u2B50 Priority: ${target.priority}`);
270
+ console.log(` \u{1F4CA} Probability: ${(target.probability * 100).toFixed(1)}%`);
271
+ let totalChunksForThisRoute = 1;
272
+ const injectedLinks = [];
273
+ try {
274
+ document.head.appendChild(link);
275
+ injectedLinks.push(target.chunk);
276
+ console.log(` \u2705 Main chunk link injected: ${target.chunk}`);
277
+ } catch (e) {
278
+ console.error(` \u274C Failed to inject main chunk link:`, e);
279
+ console.groupEnd();
280
+ return;
281
+ }
282
+ if (target.imports && target.imports.length > 0) {
283
+ console.log(` \u{1F4DA} Dependencies (${target.imports.length}):`);
284
+ target.imports.forEach((importChunk, index) => {
285
+ const importId = `import:${importChunk}`;
286
+ if (this.prefetched.has(importId)) {
287
+ console.log(` ${index + 1}. ${importChunk} (already prefetched)`);
288
+ return;
289
+ }
290
+ try {
291
+ const importLink = document.createElement("link");
292
+ importLink.rel = "modulepreload";
293
+ importLink.href = `/${importChunk}`;
294
+ importLink.setAttribute("data-prefetch-import", "true");
295
+ importLink.setAttribute("data-prefetch-parent", target.route);
296
+ document.head.appendChild(importLink);
297
+ this.prefetched.add(importId);
298
+ totalChunksForThisRoute++;
299
+ injectedLinks.push(importChunk);
300
+ console.log(` ${index + 1}. ${importChunk} \u2705`);
301
+ } catch (e) {
302
+ console.error(` ${index + 1}. ${importChunk} \u274C Error:`, e);
303
+ }
304
+ });
305
+ }
306
+ this.prefetched.add(target.route);
307
+ console.log(` \u2705 Total chunks injected: ${totalChunksForThisRoute}`);
308
+ console.log(` \u{1F4C8} Overall prefetched count: ${this.prefetched.size}`);
309
+ if (this.debug) {
310
+ console.log(` DOM Status: ${injectedLinks.length} link tag(s) added to document.head`);
311
+ console.log(` Injected URLs:`, injectedLinks.map((c) => `/${c}`));
312
+ setTimeout(() => {
313
+ const addedLink = document.querySelector(`link[data-prefetch-route="${target.route}"]`);
314
+ if (addedLink) {
315
+ console.log(` \u2714\uFE0F DOM Verification: Link exists`);
316
+ console.log(` href:`, addedLink.href);
317
+ console.log(` as:`, addedLink.getAttribute("as"));
318
+ console.log(` rel:`, addedLink.rel);
319
+ if (addedLink.relList?.contains("modulepreload")) {
320
+ console.log(` \u{1F504} Link has modulepreload rel (will fetch)`);
321
+ }
322
+ } else {
323
+ console.error(` \u274C ERROR: Link tag not found in DOM after 100ms`);
324
+ }
325
+ console.log(` \u{1F4CB} Verifying all injected links in head:`);
326
+ document.querySelectorAll("link[data-prefetch-route], link[data-prefetch-import]").forEach((el, idx) => {
327
+ const isMain = el.hasAttribute("data-prefetch-route");
328
+ const parent = isMain ? el.getAttribute("data-prefetch-route") : el.getAttribute("data-prefetch-parent");
329
+ console.log(` ${idx + 1}. ${el.href} (parent: ${parent})`);
330
+ });
331
+ }, 50);
332
+ }
333
+ console.groupEnd();
334
+ }
335
+ /**
336
+ * Check if prefetching should be performed based on network conditions
337
+ */
338
+ shouldPrefetch() {
339
+ const nav = navigator;
340
+ const connection = nav.connection || nav.mozConnection || nav.webkitConnection;
341
+ if (!connection) {
342
+ return true;
343
+ }
344
+ if (connection.saveData) {
345
+ if (this.debug) console.log(" \u26A0\uFE0F Data Saver enabled");
346
+ return false;
347
+ }
348
+ const slowConnections = ["slow-2g", "2g"];
349
+ if (slowConnections.includes(connection.effectiveType)) {
350
+ if (this.debug) console.log(` \u26A0\uFE0F Slow connection: ${connection.effectiveType}`);
351
+ return false;
352
+ }
353
+ if (connection.type === "cellular" && connection.effectiveType !== "4g") {
354
+ if (this.debug) console.log(" \u26A0\uFE0F Metered connection");
355
+ return false;
356
+ }
357
+ return true;
358
+ }
359
+ /**
360
+ * Initialize IntersectionObserver for 'visible' strategy
361
+ */
362
+ initIntersectionObserver() {
363
+ this.observer = new IntersectionObserver(
364
+ (entries) => {
365
+ entries.forEach((entry) => {
366
+ if (entry.isIntersecting) {
367
+ const route = entry.target.getAttribute("data-prefetch-route");
368
+ if (route && this.config) {
369
+ Object.values(this.config.routes).forEach((routeConfig) => {
370
+ const target = routeConfig.prefetch.find((t) => t.route === route);
371
+ if (target) {
372
+ this.injectPrefetchLink(target);
373
+ }
374
+ });
375
+ }
376
+ }
377
+ });
378
+ },
379
+ {
380
+ rootMargin: "50px"
381
+ // Start prefetch 50px before element is visible
382
+ }
383
+ );
384
+ }
385
+ /**
386
+ * Observe an element for visibility-based prefetching
387
+ */
388
+ observeLink(element, route) {
389
+ if (this.observer) {
390
+ element.setAttribute("data-prefetch-route", route);
391
+ this.observer.observe(element);
392
+ }
393
+ }
394
+ /**
395
+ * Manually trigger prefetch for a specific route
396
+ * Useful for hover events
397
+ */
398
+ prefetchRoute(route) {
399
+ if (!this.config) return;
400
+ Object.values(this.config.routes).forEach((routeConfig) => {
401
+ const target = routeConfig.prefetch.find((t) => t.route === route);
402
+ if (target) {
403
+ this.injectPrefetchLink(target);
404
+ }
405
+ });
406
+ }
407
+ /**
408
+ * Get prefetch statistics
409
+ */
410
+ getStats() {
411
+ return {
412
+ totalPrefetched: this.prefetched.size,
413
+ prefetchedRoutes: Array.from(this.prefetched),
414
+ configLoaded: this.config !== null,
415
+ strategy: this.strategy
416
+ };
417
+ }
418
+ /**
419
+ * Check if a route has been prefetched
420
+ */
421
+ isPrefetched(route) {
422
+ return this.prefetched.has(route);
423
+ }
424
+ /**
425
+ * Clear all prefetch state
426
+ */
427
+ clear() {
428
+ this.prefetched.clear();
429
+ if (this.observer) {
430
+ this.observer.disconnect();
431
+ }
432
+ }
433
+ /**
434
+ * Get all prefetch link elements currently in the DOM
435
+ */
436
+ getActivePrefetchLinks() {
437
+ return Array.from(document.querySelectorAll('link[rel="modulepreload"][data-prefetch-route]'));
438
+ }
439
+ /**
440
+ * Log current state for debugging
441
+ */
442
+ logDebugInfo() {
443
+ console.group("\u{1F41B} Smart Prefetch Debug Info");
444
+ console.log("Strategy:", this.strategy);
445
+ console.log("Config loaded:", this.config !== null);
446
+ console.log("Total prefetch entries:", this.prefetched.size);
447
+ console.log("Prefetched items:", Array.from(this.prefetched));
448
+ const links = this.getActivePrefetchLinks();
449
+ console.log("\n\u{1F517} Active Link Tags in DOM:", links.length);
450
+ if (links.length > 0) {
451
+ console.table(links.map((link) => ({
452
+ route: link.getAttribute("data-prefetch-route"),
453
+ chunk: link.href.replace(window.location.origin + "/", ""),
454
+ priority: link.getAttribute("data-prefetch-priority"),
455
+ probability: link.getAttribute("data-prefetch-probability")
456
+ })));
457
+ }
458
+ if (this.config) {
459
+ console.log("\n\u{1F4CA} Configuration Summary:");
460
+ console.log("Available routes in config:", Object.keys(this.config.routes).length);
461
+ console.log("Config environment:", this.config.environment);
462
+ console.group("\u{1F4CB} All configured routes with prefetch targets:");
463
+ Object.entries(this.config.routes).forEach(([route, data]) => {
464
+ console.group(`${route}`);
465
+ data.prefetch.forEach((t, idx) => {
466
+ console.log(` ${idx + 1}. ${t.route} (${t.priority}, ${(t.probability * 100).toFixed(1)}%) \u2192 ${t.chunk}`);
467
+ });
468
+ console.groupEnd();
469
+ });
470
+ console.groupEnd();
471
+ console.log("\n\u{1F4A1} Current location:", window.location.pathname);
472
+ console.log("\u{1F4A1} Clean route:", window.location.pathname.split("?")[0].split("#")[0]);
473
+ }
474
+ console.groupEnd();
475
+ }
476
+ /**
477
+ * Log all prefetched pages and chunks (summary view)
478
+ */
479
+ logPrefetchSummary() {
480
+ const links = this.getActivePrefetchLinks();
481
+ const routeLinks = links.filter((l) => !l.getAttribute("data-prefetch-import"));
482
+ const dependencyLinks = links.filter((l) => l.getAttribute("data-prefetch-import"));
483
+ console.group("\u{1F4CA} PREFETCH SUMMARY");
484
+ console.log(`Total pages prefetched: ${routeLinks.length}`);
485
+ console.log(`Total dependency chunks: ${dependencyLinks.length}`);
486
+ console.log(`Total overall entries: ${this.prefetched.size}`);
487
+ if (routeLinks.length > 0) {
488
+ console.group("\u{1F4C4} Pages/Routes Prefetched:");
489
+ const pageTable = routeLinks.map((link) => ({
490
+ route: link.getAttribute("data-prefetch-route"),
491
+ chunk: link.href.replace(window.location.origin + "/", ""),
492
+ priority: link.getAttribute("data-prefetch-priority"),
493
+ probability: `${link.getAttribute("data-prefetch-probability")}`
494
+ }));
495
+ console.table(pageTable);
496
+ console.groupEnd();
497
+ }
498
+ if (dependencyLinks.length > 0) {
499
+ console.group("\u{1F4E6} Dependency Chunks Prefetched:");
500
+ const depsTable = dependencyLinks.map((link) => ({
501
+ parentRoute: link.getAttribute("data-prefetch-parent"),
502
+ chunk: link.href.replace(window.location.origin + "/", "")
503
+ }));
504
+ console.table(depsTable);
505
+ console.groupEnd();
506
+ }
507
+ console.groupEnd();
508
+ }
509
+ };
510
+
511
+ // src/runtime/debug-utils.ts
512
+ function getPrefetchLinks() {
513
+ return Array.from(document.querySelectorAll('link[rel="prefetch"]'));
514
+ }
515
+ function getPluginPrefetchLinks() {
516
+ return Array.from(document.querySelectorAll('link[rel="prefetch"][data-prefetch-route]'));
517
+ }
518
+ function logPrefetchLinks() {
519
+ const allLinks = getPrefetchLinks();
520
+ const pluginLinks = getPluginPrefetchLinks();
521
+ console.group("\u{1F517} Prefetch Link Tags in DOM");
522
+ console.log(`Total prefetch links: ${allLinks.length}`);
523
+ console.log(`Plugin-managed links: ${pluginLinks.length}`);
524
+ if (pluginLinks.length > 0) {
525
+ console.group("Plugin-managed links:");
526
+ console.table(
527
+ pluginLinks.map((link) => ({
528
+ route: link.getAttribute("data-prefetch-route"),
529
+ href: link.href,
530
+ priority: link.getAttribute("data-prefetch-priority"),
531
+ probability: link.getAttribute("data-prefetch-probability"),
532
+ loaded: link.hasAttribute("data-loaded")
533
+ }))
534
+ );
535
+ console.groupEnd();
536
+ }
537
+ const otherLinks = allLinks.filter((link) => !link.hasAttribute("data-prefetch-route"));
538
+ if (otherLinks.length > 0) {
539
+ console.group("Other prefetch links:");
540
+ console.table(
541
+ otherLinks.map((link) => ({
542
+ href: link.href,
543
+ as: link.getAttribute("as")
544
+ }))
545
+ );
546
+ console.groupEnd();
547
+ }
548
+ console.groupEnd();
549
+ }
550
+ function monitorPrefetchActivity() {
551
+ console.log("\u{1F50D} Monitoring prefetch activity...");
552
+ console.log("Press the returned stop function to stop monitoring");
553
+ const observer = new MutationObserver((mutations) => {
554
+ mutations.forEach((mutation) => {
555
+ mutation.addedNodes.forEach((node) => {
556
+ if (node.nodeName === "LINK") {
557
+ const link = node;
558
+ if (link.rel === "prefetch") {
559
+ console.log("\u2795 New prefetch link added:", {
560
+ route: link.getAttribute("data-prefetch-route") || "N/A",
561
+ href: link.href,
562
+ priority: link.getAttribute("data-prefetch-priority")
563
+ });
564
+ }
565
+ }
566
+ });
567
+ mutation.removedNodes.forEach((node) => {
568
+ if (node.nodeName === "LINK") {
569
+ const link = node;
570
+ if (link.rel === "prefetch") {
571
+ console.log("\u2796 Prefetch link removed:", {
572
+ route: link.getAttribute("data-prefetch-route") || "N/A",
573
+ href: link.href
574
+ });
575
+ }
576
+ }
577
+ });
578
+ });
579
+ });
580
+ observer.observe(document.head, {
581
+ childList: true,
582
+ subtree: true
583
+ });
584
+ return () => {
585
+ console.log("\u{1F6D1} Stopped monitoring prefetch activity");
586
+ observer.disconnect();
587
+ };
588
+ }
589
+ function checkPluginConfiguration() {
590
+ console.group("\u{1F527} Smart Prefetch Plugin Configuration Check");
591
+ const globalConfig = window.__SMART_PREFETCH__;
592
+ if (globalConfig) {
593
+ console.log("\u2705 Global config found:", globalConfig);
594
+ } else {
595
+ console.warn("\u274C Global config not found on window.__SMART_PREFETCH__");
596
+ console.log(" The plugin may not be properly configured in vite.config");
597
+ }
598
+ fetch("/prefetch-config.json").then((res) => {
599
+ if (res.ok) {
600
+ console.log("\u2705 prefetch-config.json is accessible");
601
+ return res.json();
602
+ } else {
603
+ throw new Error(`HTTP ${res.status}: ${res.statusText}`);
604
+ }
605
+ }).then((config) => {
606
+ console.log("\u{1F4CB} Config content:", config);
607
+ console.log(` Routes: ${Object.keys(config.routes).length}`);
608
+ console.log(` Environment: ${config.environment}`);
609
+ }).catch((error) => {
610
+ console.error("\u274C Cannot access prefetch-config.json:", error.message);
611
+ console.log(" Make sure to build the app first: pnpm build");
612
+ }).finally(() => {
613
+ console.groupEnd();
614
+ });
615
+ if (typeof window.__PREFETCH_DEBUG__ === "function") {
616
+ console.log("\u2705 Debug function available: window.__PREFETCH_DEBUG__()");
617
+ } else {
618
+ console.warn("\u26A0\uFE0F Debug function not available (may not be initialized yet)");
619
+ }
620
+ }
621
+ function exposeDebugUtils() {
622
+ const w = window;
623
+ w.__PREFETCH_UTILS__ = {
624
+ getPrefetchLinks,
625
+ getPluginPrefetchLinks,
626
+ logPrefetchLinks,
627
+ monitorPrefetchActivity,
628
+ checkPluginConfiguration
629
+ };
630
+ console.log("\u{1F4A1} Debug utilities exposed:");
631
+ console.log(" window.__PREFETCH_UTILS__.getPrefetchLinks()");
632
+ console.log(" window.__PREFETCH_UTILS__.logPrefetchLinks()");
633
+ console.log(" window.__PREFETCH_UTILS__.monitorPrefetchActivity()");
634
+ console.log(" window.__PREFETCH_UTILS__.checkPluginConfiguration()");
635
+ }
636
+ export {
637
+ PrefetchManager,
638
+ checkPluginConfiguration,
639
+ exposeDebugUtils,
640
+ getPluginPrefetchLinks,
641
+ getPrefetchLinks,
642
+ logPrefetchLinks,
643
+ monitorPrefetchActivity
644
+ };
645
+ //# sourceMappingURL=index.js.map