@rsc-kit/core 0.21.2 → 0.21.4
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/js/navigate.js +16 -3
- package/dist/js/navigate.js.map +1 -1
- package/dist/vite.d.ts +18 -2
- package/dist/vite.js +68 -38
- package/dist/vite.js.map +1 -1
- package/package.json +1 -1
package/dist/vite.js
CHANGED
|
@@ -862,12 +862,11 @@ self.addEventListener('install', (event) => {
|
|
|
862
862
|
// worker cannot see. Added here so it is in the cache before it is
|
|
863
863
|
// needed, which is the only moment it cannot be fetched.
|
|
864
864
|
//
|
|
865
|
-
//
|
|
866
|
-
// for one failure - and a worker whose install rejects is never
|
|
865
|
+
// Each file on its own rather than cache.addAll, which rejects the whole
|
|
866
|
+
// list for one failure - and a worker whose install rejects is never
|
|
867
867
|
// installed. The worker before it then stays in charge, serving its own
|
|
868
868
|
// build's pages, for every visit until one install happens to succeed:
|
|
869
|
-
// a network blip, a quota, a file a deploy replaced mid-install
|
|
870
|
-
// phone kept a worker from builds ago whose bugs had long been fixed.
|
|
869
|
+
// a network blip, a quota, a file a deploy replaced mid-install.
|
|
871
870
|
// A file that did not arrive costs a cache entry; the update still
|
|
872
871
|
// lands. The browser checks /sw.js for itself, without the page's
|
|
873
872
|
// javascript, so an install that cannot fail is also what rescues a
|
|
@@ -1032,6 +1031,10 @@ const standIn = async (request) => {
|
|
|
1032
1031
|
// the ?__rsc=<segments> above is the one header the answer differs on.
|
|
1033
1032
|
const MATCH = { ignoreVary: true }
|
|
1034
1033
|
|
|
1034
|
+
// The documents being fetched to go with a payload, by url - so the payloads
|
|
1035
|
+
// of one page, asked for at several depths, fetch its document once.
|
|
1036
|
+
const documentsInFlight = new Set()
|
|
1037
|
+
|
|
1035
1038
|
self.addEventListener('fetch', (event) => {
|
|
1036
1039
|
const request = event.request
|
|
1037
1040
|
const url = new URL(request.url)
|
|
@@ -1109,26 +1112,14 @@ self.addEventListener('fetch', (event) => {
|
|
|
1109
1112
|
const copy = response.clone()
|
|
1110
1113
|
caches.open(CACHE).then((cache) => cache.put(keyFor(request), copy))
|
|
1111
1114
|
|
|
1112
|
-
//
|
|
1113
|
-
//
|
|
1114
|
-
//
|
|
1115
|
-
//
|
|
1116
|
-
//
|
|
1117
|
-
//
|
|
1118
|
-
//
|
|
1119
|
-
//
|
|
1120
|
-
// varies on those, and the Cache API matches on the same.
|
|
1121
|
-
if (request.mode === 'navigate') {
|
|
1122
|
-
const warm = new Request(request.url, { headers: { 'X-RSC': '1' } })
|
|
1123
|
-
|
|
1124
|
-
fetch(warm)
|
|
1125
|
-
.then((payload) => {
|
|
1126
|
-
if (mayStore(payload)) {
|
|
1127
|
-
caches.open(CACHE).then((cache) => cache.put(keyFor(warm), payload))
|
|
1128
|
-
}
|
|
1129
|
-
})
|
|
1130
|
-
.catch(() => {})
|
|
1131
|
-
}
|
|
1115
|
+
// No second fetch of the page's payload here. There used to be one,
|
|
1116
|
+
// for offline: a document alone does not boot. But whenever this
|
|
1117
|
+
// worker handles a page load, the page's own boot request - the
|
|
1118
|
+
// same url, X-RSC: 1, no segments - comes through this worker too
|
|
1119
|
+
// and is cached just above. The one time it does not is a first
|
|
1120
|
+
// visit, before the worker controls the page, and then it did not
|
|
1121
|
+
// handle the page load either. So it was a duplicate request on
|
|
1122
|
+
// every page load, at the moment the visitor was waiting.
|
|
1132
1123
|
|
|
1133
1124
|
// And the other way round. Moving between pages fetches payloads and
|
|
1134
1125
|
// never documents, so a page reached only by a link had nothing to
|
|
@@ -1138,16 +1129,20 @@ self.addEventListener('fetch', (event) => {
|
|
|
1138
1129
|
// Once per url: the document is fetched only when the cache has none,
|
|
1139
1130
|
// so this costs one extra request the first time a page is visited
|
|
1140
1131
|
// rather than one on every navigation to it.
|
|
1141
|
-
if (request.headers.get('X-RSC')) {
|
|
1132
|
+
if (request.headers.get('X-RSC') && !documentsInFlight.has(request.url)) {
|
|
1142
1133
|
const document = new Request(request.url)
|
|
1143
1134
|
|
|
1144
|
-
|
|
1145
|
-
|
|
1135
|
+
documentsInFlight.add(request.url)
|
|
1136
|
+
caches
|
|
1137
|
+
.open(CACHE)
|
|
1138
|
+
.then(async (cache) => {
|
|
1139
|
+
if (await cache.match(document)) return
|
|
1146
1140
|
|
|
1147
|
-
|
|
1141
|
+
const fresh = await fetch(document).catch(() => null)
|
|
1148
1142
|
|
|
1149
|
-
|
|
1150
|
-
|
|
1143
|
+
if (fresh && mayStore(fresh)) await cache.put(document, fresh)
|
|
1144
|
+
})
|
|
1145
|
+
.finally(() => documentsInFlight.delete(request.url))
|
|
1151
1146
|
}
|
|
1152
1147
|
}
|
|
1153
1148
|
|
|
@@ -1359,7 +1354,45 @@ export function bootsTheApp(file) {
|
|
|
1359
1354
|
return true;
|
|
1360
1355
|
return false;
|
|
1361
1356
|
}
|
|
1362
|
-
|
|
1357
|
+
/**
|
|
1358
|
+
* A service worker's version: a hash of everything it serves cache-first.
|
|
1359
|
+
*
|
|
1360
|
+
* It used to be the precache list alone - the hashed file names - on the
|
|
1361
|
+
* reasoning that a deploy changes them. A deploy that changes a stored page
|
|
1362
|
+
* and no client script does not: the list was the same, so sw.js was byte
|
|
1363
|
+
* for byte the same, the browser saw no update, and the worker went on
|
|
1364
|
+
* serving the previous build's page from its cache, cache-first, because "a
|
|
1365
|
+
* deploy changes VERSION and sweeps this cache". Reproduced: deploy build B
|
|
1366
|
+
* over A, reload, and the page is A; only the load after the background
|
|
1367
|
+
* refresh shows B. So the stored pages' bytes are in it too, and a deploy
|
|
1368
|
+
* that changes what the worker holds is a new worker.
|
|
1369
|
+
*/
|
|
1370
|
+
export function workerVersion(precache, storedDir) {
|
|
1371
|
+
const version = createHash("sha256");
|
|
1372
|
+
version.update(precache.join("\n"));
|
|
1373
|
+
if (storedDir && existsSync(storedDir)) {
|
|
1374
|
+
const stored = [];
|
|
1375
|
+
const walkStored = (dir) => {
|
|
1376
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
1377
|
+
const path = join(dir, entry.name);
|
|
1378
|
+
if (entry.isDirectory())
|
|
1379
|
+
walkStored(path);
|
|
1380
|
+
else
|
|
1381
|
+
stored.push(path);
|
|
1382
|
+
}
|
|
1383
|
+
};
|
|
1384
|
+
walkStored(storedDir);
|
|
1385
|
+
for (const path of stored.sort()) {
|
|
1386
|
+
version.update("\n" + relative(storedDir, path) + "\n");
|
|
1387
|
+
version.update(readFileSync(path));
|
|
1388
|
+
}
|
|
1389
|
+
}
|
|
1390
|
+
return version.digest("hex").slice(0, 12);
|
|
1391
|
+
}
|
|
1392
|
+
function writeServiceWorker(clientDir, frozen = [], offlineUrl = null,
|
|
1393
|
+
// The pages the build stored, which the worker serves cache-first. Their
|
|
1394
|
+
// bytes are part of what a version is - see below.
|
|
1395
|
+
storedDir = null) {
|
|
1363
1396
|
if (!existsSync(clientDir))
|
|
1364
1397
|
return;
|
|
1365
1398
|
// Before the walk, so it lands in the precache with everything else. The
|
|
@@ -1383,12 +1416,9 @@ function writeServiceWorker(clientDir, frozen = [], offlineUrl = null) {
|
|
|
1383
1416
|
};
|
|
1384
1417
|
walk(clientDir, "");
|
|
1385
1418
|
const precache = ["/", ...files.map((file) => `/${file}`)].sort();
|
|
1386
|
-
const
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
.slice(0, 12);
|
|
1390
|
-
writeFileSync(join(clientDir, "sw.js"), SERVICE_WORKER(version, precache, frozen, offlineUrl, extra));
|
|
1391
|
-
log(`offline: ${precache.length} files precached as rsc-kit-${version}` +
|
|
1419
|
+
const versionHash = workerVersion(precache, storedDir);
|
|
1420
|
+
writeFileSync(join(clientDir, "sw.js"), SERVICE_WORKER(versionHash, precache, frozen, offlineUrl, extra));
|
|
1421
|
+
log(`offline: ${precache.length} files precached as rsc-kit-${versionHash}` +
|
|
1392
1422
|
(offlineUrl ? `, falling back to ${offlineUrl}` : "") +
|
|
1393
1423
|
(extra ? ", with app/sw.js" : ""));
|
|
1394
1424
|
}
|
|
@@ -6526,7 +6556,7 @@ export function rscKit(options = {}) {
|
|
|
6526
6556
|
if (webManifestOptions)
|
|
6527
6557
|
writeWebManifest(clientOut ?? publicAssetsDir, webManifestOptions);
|
|
6528
6558
|
if (offline) {
|
|
6529
|
-
writeServiceWorker(clientOut ?? publicAssetsDir, frozen, offlineFallback(frozen, results));
|
|
6559
|
+
writeServiceWorker(clientOut ?? publicAssetsDir, frozen, offlineFallback(frozen, results), staticDir);
|
|
6530
6560
|
}
|
|
6531
6561
|
},
|
|
6532
6562
|
configResolved(config) {
|