veryfront 0.1.851 → 0.1.852
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/esm/deno.js +1 -1
- package/esm/src/html/hydration-script-builder/templates/router.d.ts.map +1 -1
- package/esm/src/html/hydration-script-builder/templates/router.js +117 -2
- package/esm/src/react/runtime/core.js +1 -1
- package/esm/src/utils/version-constant.d.ts +1 -1
- package/esm/src/utils/version-constant.js +1 -1
- package/package.json +1 -1
package/esm/deno.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../../../../../src/src/html/hydration-script-builder/templates/router.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,eAAe,
|
|
1
|
+
{"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../../../../../src/src/html/hydration-script-builder/templates/router.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,eAAe,cAklC3B,CAAC"}
|
|
@@ -36,6 +36,10 @@ export const getRouterScript = () => `
|
|
|
36
36
|
const BACKGROUND_REFRESH_INTERVAL_MS = 30 * 1000;
|
|
37
37
|
const PREFETCH_DELAY_MS = 100;
|
|
38
38
|
const MAX_PREFETCH_PATHS = 100;
|
|
39
|
+
const IDLE_PREFETCH_DELAY_MS = 1200;
|
|
40
|
+
const IDLE_PREFETCH_MAX_LINKS = 4;
|
|
41
|
+
const VIEWPORT_PREFETCH_MAX_LINKS = 8;
|
|
42
|
+
const VIEWPORT_PREFETCH_ROOT_MARGIN = '200px';
|
|
39
43
|
const MAX_ROUTE_TIMINGS = 100;
|
|
40
44
|
const MAX_SERVER_TIMING_LENGTH = 1024;
|
|
41
45
|
|
|
@@ -758,6 +762,7 @@ export const getRouterScript = () => `
|
|
|
758
762
|
container.__reactRoot.render(tree);
|
|
759
763
|
perfEnd('render:reactRender');
|
|
760
764
|
log('Page re-rendered via SPA');
|
|
765
|
+
scheduleRoutePrefetchRefresh();
|
|
761
766
|
return;
|
|
762
767
|
}
|
|
763
768
|
|
|
@@ -773,6 +778,9 @@ export const getRouterScript = () => `
|
|
|
773
778
|
// ============================================
|
|
774
779
|
let prefetchTimeout = null;
|
|
775
780
|
let currentHoverLink = null;
|
|
781
|
+
let routePrefetchRefreshPending = false;
|
|
782
|
+
let viewportPrefetchObserver = null;
|
|
783
|
+
const observedPrefetchLinks = new WeakSet();
|
|
776
784
|
const prefetchedPaths = new Set();
|
|
777
785
|
const inFlightPrefetches = new Set();
|
|
778
786
|
|
|
@@ -794,6 +802,51 @@ export const getRouterScript = () => `
|
|
|
794
802
|
return allPaths;
|
|
795
803
|
}
|
|
796
804
|
|
|
805
|
+
function getCurrentRouteHref() {
|
|
806
|
+
return window.location.pathname + window.location.search;
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
function getInternalRouteHrefFromLink(link) {
|
|
810
|
+
if (
|
|
811
|
+
!link ||
|
|
812
|
+
link.target === '_blank' ||
|
|
813
|
+
link.hasAttribute('download') ||
|
|
814
|
+
link.getAttribute('data-prefetch') === 'false'
|
|
815
|
+
) {
|
|
816
|
+
return null;
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
const href = link.getAttribute('href');
|
|
820
|
+
if (!href || href.startsWith('#') || href.startsWith('//') || !href.startsWith('/')) return null;
|
|
821
|
+
|
|
822
|
+
try {
|
|
823
|
+
const url = new URL(href, window.location.origin);
|
|
824
|
+
if (url.origin !== window.location.origin) return null;
|
|
825
|
+
|
|
826
|
+
const routeHref = url.pathname + url.search;
|
|
827
|
+
return routeHref === getCurrentRouteHref() ? null : routeHref;
|
|
828
|
+
} catch (_) {
|
|
829
|
+
return null;
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
function getEligiblePrefetchLinks(limit) {
|
|
834
|
+
const links = [];
|
|
835
|
+
const seenHrefs = new Set();
|
|
836
|
+
|
|
837
|
+
for (const link of document.querySelectorAll('a[href]')) {
|
|
838
|
+
const href = getInternalRouteHrefFromLink(link);
|
|
839
|
+
if (!href || seenHrefs.has(href)) continue;
|
|
840
|
+
|
|
841
|
+
seenHrefs.add(href);
|
|
842
|
+
links.push({ link, href });
|
|
843
|
+
|
|
844
|
+
if (links.length >= limit) break;
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
return links;
|
|
848
|
+
}
|
|
849
|
+
|
|
797
850
|
async function preloadModulesForPageData(pageData, path) {
|
|
798
851
|
if (!pageData) return;
|
|
799
852
|
if (pageData.releaseId && window.__veryfrontSetReleaseId) {
|
|
@@ -842,6 +895,62 @@ export const getRouterScript = () => `
|
|
|
842
895
|
});
|
|
843
896
|
}
|
|
844
897
|
|
|
898
|
+
function prefetchEligibleRouteLinks(limit) {
|
|
899
|
+
for (const { href } of getEligiblePrefetchLinks(limit)) {
|
|
900
|
+
prefetchPage(href);
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
function ensureViewportPrefetchObserver() {
|
|
905
|
+
if (viewportPrefetchObserver || typeof IntersectionObserver !== 'function') {
|
|
906
|
+
return viewportPrefetchObserver;
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
viewportPrefetchObserver = new IntersectionObserver((entries) => {
|
|
910
|
+
for (const entry of entries) {
|
|
911
|
+
if (!entry.isIntersecting) continue;
|
|
912
|
+
|
|
913
|
+
viewportPrefetchObserver?.unobserve(entry.target);
|
|
914
|
+
const href = getInternalRouteHrefFromLink(entry.target);
|
|
915
|
+
if (href) prefetchPage(href);
|
|
916
|
+
}
|
|
917
|
+
}, { rootMargin: VIEWPORT_PREFETCH_ROOT_MARGIN });
|
|
918
|
+
|
|
919
|
+
return viewportPrefetchObserver;
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
function observeViewportPrefetchLinks() {
|
|
923
|
+
const observer = ensureViewportPrefetchObserver();
|
|
924
|
+
if (!observer) return;
|
|
925
|
+
|
|
926
|
+
for (const { link } of getEligiblePrefetchLinks(VIEWPORT_PREFETCH_MAX_LINKS)) {
|
|
927
|
+
if (observedPrefetchLinks.has(link)) continue;
|
|
928
|
+
|
|
929
|
+
observedPrefetchLinks.add(link);
|
|
930
|
+
observer.observe(link);
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
function runRoutePrefetchRefresh() {
|
|
935
|
+
routePrefetchRefreshPending = false;
|
|
936
|
+
prefetchEligibleRouteLinks(IDLE_PREFETCH_MAX_LINKS);
|
|
937
|
+
observeViewportPrefetchLinks();
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
function scheduleRoutePrefetchRefresh() {
|
|
941
|
+
if (routePrefetchRefreshPending) return;
|
|
942
|
+
|
|
943
|
+
routePrefetchRefreshPending = true;
|
|
944
|
+
setTimeout(() => {
|
|
945
|
+
if (typeof requestIdleCallback === 'function') {
|
|
946
|
+
requestIdleCallback(runRoutePrefetchRefresh, { timeout: IDLE_PREFETCH_DELAY_MS });
|
|
947
|
+
return;
|
|
948
|
+
}
|
|
949
|
+
|
|
950
|
+
runRoutePrefetchRefresh();
|
|
951
|
+
}, IDLE_PREFETCH_DELAY_MS);
|
|
952
|
+
}
|
|
953
|
+
|
|
845
954
|
// ============================================
|
|
846
955
|
// Router object
|
|
847
956
|
// ============================================
|
|
@@ -946,8 +1055,8 @@ export const getRouterScript = () => `
|
|
|
946
1055
|
const link = e.target.closest('a[href]');
|
|
947
1056
|
if (!link) return;
|
|
948
1057
|
|
|
949
|
-
const href = link
|
|
950
|
-
if (!href
|
|
1058
|
+
const href = getInternalRouteHrefFromLink(link);
|
|
1059
|
+
if (!href) return;
|
|
951
1060
|
|
|
952
1061
|
if (currentHoverLink === link) return;
|
|
953
1062
|
|
|
@@ -978,6 +1087,12 @@ export const getRouterScript = () => `
|
|
|
978
1087
|
true
|
|
979
1088
|
);
|
|
980
1089
|
|
|
1090
|
+
if (document.readyState === 'loading') {
|
|
1091
|
+
document.addEventListener('DOMContentLoaded', scheduleRoutePrefetchRefresh, { once: true });
|
|
1092
|
+
} else {
|
|
1093
|
+
scheduleRoutePrefetchRefresh();
|
|
1094
|
+
}
|
|
1095
|
+
|
|
981
1096
|
// ============================================
|
|
982
1097
|
// Router hooks
|
|
983
1098
|
// ============================================
|
|
@@ -60,7 +60,7 @@ export function useRouter() {
|
|
|
60
60
|
}
|
|
61
61
|
/** Renders an anchor element annotated for Veryfront prefetch handling. */
|
|
62
62
|
export function Link({ prefetch = true, children, ...rest }) {
|
|
63
|
-
return React.createElement("a", { ...rest, "data-prefetch": prefetch ? "true" :
|
|
63
|
+
return React.createElement("a", { ...rest, "data-prefetch": prefetch ? "true" : "false" }, children);
|
|
64
64
|
}
|
|
65
65
|
/** Provides page context to route and MDX descendants. */
|
|
66
66
|
export function PageContextProvider({ children, pageContext, }) {
|