@pylonsync/react 0.4.9 → 0.4.11
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/Link.d.ts +4 -1
- package/package.json +3 -3
- package/src/Link.tsx +29 -17
package/dist/Link.d.ts
CHANGED
|
@@ -2,7 +2,10 @@ import React from "react";
|
|
|
2
2
|
declare global {
|
|
3
3
|
interface Window {
|
|
4
4
|
__pylon?: {
|
|
5
|
-
prefetch: (href: string
|
|
5
|
+
prefetch: (href: string, opts?: {
|
|
6
|
+
/** Also fetch the page payload (costs a server render — hover only). */
|
|
7
|
+
document?: boolean;
|
|
8
|
+
}) => Promise<void>;
|
|
6
9
|
navigate: (href: string, opts?: {
|
|
7
10
|
push?: boolean;
|
|
8
11
|
replace?: boolean;
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"publishConfig": {
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
|
-
"version": "0.4.
|
|
6
|
+
"version": "0.4.11",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"main": "./src/index.ts",
|
|
9
9
|
"types": "./dist/index.d.ts",
|
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
"prepack": "bun run build"
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"@pylonsync/sdk": "0.4.
|
|
18
|
-
"@pylonsync/sync": "0.4.
|
|
17
|
+
"@pylonsync/sdk": "0.4.11",
|
|
18
|
+
"@pylonsync/sync": "0.4.11"
|
|
19
19
|
},
|
|
20
20
|
"peerDependencies": {
|
|
21
21
|
"react": ">=19.0.0"
|
package/src/Link.tsx
CHANGED
|
@@ -8,12 +8,12 @@
|
|
|
8
8
|
// route entry, and re-renders the React root in place. Layouts
|
|
9
9
|
// that match across the two routes survive reconciliation, so
|
|
10
10
|
// their state persists.
|
|
11
|
-
// - Prefetches
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
//
|
|
16
|
-
//
|
|
11
|
+
// - Prefetches in two stages, because the two halves cost very
|
|
12
|
+
// different things. On viewport entry (IntersectionObserver) the
|
|
13
|
+
// runtime modulepreloads the destination's client chunks — static,
|
|
14
|
+
// immutable, cacheable. On hover/touch it also fetches the page
|
|
15
|
+
// itself, which costs a server render, so that waits for a real
|
|
16
|
+
// signal of intent rather than firing for a screenful of links.
|
|
17
17
|
// - Modifier keys (cmd/ctrl/shift/alt) or middle-click fall
|
|
18
18
|
// through to the browser's default behavior (open in new tab,
|
|
19
19
|
// etc.) — matches Next.js semantics.
|
|
@@ -29,7 +29,13 @@ import React, { useEffect, useRef } from "react";
|
|
|
29
29
|
declare global {
|
|
30
30
|
interface Window {
|
|
31
31
|
__pylon?: {
|
|
32
|
-
prefetch: (
|
|
32
|
+
prefetch: (
|
|
33
|
+
href: string,
|
|
34
|
+
opts?: {
|
|
35
|
+
/** Also fetch the page payload (costs a server render — hover only). */
|
|
36
|
+
document?: boolean;
|
|
37
|
+
},
|
|
38
|
+
) => Promise<void>;
|
|
33
39
|
navigate: (
|
|
34
40
|
href: string,
|
|
35
41
|
opts?: { push?: boolean; replace?: boolean; seed?: unknown },
|
|
@@ -115,12 +121,19 @@ export function Link({
|
|
|
115
121
|
}
|
|
116
122
|
|
|
117
123
|
const el = ref.current;
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
124
|
+
// Chunks warm once, on sight. The page payload warms on intent — and may
|
|
125
|
+
// re-warm on a later hover, since the runtime expires payloads that have
|
|
126
|
+
// gone stale.
|
|
127
|
+
let warmedChunks = false;
|
|
128
|
+
const warmChunks = () => {
|
|
129
|
+
if (warmedChunks) return;
|
|
130
|
+
warmedChunks = true;
|
|
122
131
|
window.__pylon?.prefetch(href);
|
|
123
132
|
};
|
|
133
|
+
const warmPage = () => {
|
|
134
|
+
warmedChunks = true;
|
|
135
|
+
window.__pylon?.prefetch(href, { document: true });
|
|
136
|
+
};
|
|
124
137
|
|
|
125
138
|
let io: IntersectionObserver | null = null;
|
|
126
139
|
if (typeof IntersectionObserver !== "undefined") {
|
|
@@ -128,7 +141,7 @@ export function Link({
|
|
|
128
141
|
(entries) => {
|
|
129
142
|
for (const e of entries) {
|
|
130
143
|
if (e.isIntersecting) {
|
|
131
|
-
|
|
144
|
+
warmChunks();
|
|
132
145
|
io?.disconnect();
|
|
133
146
|
}
|
|
134
147
|
}
|
|
@@ -138,14 +151,13 @@ export function Link({
|
|
|
138
151
|
io.observe(el);
|
|
139
152
|
}
|
|
140
153
|
|
|
141
|
-
|
|
142
|
-
el.addEventListener("
|
|
143
|
-
el.addEventListener("touchstart", onHover, { once: true, passive: true });
|
|
154
|
+
el.addEventListener("mouseenter", warmPage);
|
|
155
|
+
el.addEventListener("touchstart", warmPage, { passive: true });
|
|
144
156
|
|
|
145
157
|
return () => {
|
|
146
158
|
io?.disconnect();
|
|
147
|
-
el.removeEventListener("mouseenter",
|
|
148
|
-
el.removeEventListener("touchstart",
|
|
159
|
+
el.removeEventListener("mouseenter", warmPage);
|
|
160
|
+
el.removeEventListener("touchstart", warmPage);
|
|
149
161
|
};
|
|
150
162
|
}, [href, prefetch]);
|
|
151
163
|
|