bun-plugin-stx 0.2.139 → 0.2.141
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/chunk-45dqy4z3.js +10506 -0
- package/dist/{chunk-9e56perq.js → chunk-7xv85mm2.js} +49 -32
- package/dist/serve.d.ts +4 -0
- package/dist/serve.js +46 -13
- package/package.json +1 -1
- package/dist/chunk-11kz6apt.js +0 -10129
|
@@ -879,7 +879,7 @@ function getRouterScript() {
|
|
|
879
879
|
// Re-localizing would map it back to the *current* locale and no-op.
|
|
880
880
|
if(!force) url=withCurrentLocale(url);
|
|
881
881
|
log('[router] navigate() called:',url,'isNavigating:',isNavigating);
|
|
882
|
-
if(isNavigating)return;
|
|
882
|
+
if(isNavigating)return Promise.resolve(false);
|
|
883
883
|
// Resolve against the current document URL, matching native <a> semantics.
|
|
884
884
|
// With location.origin as the base, any relative href ('?status=resolved',
|
|
885
885
|
// '#anchor', './sibling') resolved to the SITE ROOT \u2014 so filter tabs,
|
|
@@ -887,13 +887,13 @@ function getRouterScript() {
|
|
|
887
887
|
// the SPA interceptor was active (#1777).
|
|
888
888
|
var t=new URL(url,location.href);
|
|
889
889
|
|
|
890
|
-
if(t.origin!==location.origin){location.href=url;return}
|
|
890
|
+
if(t.origin!==location.origin){location.href=url;return Promise.resolve(false)}
|
|
891
891
|
|
|
892
892
|
if(t.pathname===location.pathname&&t.hash){
|
|
893
893
|
if(pushState!==false)history.pushState({},'',t.href);
|
|
894
894
|
var el=document.querySelector(t.hash);
|
|
895
895
|
if(el)el.scrollIntoView({behavior:'smooth'});
|
|
896
|
-
return;
|
|
896
|
+
return Promise.resolve(true);
|
|
897
897
|
}
|
|
898
898
|
|
|
899
899
|
// Skip if user clicks a link to the page they're already on. We
|
|
@@ -902,7 +902,7 @@ function getRouterScript() {
|
|
|
902
902
|
// entry \u2014 without this allowance, hitting back would early-return
|
|
903
903
|
// and the visible page content would be left frozen on the
|
|
904
904
|
// forward-navigation page.
|
|
905
|
-
if(pushState!==false&&t.href===location.href&&!t.hash&&!force)return;
|
|
905
|
+
if(pushState!==false&&t.href===location.href&&!t.hash&&!force)return Promise.resolve(false);
|
|
906
906
|
|
|
907
907
|
isNavigating=true;
|
|
908
908
|
document.body.classList.add(o.loadingClass);
|
|
@@ -921,22 +921,22 @@ function getRouterScript() {
|
|
|
921
921
|
if(checkLayoutChange(layoutCache[targetPath],url,layoutGroupCache[targetPath])){
|
|
922
922
|
// Layout changed \u2014 fetch full page and do full document swap
|
|
923
923
|
log('[router] cache hit but layout changed \u2014 fetching full page');
|
|
924
|
-
fetch(url,{headers:{'Accept':'text/html'}}).then(function(r){
|
|
924
|
+
return fetch(url,{headers:{'Accept':'text/html'}}).then(function(r){
|
|
925
925
|
if(!r.ok)throw new Error(r.status);
|
|
926
926
|
return r.text();
|
|
927
927
|
}).then(function(html){
|
|
928
928
|
log('[router] full page fetched from cache path, len:',html.length);
|
|
929
|
-
swap(html,targetPath,pushState,targetHash);
|
|
929
|
+
return swap(html,targetPath,pushState,targetHash);
|
|
930
930
|
}).catch(function(err){
|
|
931
931
|
console.error('[router] full page fetch error:',err);
|
|
932
932
|
location.href=url;
|
|
933
933
|
}).finally(done);
|
|
934
|
-
return;
|
|
935
934
|
}
|
|
936
935
|
pendingContainerAttrs=attrsCache[targetPath]||'';
|
|
937
|
-
swap(cache[targetPath],targetPath,pushState,targetHash)
|
|
938
|
-
|
|
939
|
-
|
|
936
|
+
return Promise.resolve(swap(cache[targetPath],targetPath,pushState,targetHash)).then(function(){
|
|
937
|
+
applyTitle(titleCache[targetPath]);
|
|
938
|
+
return true;
|
|
939
|
+
}).finally(done);
|
|
940
940
|
}
|
|
941
941
|
else {
|
|
942
942
|
if(force&&cache[targetPath])evictCache(targetPath);
|
|
@@ -944,7 +944,7 @@ else {
|
|
|
944
944
|
// the page content. Custom app-shell containers need full documents so
|
|
945
945
|
// the router does not inject a <main> fragment into the wrong element.
|
|
946
946
|
var wantsFragment=shouldUseFragmentResponse();
|
|
947
|
-
fetch(url,{headers:wantsFragment?{'X-STX-Router':'true','Accept':'text/html'}:{'Accept':'text/html'}}).then(function(r){
|
|
947
|
+
return fetch(url,{headers:wantsFragment?{'X-STX-Router':'true','Accept':'text/html'}:{'Accept':'text/html'}}).then(function(r){
|
|
948
948
|
if(!r.ok)throw new Error(r.status);
|
|
949
949
|
var isFragment=wantsFragment&&r.headers.get('X-STX-Fragment')==='true';
|
|
950
950
|
var newLayout=r.headers.get('X-STX-Layout')||'';
|
|
@@ -969,10 +969,12 @@ else {
|
|
|
969
969
|
if(result.isFragment)result.html='<!--stx-fragment-->'+result.html;
|
|
970
970
|
if(o.cache)setCache(targetPath,result.html,result.layout,result.layoutGroup,result.title,result.containerAttrs);
|
|
971
971
|
pendingContainerAttrs=result.isFragment?(result.containerAttrs||''):'';
|
|
972
|
-
swap(result.html,targetPath,pushState,targetHash)
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
972
|
+
return Promise.resolve(swap(result.html,targetPath,pushState,targetHash)).then(function(){
|
|
973
|
+
// Fragment swaps carry no <head>; apply the title from the header.
|
|
974
|
+
// Full-document swaps already set document.title from the <title> tag.
|
|
975
|
+
if(result.isFragment)applyTitle(result.title);
|
|
976
|
+
return true;
|
|
977
|
+
});
|
|
976
978
|
}).catch(function(err){
|
|
977
979
|
console.error('[router] fetch error:',err);
|
|
978
980
|
location.href=url;
|
|
@@ -994,10 +996,10 @@ else {
|
|
|
994
996
|
function swap(html,url,pushState,hash){
|
|
995
997
|
var isFragment=html.indexOf('<!--stx-fragment-->')===0;
|
|
996
998
|
if(isFragment)html=html.slice('<!--stx-fragment-->'.length);
|
|
997
|
-
if(!isFragment&&!isStxDocument(html)){log('[router] non-stx document \u2014 full navigation to:',url);location.href=url;return}
|
|
999
|
+
if(!isFragment&&!isStxDocument(html)){log('[router] non-stx document \u2014 full navigation to:',url);location.href=url;return Promise.resolve(false)}
|
|
998
1000
|
var currentContent=getContainer();
|
|
999
1001
|
log('[router] swap: isFragment='+isFragment+' container='+!!currentContent+' tag='+(currentContent&¤tContent.tagName)+' selector='+containerSel+' htmlLen='+html.length);
|
|
1000
|
-
if(!currentContent){log('[router] no container \u2014 falling back');location.href=url;return}
|
|
1002
|
+
if(!currentContent){log('[router] no container \u2014 falling back');location.href=url;return Promise.resolve(false)}
|
|
1001
1003
|
|
|
1002
1004
|
// Fragment mode: server returned just the page content (no document wrapper)
|
|
1003
1005
|
if(isFragment){
|
|
@@ -1155,16 +1157,23 @@ else {
|
|
|
1155
1157
|
// THEN fire stx:load \u2014 now _latestSetup is set and processElement has the right scope
|
|
1156
1158
|
window.dispatchEvent(new Event('stx:load'));
|
|
1157
1159
|
}
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1160
|
+
return new Promise(function(resolve,reject){
|
|
1161
|
+
function completeFragSwap(){
|
|
1162
|
+
try{
|
|
1163
|
+
doFragSwap();
|
|
1164
|
+
resolve(true);
|
|
1165
|
+
}catch(err){reject(err)}
|
|
1166
|
+
}
|
|
1167
|
+
if(runViewTransition(completeFragSwap)){}
|
|
1168
|
+
else{currentContent.style.transition='opacity 0.12s ease-out';currentContent.style.opacity='0';setTimeout(function(){completeFragSwap();currentContent.style.opacity='1';setTimeout(function(){currentContent.style.transition=''},150)},120)}
|
|
1169
|
+
});
|
|
1161
1170
|
}
|
|
1162
1171
|
|
|
1163
1172
|
// Full document mode: parse with DOMParser and extract container content
|
|
1164
1173
|
var parser=new DOMParser();
|
|
1165
1174
|
var doc=parser.parseFromString(html,'text/html');
|
|
1166
1175
|
var newContent=doc.querySelector(containerSel)||doc.querySelector('[data-stx-content]')||doc.querySelector('main');
|
|
1167
|
-
if(!newContent){location.href=url;return}
|
|
1176
|
+
if(!newContent){location.href=url;return Promise.resolve(false)}
|
|
1168
1177
|
|
|
1169
1178
|
// Clean up existing signals/effects
|
|
1170
1179
|
if(window.stx&&window.stx._cleanupContainer){
|
|
@@ -1456,18 +1465,26 @@ else {
|
|
|
1456
1465
|
}
|
|
1457
1466
|
}
|
|
1458
1467
|
|
|
1459
|
-
|
|
1460
|
-
|
|
1468
|
+
return new Promise(function(resolve,reject){
|
|
1469
|
+
function completeSwap(){
|
|
1470
|
+
try{
|
|
1471
|
+
doSwap();
|
|
1472
|
+
resolve(true);
|
|
1473
|
+
}catch(err){reject(err)}
|
|
1474
|
+
}
|
|
1475
|
+
if(runViewTransition(completeSwap)){
|
|
1476
|
+
}
|
|
1461
1477
|
else {
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1478
|
+
// Fallback fade for browsers without View Transitions API
|
|
1479
|
+
currentContent.style.transition='opacity 0.12s ease-out';
|
|
1480
|
+
currentContent.style.opacity='0';
|
|
1481
|
+
setTimeout(function(){
|
|
1482
|
+
completeSwap();
|
|
1483
|
+
currentContent.style.opacity='1';
|
|
1484
|
+
setTimeout(function(){currentContent.style.transition=''},150);
|
|
1485
|
+
},120);
|
|
1486
|
+
}
|
|
1487
|
+
});
|
|
1471
1488
|
}
|
|
1472
1489
|
|
|
1473
1490
|
// \u2500\u2500 Link interception \u2500\u2500
|
package/dist/serve.d.ts
CHANGED
|
@@ -114,6 +114,10 @@ export declare interface ServeOptions {
|
|
|
114
114
|
componentsDir?: string
|
|
115
115
|
layoutsDir?: string
|
|
116
116
|
partialsDir?: string
|
|
117
|
+
watchDirs?: string[]
|
|
118
|
+
renderCache?: boolean
|
|
119
|
+
renderCacheVary?: 'request' | 'source'
|
|
120
|
+
prewarmRenderCache?: boolean | number
|
|
117
121
|
publicDir?: string
|
|
118
122
|
quiet?: boolean
|
|
119
123
|
autoIncrementPort?: boolean | number
|
package/dist/serve.js
CHANGED
|
@@ -8995,7 +8995,8 @@ After installing: bun add bun-plugin-stx`);
|
|
|
8995
8995
|
let discoveredPagePaths = null;
|
|
8996
8996
|
let assetsInitialized = false;
|
|
8997
8997
|
const htmlCache = new Map;
|
|
8998
|
-
const ENABLE_HTML_CACHE =
|
|
8998
|
+
const ENABLE_HTML_CACHE = options.renderCache === true;
|
|
8999
|
+
const RENDER_CACHE_VARY = options.renderCacheVary ?? "request";
|
|
8999
9000
|
const crosswindCssCache = new Map;
|
|
9000
9001
|
const hmrClients = new Set;
|
|
9001
9002
|
const hmrEncoder = new TextEncoder;
|
|
@@ -9031,12 +9032,15 @@ After installing: bun add bun-plugin-stx`);
|
|
|
9031
9032
|
return;
|
|
9032
9033
|
const f = String(filename);
|
|
9033
9034
|
const isStxLike = f.endsWith(".stx") || f.endsWith(".md") || f.endsWith(".html");
|
|
9035
|
+
const isCode = f.endsWith(".js") || f.endsWith(".ts") || f.endsWith(".tsx") || f.endsWith(".mts") || f.endsWith(".cts");
|
|
9036
|
+
const isData = f.endsWith(".json");
|
|
9034
9037
|
const isCss = f.endsWith(".css");
|
|
9035
|
-
const isAsset = isCss ||
|
|
9036
|
-
if (!isStxLike && !isAsset)
|
|
9038
|
+
const isAsset = isCss || isCode || f.endsWith(".jpg") || f.endsWith(".jpeg") || f.endsWith(".png") || f.endsWith(".gif") || f.endsWith(".svg") || f.endsWith(".webp") || f.endsWith(".avif") || f.endsWith(".woff") || f.endsWith(".woff2") || f.endsWith(".ttf") || f.endsWith(".otf");
|
|
9039
|
+
if (!isStxLike && !isAsset && !isData)
|
|
9037
9040
|
return;
|
|
9038
|
-
if (isStxLike) {
|
|
9039
|
-
|
|
9041
|
+
if (isStxLike || isCode || isData) {
|
|
9042
|
+
if (isStxLike)
|
|
9043
|
+
sourceFiles = null;
|
|
9040
9044
|
routes.clear();
|
|
9041
9045
|
htmlCache.clear();
|
|
9042
9046
|
crosswindCssCache.clear();
|
|
@@ -9053,7 +9057,8 @@ After installing: bun add bun-plugin-stx`);
|
|
|
9053
9057
|
layoutsDir,
|
|
9054
9058
|
partialsDir,
|
|
9055
9059
|
publicDir,
|
|
9056
|
-
"resources/assets"
|
|
9060
|
+
"resources/assets",
|
|
9061
|
+
...options.watchDirs ?? []
|
|
9057
9062
|
]) {
|
|
9058
9063
|
if (!dir)
|
|
9059
9064
|
continue;
|
|
@@ -9209,14 +9214,24 @@ After installing: bun add bun-plugin-stx`);
|
|
|
9209
9214
|
context.__stxServeContext = full;
|
|
9210
9215
|
globalThis.__stxServeContext = full;
|
|
9211
9216
|
}
|
|
9212
|
-
function htmlCacheKey(filePath) {
|
|
9217
|
+
function htmlCacheKey(filePath, reqCtx) {
|
|
9218
|
+
if (RENDER_CACHE_VARY === "source")
|
|
9219
|
+
return filePath;
|
|
9220
|
+
if (reqCtx) {
|
|
9221
|
+
try {
|
|
9222
|
+
return `${filePath}\x00${JSON.stringify(reqCtx)}`;
|
|
9223
|
+
} catch {
|
|
9224
|
+
return `${filePath}\x00uncacheable:${crypto.randomUUID()}`;
|
|
9225
|
+
}
|
|
9226
|
+
}
|
|
9213
9227
|
const loc = i18nConfig ? activeServeLocale ?? i18nConfig.defaultLocale : "";
|
|
9214
9228
|
const search = activeServeSearch || "";
|
|
9215
9229
|
const host = activeServeHost || "";
|
|
9216
9230
|
const cookies = activeServeCookieHeader;
|
|
9217
|
-
|
|
9231
|
+
const ip = activeServeIp;
|
|
9232
|
+
if (!loc && !search && !host && !cookies && !ip)
|
|
9218
9233
|
return filePath;
|
|
9219
|
-
return `${filePath}\x00${loc}\x00${search}\x00${host}\x00${cookies}`;
|
|
9234
|
+
return `${filePath}\x00${loc}\x00${search}\x00${host}\x00${cookies}\x00${ip}`;
|
|
9220
9235
|
}
|
|
9221
9236
|
const builtInMiddleware = authConfig === null ? {} : {
|
|
9222
9237
|
auth: (_req, ctx) => {
|
|
@@ -9325,7 +9340,7 @@ After installing: bun add bun-plugin-stx`);
|
|
|
9325
9340
|
pageMiddlewarePatterns.length = 0;
|
|
9326
9341
|
await Promise.all(files.map((f) => detectPageMiddleware(f)));
|
|
9327
9342
|
try {
|
|
9328
|
-
const { Router } = await import("./chunk-
|
|
9343
|
+
const { Router } = await import("./chunk-7xv85mm2.js");
|
|
9329
9344
|
const pagesDirs = patterns.map((p) => p.replace(/\/$/, "")).filter(Boolean);
|
|
9330
9345
|
const router = new Router(process19.cwd(), { pagesDirs, stateDir: stateDirName() });
|
|
9331
9346
|
if (!options.quiet)
|
|
@@ -9392,7 +9407,7 @@ After installing: bun add bun-plugin-stx`);
|
|
|
9392
9407
|
dir = nodePath.dirname(dir);
|
|
9393
9408
|
}
|
|
9394
9409
|
try {
|
|
9395
|
-
const mod = await import("./chunk-
|
|
9410
|
+
const mod = await import("./chunk-45dqy4z3.js");
|
|
9396
9411
|
crosswindModule = { CSSGenerator: mod.CSSGenerator, config: mod.config };
|
|
9397
9412
|
return crosswindModule;
|
|
9398
9413
|
} catch {
|
|
@@ -9517,7 +9532,7 @@ After installing: bun add bun-plugin-stx`);
|
|
|
9517
9532
|
reqCtx.responseStatus = extractPageResponseStatus(content) ?? 200;
|
|
9518
9533
|
const skipCacheHint = /(?:^|[^\w$])__stx_skip_cache\s*=\s*true/.test(content);
|
|
9519
9534
|
if (ENABLE_HTML_CACHE && !skipCacheHint) {
|
|
9520
|
-
const cacheKey = htmlCacheKey(filePath);
|
|
9535
|
+
const cacheKey = htmlCacheKey(filePath, reqCtx);
|
|
9521
9536
|
const cachedEntry = htmlCache.get(cacheKey);
|
|
9522
9537
|
if (cachedEntry && await templateSignatureFresh(cachedEntry.signature))
|
|
9523
9538
|
return cachedEntry.html;
|
|
@@ -9584,7 +9599,7 @@ After installing: bun add bun-plugin-stx`);
|
|
|
9584
9599
|
}
|
|
9585
9600
|
if (ENABLE_HTML_CACHE && !context.__stx_skip_cache && !skipCacheHint) {
|
|
9586
9601
|
const signature = await buildTemplateSignature(filePath, dependencies);
|
|
9587
|
-
htmlCache.set(htmlCacheKey(filePath), { html: output, signature });
|
|
9602
|
+
htmlCache.set(htmlCacheKey(filePath, reqCtx), { html: output, signature });
|
|
9588
9603
|
}
|
|
9589
9604
|
return output;
|
|
9590
9605
|
}
|
|
@@ -10472,6 +10487,24 @@ ${trailingPageScripts.join(`
|
|
|
10472
10487
|
if (actualPort !== port && !options.quiet) {
|
|
10473
10488
|
console.warn(`\x1B[33m[stx]\x1B[0m port ${port} in use \u2014 using \x1B[1m${actualPort}\x1B[0m instead`);
|
|
10474
10489
|
}
|
|
10490
|
+
if (ENABLE_HTML_CACHE && options.prewarmRenderCache) {
|
|
10491
|
+
const requestedConcurrency = typeof options.prewarmRenderCache === "number" ? Math.floor(options.prewarmRenderCache) : 4;
|
|
10492
|
+
const concurrency = Math.max(1, requestedConcurrency);
|
|
10493
|
+
(async () => {
|
|
10494
|
+
const files = await discoverFiles();
|
|
10495
|
+
const pending = [...new Set(files.map(stxViewFileToRoutePath).filter((routePath) => routePath !== null))];
|
|
10496
|
+
let nextIndex = 0;
|
|
10497
|
+
await Promise.all(Array.from({ length: Math.min(concurrency, pending.length) }, async () => {
|
|
10498
|
+
while (nextIndex < pending.length) {
|
|
10499
|
+
const routePath = pending[nextIndex++];
|
|
10500
|
+
try {
|
|
10501
|
+
const response = await fetch(`http://127.0.0.1:${actualPort}${routePath}`);
|
|
10502
|
+
await response.arrayBuffer();
|
|
10503
|
+
} catch {}
|
|
10504
|
+
}
|
|
10505
|
+
}));
|
|
10506
|
+
})().catch(() => {});
|
|
10507
|
+
}
|
|
10475
10508
|
if (options.reusePort) {
|
|
10476
10509
|
const graceMs = Number(process19.env.SHUTDOWN_GRACE_MS) || 15000;
|
|
10477
10510
|
process19.once("SIGTERM", () => {
|
package/package.json
CHANGED