stx-router 0.2.708 → 0.2.710
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/README.md +5 -0
- package/dist/client.js +39 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -161,6 +161,11 @@ const script = getRouterScript()
|
|
|
161
161
|
// - Loading indicator
|
|
162
162
|
```
|
|
163
163
|
|
|
164
|
+
Background page prefetches and revalidations run at most two at a time. Hover or
|
|
165
|
+
touch intent moves a queued page ahead of links merely visible on screen. A
|
|
166
|
+
navigation starts its queued destination immediately and shares that request,
|
|
167
|
+
so it never waits for the speculative queue or fetches the page twice.
|
|
168
|
+
|
|
164
169
|
### Route Type Generation
|
|
165
170
|
|
|
166
171
|
```typescript
|
package/dist/client.js
CHANGED
|
@@ -51,7 +51,7 @@ function routerSource() {
|
|
|
51
51
|
return `
|
|
52
52
|
;(function(){
|
|
53
53
|
'use strict';
|
|
54
|
-
var ROUTER_REV=
|
|
54
|
+
var ROUTER_REV=8;
|
|
55
55
|
if(window.__stxRouter&&window.__stxRouter.__rev===ROUTER_REV)return;
|
|
56
56
|
|
|
57
57
|
// \u2500\u2500 Configuration \u2500\u2500
|
|
@@ -516,6 +516,37 @@ function routerSource() {
|
|
|
516
516
|
// checking behind the swap (revalidate).
|
|
517
517
|
var cacheAt={};
|
|
518
518
|
var prefetching={};
|
|
519
|
+
// Speculative HTML still renders on the server. A viewport with twelve
|
|
520
|
+
// links must not start twelve renders alongside the page being read.
|
|
521
|
+
// Intent moves a queued page to the front; navigation starts it at once,
|
|
522
|
+
// sharing the same promise instead of waiting behind background work.
|
|
523
|
+
var prefetchQueue=[],prefetchActive=0;
|
|
524
|
+
function runPrefetch(job){
|
|
525
|
+
prefetchActive++;
|
|
526
|
+
var started;
|
|
527
|
+
try{started=job.start()}catch(error){started=Promise.reject(error)}
|
|
528
|
+
Promise.resolve(started).then(job.resolve,job.reject).finally(function(){
|
|
529
|
+
prefetchActive--;
|
|
530
|
+
while(prefetchActive<2&&prefetchQueue.length)runPrefetch(prefetchQueue.shift());
|
|
531
|
+
});
|
|
532
|
+
}
|
|
533
|
+
function queuePrefetch(key,start,intent){
|
|
534
|
+
return new Promise(function(resolve,reject){
|
|
535
|
+
var job={key:key,start:start,resolve:resolve,reject:reject};
|
|
536
|
+
if(prefetchActive<2)runPrefetch(job);
|
|
537
|
+
else if(intent)prefetchQueue.unshift(job);
|
|
538
|
+
else prefetchQueue.push(job);
|
|
539
|
+
});
|
|
540
|
+
}
|
|
541
|
+
function promotePrefetch(key,navigation){
|
|
542
|
+
for(var i=0;i<prefetchQueue.length;i++){
|
|
543
|
+
if(prefetchQueue[i].key!==key)continue;
|
|
544
|
+
var job=prefetchQueue.splice(i,1)[0];
|
|
545
|
+
if(navigation)runPrefetch(job);
|
|
546
|
+
else prefetchQueue.unshift(job);
|
|
547
|
+
break;
|
|
548
|
+
}
|
|
549
|
+
}
|
|
519
550
|
var awaitingKey='';
|
|
520
551
|
var isNavigating=false;
|
|
521
552
|
|
|
@@ -1303,6 +1334,7 @@ function routerSource() {
|
|
|
1303
1334
|
var awaitedKey=cacheKey(url);
|
|
1304
1335
|
if(o.cache&&!force&&!cache[awaitedKey]&&prefetching[awaitedKey]&&prefetching[awaitedKey].then){
|
|
1305
1336
|
awaitingKey=awaitedKey;
|
|
1337
|
+
promotePrefetch(awaitedKey,true);
|
|
1306
1338
|
// Answer the tap now, not when the prefetch lands. The page it asked
|
|
1307
1339
|
// for is on the way, but until then nothing on screen said so: no
|
|
1308
1340
|
// loading class, no progress bar. On a server a second or two away
|
|
@@ -3186,7 +3218,7 @@ else {
|
|
|
3186
3218
|
if(Date.now()-(cacheAt[key]||0)<o.revalidateAfter)return;
|
|
3187
3219
|
// Compare like with like, including documents prefetched across layouts.
|
|
3188
3220
|
var before=cache[key],wantsFragment=before?isFragment(before):shouldUseFragmentResponse();
|
|
3189
|
-
prefetching[key]=fetch(url,{headers:wantsFragment?{'X-STX-Router':'true','Accept':'text/html'}:{'Accept':'text/html'}}).then(function(r){
|
|
3221
|
+
prefetching[key]=queuePrefetch(key,function(){return fetch(url,{priority:'low',headers:wantsFragment?{'X-STX-Router':'true','Accept':'text/html'}:{'Accept':'text/html'}}).then(function(r){
|
|
3190
3222
|
var incoming=r.headers.get('X-STX-Build')||'';
|
|
3191
3223
|
if(isBuildSkew(incoming)){reloadForSkew(url,incoming,true);return null}
|
|
3192
3224
|
return readPrefetchResponse(r,wantsFragment);
|
|
@@ -3194,7 +3226,7 @@ else {
|
|
|
3194
3226
|
if(!result)return;
|
|
3195
3227
|
if(o.cache)setCache(key,result.html,result.layout,result.layoutGroup,result.title,result.containerAttrs);
|
|
3196
3228
|
if(before!==undefined&&before!==result.html&&cacheKey(location.href)===key)emitUpdated(url,'page');
|
|
3197
|
-
}).catch(function(){}).finally(function(){delete prefetching[key]});
|
|
3229
|
+
}).catch(function(){}).finally(function(){delete prefetching[key]})});
|
|
3198
3230
|
}
|
|
3199
3231
|
// The offline worker answered from its cache and found something newer
|
|
3200
3232
|
// behind it. It posts { type: 'stx:updated', url, kind }, which its own
|
|
@@ -3571,12 +3603,12 @@ else {
|
|
|
3571
3603
|
var key=cacheKey(href);
|
|
3572
3604
|
if(cache[key]&&!fresh){if(!glance)loadModuleRegistries(cache[key],href);return}
|
|
3573
3605
|
if(prefetching[key]){
|
|
3574
|
-
if(!glance)prefetching[key].then(function(){if(cache[key])loadModuleRegistries(cache[key],href)})
|
|
3606
|
+
if(!glance){promotePrefetch(key,false);prefetching[key].then(function(){if(cache[key])loadModuleRegistries(cache[key],href)})}
|
|
3575
3607
|
return;
|
|
3576
3608
|
}
|
|
3577
3609
|
var eager=link.getAttribute('data-stx-prefetch')==='eager';
|
|
3578
3610
|
var wantsFragment=shouldUseFragmentResponse();
|
|
3579
|
-
prefetching[key]=fetch(href,{headers:wantsFragment?{'X-STX-Router':'true','Accept':'text/html'}:{'Accept':'text/html'}}).then(function(r){
|
|
3611
|
+
prefetching[key]=queuePrefetch(key,function(){return fetch(href,{priority:'low',headers:wantsFragment?{'X-STX-Router':'true','Accept':'text/html'}:{'Accept':'text/html'}}).then(function(r){
|
|
3580
3612
|
return readPrefetchResponse(r,wantsFragment);
|
|
3581
3613
|
}).then(function(result){
|
|
3582
3614
|
// A page in another layout cannot be swapped in as a fragment: the tap
|
|
@@ -3585,7 +3617,7 @@ else {
|
|
|
3585
3617
|
// still reaching for the link, so the tap is a swap like any other.
|
|
3586
3618
|
if(!result||!isFragment(result.html)||!checkLayoutChange(result.layout,href,result.layoutGroup))return result;
|
|
3587
3619
|
// Same guards as any prefetch; the layout is the one the fragment declared.
|
|
3588
|
-
return fetch(href,{headers:{'Accept':'text/html'}}).then(function(full){
|
|
3620
|
+
return fetch(href,{priority:'low',headers:{'Accept':'text/html'}}).then(function(full){
|
|
3589
3621
|
return full.ok?readPrefetchResponse(full,false).then(function(doc){return doc&&(doc.layout=result.layout,doc.layoutGroup=result.layoutGroup,doc)}):null;
|
|
3590
3622
|
});
|
|
3591
3623
|
}).then(function(result){
|
|
@@ -3601,7 +3633,7 @@ else {
|
|
|
3601
3633
|
// A whole document's generated sheets too, named the same way in its head.
|
|
3602
3634
|
preloadGeneratedCss(fragmentCssHrefs(result.html),location.href);
|
|
3603
3635
|
}
|
|
3604
|
-
}).catch(function(){}).finally(function(){delete prefetching[key]});
|
|
3636
|
+
}).catch(function(){}).finally(function(){delete prefetching[key]})},!glance);
|
|
3605
3637
|
}
|
|
3606
3638
|
|
|
3607
3639
|
// \u2500\u2500 Pages kept between launches \u2500\u2500
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "stx-router",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.2.
|
|
4
|
+
"version": "0.2.710",
|
|
5
5
|
"description": "File-based router for STX — .stx template discovery, nested layouts, typed route params, middleware, and client-side SPA navigation.",
|
|
6
6
|
"author": "Chris Breuer <chris@stacksjs.org>",
|
|
7
7
|
"license": "MIT",
|