vite-plugin-smart-prefetch 0.4.0 → 0.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +23 -191
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -19
- package/dist/index.d.ts +2 -19
- package/dist/index.js +23 -191
- package/dist/index.js.map +1 -1
- package/dist/react/index.cjs +70 -211
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +112 -127
- package/dist/react/index.d.ts +112 -127
- package/dist/react/index.js +55 -181
- package/dist/react/index.js.map +1 -1
- package/dist/runtime/index.cjs +35 -35
- package/dist/runtime/index.cjs.map +1 -1
- package/dist/runtime/index.d.cts +30 -25
- package/dist/runtime/index.d.ts +30 -25
- package/dist/runtime/index.js +35 -35
- package/dist/runtime/index.js.map +1 -1
- package/package.json +4 -8
package/dist/index.cjs
CHANGED
|
@@ -574,7 +574,7 @@ ${"\u2550".repeat(60)}`);
|
|
|
574
574
|
}
|
|
575
575
|
};
|
|
576
576
|
|
|
577
|
-
// src/plugin/model/
|
|
577
|
+
// src/plugin/model/prefetch-ml-trainer.ts
|
|
578
578
|
var MarkovChainTrainer = class {
|
|
579
579
|
constructor(config, debug = false) {
|
|
580
580
|
this.config = config;
|
|
@@ -754,57 +754,6 @@ var MarkovChainTrainer = class {
|
|
|
754
754
|
topDestination
|
|
755
755
|
};
|
|
756
756
|
}
|
|
757
|
-
/**
|
|
758
|
-
* Train segment-specific Markov models from navigation data with segment field
|
|
759
|
-
* Creates separate models for each user segment/role
|
|
760
|
-
*/
|
|
761
|
-
trainSegmentedModels(navigationDataWithSegments, environment) {
|
|
762
|
-
if (this.debug) {
|
|
763
|
-
console.log(`
|
|
764
|
-
\u{1F916} Training Segment-Specific Markov Models...`);
|
|
765
|
-
}
|
|
766
|
-
const dataBySegment = /* @__PURE__ */ new Map();
|
|
767
|
-
navigationDataWithSegments.forEach((data) => {
|
|
768
|
-
const segment = data.segment || "default";
|
|
769
|
-
if (!dataBySegment.has(segment)) {
|
|
770
|
-
dataBySegment.set(segment, []);
|
|
771
|
-
}
|
|
772
|
-
dataBySegment.get(segment).push({
|
|
773
|
-
from: data.from,
|
|
774
|
-
to: data.to,
|
|
775
|
-
count: data.count
|
|
776
|
-
});
|
|
777
|
-
});
|
|
778
|
-
if (this.debug) {
|
|
779
|
-
console.log(`
|
|
780
|
-
\u{1F4CA} Detected segments:`);
|
|
781
|
-
dataBySegment.forEach((data, segment) => {
|
|
782
|
-
console.log(` \u2022 ${segment}: ${data.length} transitions`);
|
|
783
|
-
});
|
|
784
|
-
}
|
|
785
|
-
const segmentModels = /* @__PURE__ */ new Map();
|
|
786
|
-
dataBySegment.forEach((navigationData, segment) => {
|
|
787
|
-
if (this.debug) {
|
|
788
|
-
console.log(`
|
|
789
|
-
\u{1F504} Training model for segment: "${segment}"`);
|
|
790
|
-
}
|
|
791
|
-
const model = this.trainMLModel(navigationData, environment);
|
|
792
|
-
model.dataSource.provider = `markov-chain[${segment}]`;
|
|
793
|
-
segmentModels.set(segment, model);
|
|
794
|
-
if (this.debug) {
|
|
795
|
-
const totalTargets = Object.values(model.routes).reduce(
|
|
796
|
-
(sum, route) => sum + (route.prefetch?.length || 0),
|
|
797
|
-
0
|
|
798
|
-
);
|
|
799
|
-
console.log(` \u2705 Model for "${segment}" trained with ${totalTargets} prefetch targets`);
|
|
800
|
-
}
|
|
801
|
-
});
|
|
802
|
-
if (this.debug) {
|
|
803
|
-
console.log(`
|
|
804
|
-
\u2705 All ${segmentModels.size} segment models trained successfully`);
|
|
805
|
-
}
|
|
806
|
-
return segmentModels;
|
|
807
|
-
}
|
|
808
757
|
/**
|
|
809
758
|
* Get date range string
|
|
810
759
|
*/
|
|
@@ -837,7 +786,6 @@ var ConfigGenerator = class {
|
|
|
837
786
|
}
|
|
838
787
|
/**
|
|
839
788
|
* Generate final prefetch configuration with chunk mappings
|
|
840
|
-
* Includes common prefetch rules and segment-specific rules if available
|
|
841
789
|
*/
|
|
842
790
|
generate(model) {
|
|
843
791
|
if (this.debug) {
|
|
@@ -846,9 +794,6 @@ var ConfigGenerator = class {
|
|
|
846
794
|
console.log(` Manifest entries: ${Object.keys(this.manifest).length}`);
|
|
847
795
|
console.log(` Model routes: ${Object.keys(model.routes).length}`);
|
|
848
796
|
console.log(` Manual rules: ${Object.keys(this.manualRules).length}`);
|
|
849
|
-
if (Object.values(model.routes).some((r) => r.segments)) {
|
|
850
|
-
console.log(` \u2139\uFE0F Segment-based rules detected`);
|
|
851
|
-
}
|
|
852
797
|
}
|
|
853
798
|
const mergedModel = this.mergeManualRules(model);
|
|
854
799
|
const routePatterns = this.extractRoutePatterns(Object.keys(mergedModel.routes));
|
|
@@ -869,10 +814,8 @@ var ConfigGenerator = class {
|
|
|
869
814
|
};
|
|
870
815
|
let mappedRoutes = 0;
|
|
871
816
|
let unmappedRoutes = 0;
|
|
872
|
-
let totalSegmentRules = 0;
|
|
873
817
|
Object.entries(mergedModel.routes).forEach(([sourceRoute, prediction]) => {
|
|
874
818
|
const prefetchTargets = [];
|
|
875
|
-
const segmentConfigs = {};
|
|
876
819
|
const sourceChunk = this.routeToChunk(sourceRoute);
|
|
877
820
|
if (sourceChunk && !config.chunks[sourceRoute]) {
|
|
878
821
|
config.chunks[sourceRoute] = sourceChunk;
|
|
@@ -911,46 +854,12 @@ var ConfigGenerator = class {
|
|
|
911
854
|
unmappedRoutes++;
|
|
912
855
|
}
|
|
913
856
|
});
|
|
914
|
-
if (prediction.segments) {
|
|
915
|
-
Object.entries(prediction.segments).forEach(([segment, segmentTargets]) => {
|
|
916
|
-
const segmentPrefetchTargets = [];
|
|
917
|
-
segmentTargets.forEach((target) => {
|
|
918
|
-
const chunkFile = this.routeToChunk(target.route);
|
|
919
|
-
if (chunkFile) {
|
|
920
|
-
const manifestEntry = this.getManifestEntryByFile(chunkFile);
|
|
921
|
-
const importChunkIds = manifestEntry?.imports || [];
|
|
922
|
-
const imports = importChunkIds.map((chunkId) => {
|
|
923
|
-
const entry = this.manifest[chunkId];
|
|
924
|
-
return entry?.file;
|
|
925
|
-
}).filter((file) => !!file);
|
|
926
|
-
segmentPrefetchTargets.push({
|
|
927
|
-
...target,
|
|
928
|
-
chunk: chunkFile,
|
|
929
|
-
chunk_prod: chunkFile,
|
|
930
|
-
// NEW: Include production chunk path
|
|
931
|
-
imports
|
|
932
|
-
});
|
|
933
|
-
config.chunks[target.route] = chunkFile;
|
|
934
|
-
totalSegmentRules++;
|
|
935
|
-
}
|
|
936
|
-
});
|
|
937
|
-
if (segmentPrefetchTargets.length > 0) {
|
|
938
|
-
segmentConfigs[segment] = segmentPrefetchTargets;
|
|
939
|
-
}
|
|
940
|
-
});
|
|
941
|
-
if (this.debug && Object.keys(segmentConfigs).length > 0) {
|
|
942
|
-
console.log(` \u{1F465} Segment configs for ${sourceRoute}: ${Object.keys(segmentConfigs).join(", ")}`);
|
|
943
|
-
}
|
|
944
|
-
}
|
|
945
857
|
const patterns = routePatterns[sourceRoute] || [sourceRoute];
|
|
946
|
-
if (prefetchTargets.length > 0
|
|
858
|
+
if (prefetchTargets.length > 0) {
|
|
947
859
|
config.routes[sourceRoute] = {
|
|
948
860
|
patterns,
|
|
949
|
-
//
|
|
861
|
+
// Include patterns for dynamic route matching
|
|
950
862
|
prefetch: prefetchTargets,
|
|
951
|
-
...Object.keys(segmentConfigs).length > 0 && {
|
|
952
|
-
segments: segmentConfigs
|
|
953
|
-
},
|
|
954
863
|
metadata: prediction.metadata
|
|
955
864
|
};
|
|
956
865
|
}
|
|
@@ -959,21 +868,8 @@ var ConfigGenerator = class {
|
|
|
959
868
|
console.log(`\u2705 Configuration generated`);
|
|
960
869
|
console.log(` Routes with prefetch: ${Object.keys(config.routes).length}`);
|
|
961
870
|
console.log(` Mapped chunks: ${mappedRoutes}`);
|
|
962
|
-
console.log(` Segment-specific rules: ${totalSegmentRules}`);
|
|
963
871
|
console.log(` Unmapped routes: ${unmappedRoutes}`);
|
|
964
872
|
}
|
|
965
|
-
const allSegments = /* @__PURE__ */ new Set();
|
|
966
|
-
Object.values(config.routes).forEach((route) => {
|
|
967
|
-
if (route.segments) {
|
|
968
|
-
Object.keys(route.segments).forEach((seg) => allSegments.add(seg));
|
|
969
|
-
}
|
|
970
|
-
});
|
|
971
|
-
if (allSegments.size > 0) {
|
|
972
|
-
config.segmentInfo = {
|
|
973
|
-
available: Array.from(allSegments),
|
|
974
|
-
description: "Load segment-specific config based on user role/segment"
|
|
975
|
-
};
|
|
976
|
-
}
|
|
977
873
|
return config;
|
|
978
874
|
}
|
|
979
875
|
/**
|
|
@@ -1167,32 +1063,6 @@ var ConfigGenerator = class {
|
|
|
1167
1063
|
}
|
|
1168
1064
|
return null;
|
|
1169
1065
|
}
|
|
1170
|
-
/**
|
|
1171
|
-
* Generate segment-specific prefetch configurations
|
|
1172
|
-
* Creates one config per user segment/role
|
|
1173
|
-
*/
|
|
1174
|
-
generateSegmentConfigs(segmentModels) {
|
|
1175
|
-
const segmentConfigs = /* @__PURE__ */ new Map();
|
|
1176
|
-
segmentModels.forEach((model, segment) => {
|
|
1177
|
-
if (this.debug) {
|
|
1178
|
-
console.log(`
|
|
1179
|
-
\u{1F4E6} Generating config for segment: "${segment}"`);
|
|
1180
|
-
}
|
|
1181
|
-
const config = this.generate(model);
|
|
1182
|
-
config.segment = segment;
|
|
1183
|
-
segmentConfigs.set(segment, config);
|
|
1184
|
-
if (this.debug) {
|
|
1185
|
-
console.log(` \u2705 Config generated for "${segment}"`);
|
|
1186
|
-
console.log(` Routes: ${Object.keys(config.routes).length}`);
|
|
1187
|
-
console.log(` Chunks: ${Object.keys(config.chunks).length}`);
|
|
1188
|
-
}
|
|
1189
|
-
});
|
|
1190
|
-
if (this.debug) {
|
|
1191
|
-
console.log(`
|
|
1192
|
-
\u2705 Generated ${segmentConfigs.size} segment-specific configurations`);
|
|
1193
|
-
}
|
|
1194
|
-
return segmentConfigs;
|
|
1195
|
-
}
|
|
1196
1066
|
};
|
|
1197
1067
|
|
|
1198
1068
|
// src/plugin/cache-manager.ts
|
|
@@ -1368,7 +1238,6 @@ function smartPrefetch(options = {}) {
|
|
|
1368
1238
|
let config;
|
|
1369
1239
|
let cacheManager;
|
|
1370
1240
|
let prefetchModel = null;
|
|
1371
|
-
let segmentModels = null;
|
|
1372
1241
|
return {
|
|
1373
1242
|
name: "@farmart/vite-plugin-smart-prefetch",
|
|
1374
1243
|
enforce: "post",
|
|
@@ -1449,9 +1318,6 @@ function smartPrefetch(options = {}) {
|
|
|
1449
1318
|
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
1450
1319
|
res.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
|
|
1451
1320
|
res.end(JSON.stringify(finalConfig, null, 2));
|
|
1452
|
-
if (debug) {
|
|
1453
|
-
console.log("\u{1F4E4} Serving fresh prefetch-config.json from development server");
|
|
1454
|
-
}
|
|
1455
1321
|
return;
|
|
1456
1322
|
} catch (error) {
|
|
1457
1323
|
if (debug) {
|
|
@@ -1489,37 +1355,30 @@ function smartPrefetch(options = {}) {
|
|
|
1489
1355
|
debug,
|
|
1490
1356
|
analytics.credentials.keyFilePath
|
|
1491
1357
|
);
|
|
1492
|
-
|
|
1358
|
+
if (debug) {
|
|
1359
|
+
console.log("\n\u{1F3AF} Using real navigation data from BigQuery GA4 export...");
|
|
1360
|
+
}
|
|
1493
1361
|
const navigationData = await bqConnector.fetchNavigationSequences(analytics.dataRange);
|
|
1494
1362
|
if (navigationData.length === 0) {
|
|
1495
1363
|
console.warn("\u26A0\uFE0F No navigation data found, using manual rules only");
|
|
1496
1364
|
prefetchModel = createManualModel(manualRules, environment);
|
|
1497
1365
|
return;
|
|
1498
1366
|
}
|
|
1499
|
-
|
|
1367
|
+
if (debug) {
|
|
1368
|
+
console.log(`
|
|
1500
1369
|
\u{1F916} Training model using Markov Chain ML...`);
|
|
1370
|
+
}
|
|
1501
1371
|
const mlTrainer = new MarkovChainTrainer(analytics.model, debug);
|
|
1502
1372
|
const prefetchModelResult = mlTrainer.trainMLModel(navigationData, environment);
|
|
1503
1373
|
prefetchModel = prefetchModelResult;
|
|
1504
1374
|
await cacheManager.set(environment, prefetchModel);
|
|
1505
|
-
try {
|
|
1506
|
-
const navigationWithSegments = await bqConnector.fetchNavigationWithSegments(analytics.dataRange);
|
|
1507
|
-
if (navigationWithSegments.length > 0) {
|
|
1508
|
-
console.log(`
|
|
1509
|
-
\u{1F465} Training segment-specific models...`);
|
|
1510
|
-
segmentModels = mlTrainer.trainSegmentedModels(navigationWithSegments, environment);
|
|
1511
|
-
if (debug && segmentModels.size > 0) {
|
|
1512
|
-
console.log(` \u2705 Trained ${segmentModels.size} segment-specific models`);
|
|
1513
|
-
}
|
|
1514
|
-
}
|
|
1515
|
-
} catch (error) {
|
|
1516
|
-
if (debug) {
|
|
1517
|
-
console.warn(`\u26A0\uFE0F Could not train segment models:`, error instanceof Error ? error.message : "Unknown error");
|
|
1518
|
-
}
|
|
1519
|
-
}
|
|
1520
1375
|
} catch (error) {
|
|
1521
|
-
|
|
1522
|
-
|
|
1376
|
+
if (debug) {
|
|
1377
|
+
console.error("\u274C Failed to fetch analytics data:", error);
|
|
1378
|
+
}
|
|
1379
|
+
if (debug) {
|
|
1380
|
+
console.log("\u26A0\uFE0F Falling back to manual rules only");
|
|
1381
|
+
}
|
|
1523
1382
|
prefetchModel = createManualModel(manualRules, environment);
|
|
1524
1383
|
if (debug) {
|
|
1525
1384
|
console.error("Error details:", error);
|
|
@@ -1528,7 +1387,9 @@ function smartPrefetch(options = {}) {
|
|
|
1528
1387
|
},
|
|
1529
1388
|
async writeBundle(outputOptions) {
|
|
1530
1389
|
if (!prefetchModel) {
|
|
1531
|
-
|
|
1390
|
+
if (debug) {
|
|
1391
|
+
console.warn("\u26A0\uFE0F No prefetch model available, skipping config generation");
|
|
1392
|
+
}
|
|
1532
1393
|
return;
|
|
1533
1394
|
}
|
|
1534
1395
|
const fs2 = await import("fs");
|
|
@@ -1536,7 +1397,9 @@ function smartPrefetch(options = {}) {
|
|
|
1536
1397
|
const outDir = outputOptions.dir || "dist";
|
|
1537
1398
|
const manifestPath = path2.join(outDir, ".vite", "manifest.json");
|
|
1538
1399
|
if (!fs2.existsSync(manifestPath)) {
|
|
1539
|
-
|
|
1400
|
+
if (debug) {
|
|
1401
|
+
console.warn("\u26A0\uFE0F Vite manifest not found at:", manifestPath);
|
|
1402
|
+
}
|
|
1540
1403
|
return;
|
|
1541
1404
|
}
|
|
1542
1405
|
const manifestContent = fs2.readFileSync(manifestPath, "utf-8");
|
|
@@ -1548,10 +1411,10 @@ function smartPrefetch(options = {}) {
|
|
|
1548
1411
|
const generator = new ConfigGenerator(manifest, manualRules, debug);
|
|
1549
1412
|
const finalConfig = generator.generate(prefetchModel);
|
|
1550
1413
|
const validation = generator.validateChunks(finalConfig);
|
|
1551
|
-
if (!validation.valid) {
|
|
1414
|
+
if (!validation.valid && debug) {
|
|
1552
1415
|
console.warn("\u26A0\uFE0F Some chunks could not be mapped:");
|
|
1553
1416
|
validation.missing.forEach((m) => console.warn(` ${m}`));
|
|
1554
|
-
} else {
|
|
1417
|
+
} else if (debug) {
|
|
1555
1418
|
console.log(`\u2705 All ${Object.keys(finalConfig.chunks).length} chunks successfully mapped with real build hashes`);
|
|
1556
1419
|
}
|
|
1557
1420
|
const configPath = path2.join(outDir, "prefetch-config.json");
|
|
@@ -1564,37 +1427,6 @@ function smartPrefetch(options = {}) {
|
|
|
1564
1427
|
console.log(`\u{1F4CA} Total routes configured: ${Object.keys(finalConfig.routes).length}`);
|
|
1565
1428
|
console.log(`\u{1F4E6} Total chunks: ${Object.keys(finalConfig.chunks).length}`);
|
|
1566
1429
|
}
|
|
1567
|
-
if (segmentModels && segmentModels.size > 0) {
|
|
1568
|
-
console.log(`
|
|
1569
|
-
\u{1F4C1} Generating segment-specific prefetch configurations...`);
|
|
1570
|
-
const segmentGenerator = new ConfigGenerator(manifest, manualRules, debug);
|
|
1571
|
-
const segmentConfigs = segmentGenerator.generateSegmentConfigs(segmentModels);
|
|
1572
|
-
const segmentDir = path2.join(outDir, "prefetch-configs");
|
|
1573
|
-
if (!fs2.existsSync(segmentDir)) {
|
|
1574
|
-
fs2.mkdirSync(segmentDir, { recursive: true });
|
|
1575
|
-
}
|
|
1576
|
-
segmentConfigs.forEach((segConfig, segment) => {
|
|
1577
|
-
const segmentPath = path2.join(segmentDir, `${segment}.json`);
|
|
1578
|
-
fs2.writeFileSync(segmentPath, JSON.stringify(segConfig, null, 2));
|
|
1579
|
-
if (debug) {
|
|
1580
|
-
console.log(` \u2705 Emitted ${segment}.json (${Object.keys(segConfig.routes).length} routes)`);
|
|
1581
|
-
}
|
|
1582
|
-
});
|
|
1583
|
-
const segmentIndex = {
|
|
1584
|
-
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1585
|
-
environment: analytics?.environment || (config.command === "serve" ? "development" : "production"),
|
|
1586
|
-
segments: Array.from(segmentConfigs.keys()),
|
|
1587
|
-
description: "Segment-specific prefetch configurations. Use based on user role/segment."
|
|
1588
|
-
};
|
|
1589
|
-
const segmentIndexPath = path2.join(segmentDir, "index.json");
|
|
1590
|
-
fs2.writeFileSync(segmentIndexPath, JSON.stringify(segmentIndex, null, 2));
|
|
1591
|
-
if (debug) {
|
|
1592
|
-
console.log(`
|
|
1593
|
-
\u2705 Emitted ${segmentConfigs.size} segment-specific configurations`);
|
|
1594
|
-
console.log(` Location: ${segmentDir}`);
|
|
1595
|
-
console.log(` Segments: ${Array.from(segmentConfigs.keys()).join(", ")}`);
|
|
1596
|
-
}
|
|
1597
|
-
}
|
|
1598
1430
|
if (analytics?.dashboard) {
|
|
1599
1431
|
const dashboardHtml = generateDashboard(finalConfig);
|
|
1600
1432
|
const dashboardPath = path2.join(outDir, "prefetch-report.html");
|