@lomray/vite-ssr-boost 8.4.0-beta.2 → 8.4.0-beta.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/README.md +2 -0
- package/adapters/express/render.d.ts +1 -0
- package/adapters/express/render.js +1 -1
- package/adapters/express/render.js.map +1 -1
- package/browser/entry.js +1 -1
- package/browser/entry.js.map +1 -1
- package/cloudflare.d.ts +57 -0
- package/cloudflare.js +2 -0
- package/cloudflare.js.map +1 -0
- package/core/compose-html.d.ts +2 -1
- package/core/compose-html.js +1 -1
- package/core/compose-html.js.map +1 -1
- package/core/data-stream.d.ts +3 -1
- package/core/data-stream.js +1 -1
- package/core/data-stream.js.map +1 -1
- package/core/handler.d.ts +6 -2
- package/core/handler.js +1 -1
- package/core/handler.js.map +1 -1
- package/core/render.d.ts +4 -1
- package/core/render.js +1 -1
- package/core/render.js.map +1 -1
- package/core/types.d.ts +5 -1
- package/node/production.d.ts +10 -4
- package/node/production.js +1 -1
- package/node/production.js.map +1 -1
- package/package.json +36 -3
- package/services/request-timeline.d.ts +30 -0
- package/services/request-timeline.js +2 -0
- package/services/request-timeline.js.map +1 -0
- package/services/route-asset-preparer.d.ts +7 -0
- package/services/route-asset-preparer.js +2 -0
- package/services/route-asset-preparer.js.map +1 -0
- package/services/route-assets-memory.d.ts +63 -0
- package/services/route-assets-memory.js +2 -0
- package/services/route-assets-memory.js.map +1 -0
- package/services/route-assets.d.ts +9 -55
- package/services/route-assets.js +1 -1
- package/services/route-assets.js.map +1 -1
- package/services/ssr-manifest.js +1 -1
- package/services/ssr-manifest.js.map +1 -1
- package/testing/browser-observer.d.ts +30 -0
- package/testing/browser-observer.js +2 -0
- package/testing/browser-observer.js.map +1 -0
- package/testing/create-handler.d.ts +32 -0
- package/testing/create-handler.js +2 -0
- package/testing/create-handler.js.map +1 -0
- package/testing/deferred.d.ts +9 -0
- package/testing/deferred.js +2 -0
- package/testing/deferred.js.map +1 -0
- package/testing/edge.d.ts +9 -0
- package/testing/edge.js +2 -0
- package/testing/edge.js.map +1 -0
- package/testing/parse-response.d.ts +12 -0
- package/testing/parse-response.js +2 -0
- package/testing/parse-response.js.map +1 -0
- package/testing/playwright.d.ts +17 -0
- package/testing/playwright.js +2 -0
- package/testing/playwright.js.map +1 -0
- package/testing/requests.d.ts +6 -0
- package/testing/requests.js +2 -0
- package/testing/requests.js.map +1 -0
- package/testing/response.d.ts +46 -0
- package/testing/response.js +2 -0
- package/testing/response.js.map +1 -0
- package/testing.d.ts +9 -0
- package/testing.js +2 -0
- package/testing.js.map +1 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lomray/vite-ssr-boost",
|
|
3
|
-
"version": "8.4.0-beta.
|
|
3
|
+
"version": "8.4.0-beta.4",
|
|
4
4
|
"description": "SSR and streaming for existing Vite + React Router apps in Data mode, without Framework mode",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -25,6 +25,30 @@
|
|
|
25
25
|
"./*": {
|
|
26
26
|
"types": "./*.d.ts",
|
|
27
27
|
"default": "./*.js"
|
|
28
|
+
},
|
|
29
|
+
"./testing": {
|
|
30
|
+
"types": "./testing.d.ts",
|
|
31
|
+
"workerd": "./testing/edge.js",
|
|
32
|
+
"worker": "./testing/edge.js",
|
|
33
|
+
"edge-light": "./testing/edge.js",
|
|
34
|
+
"browser": "./testing/edge.js",
|
|
35
|
+
"default": "./testing.js"
|
|
36
|
+
},
|
|
37
|
+
"./testing.js": {
|
|
38
|
+
"types": "./testing.d.ts",
|
|
39
|
+
"workerd": "./testing/edge.js",
|
|
40
|
+
"worker": "./testing/edge.js",
|
|
41
|
+
"edge-light": "./testing/edge.js",
|
|
42
|
+
"browser": "./testing/edge.js",
|
|
43
|
+
"default": "./testing.js"
|
|
44
|
+
},
|
|
45
|
+
"./testing/playwright": {
|
|
46
|
+
"types": "./testing/playwright.d.ts",
|
|
47
|
+
"default": "./testing/playwright.js"
|
|
48
|
+
},
|
|
49
|
+
"./testing/playwright.js": {
|
|
50
|
+
"types": "./testing/playwright.d.ts",
|
|
51
|
+
"default": "./testing/playwright.js"
|
|
28
52
|
}
|
|
29
53
|
},
|
|
30
54
|
"keywords": [
|
|
@@ -69,7 +93,9 @@
|
|
|
69
93
|
"test:bun": "bun scripts/test-bun.mjs",
|
|
70
94
|
"test:template": "npm run build && node scripts/test-template.mjs",
|
|
71
95
|
"test:coverage": "vitest run --coverage",
|
|
72
|
-
"test:browser": "playwright test --config playwright.config.mjs"
|
|
96
|
+
"test:browser": "playwright test --config playwright.config.mjs",
|
|
97
|
+
"test:worker:packed": "node scripts/test-packed-worker.mjs",
|
|
98
|
+
"test:worker:browser": "playwright test --config playwright.worker.config.mjs"
|
|
73
99
|
},
|
|
74
100
|
"dependencies": {
|
|
75
101
|
"chalk": "^6.0.0",
|
|
@@ -92,6 +118,8 @@
|
|
|
92
118
|
"@babel/parser": "^8.0.4",
|
|
93
119
|
"@babel/traverse": "^8.0.4",
|
|
94
120
|
"@babel/types": "^8.0.4",
|
|
121
|
+
"@cloudflare/vite-plugin": "^1.54.4",
|
|
122
|
+
"@cloudflare/workers-types": "^5.20260906.1",
|
|
95
123
|
"@commitlint/cli": "^21.2.2",
|
|
96
124
|
"@commitlint/config-conventional": "^21.2.2",
|
|
97
125
|
"@lomray/eslint-config": "^7.0.0",
|
|
@@ -139,13 +167,15 @@
|
|
|
139
167
|
"typescript-eslint": "^8.69.0",
|
|
140
168
|
"vite": "^8.2.2",
|
|
141
169
|
"vitepress": "^1.6.4",
|
|
142
|
-
"vitest": "^5.0.0"
|
|
170
|
+
"vitest": "^5.0.0",
|
|
171
|
+
"wrangler": "^4.129.0"
|
|
143
172
|
},
|
|
144
173
|
"peerDependencies": {
|
|
145
174
|
"@babel/generator": ">=7.23.0",
|
|
146
175
|
"@babel/parser": ">=7.23.0",
|
|
147
176
|
"@babel/traverse": ">=7.23.0",
|
|
148
177
|
"@babel/types": ">=7.23.0",
|
|
178
|
+
"@playwright/test": ">=1.40.0",
|
|
149
179
|
"@types/compression": ">=1.7.5",
|
|
150
180
|
"@types/express": ">=4.17.21",
|
|
151
181
|
"@types/serve-static": ">=1.15.5",
|
|
@@ -163,6 +193,9 @@
|
|
|
163
193
|
},
|
|
164
194
|
"@types/serve-static": {
|
|
165
195
|
"optional": true
|
|
196
|
+
},
|
|
197
|
+
"@playwright/test": {
|
|
198
|
+
"optional": true
|
|
166
199
|
}
|
|
167
200
|
},
|
|
168
201
|
"overrides": {
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
type TRequestStage = 'router.query' | 'prepare' | 'shell.ready' | 'state.emitted' | 'stream.resolve' | 'stream.reject' | 'body.end' | 'response.end' | 'abort';
|
|
2
|
+
interface ITimelineEvent {
|
|
3
|
+
stage: TRequestStage;
|
|
4
|
+
at: number;
|
|
5
|
+
id?: number;
|
|
6
|
+
placement?: 'early' | 'footer';
|
|
7
|
+
reason?: string;
|
|
8
|
+
}
|
|
9
|
+
/** Request-local observations; never constructed on the disabled path. */
|
|
10
|
+
declare class RequestTimeline {
|
|
11
|
+
protected readonly request: Request;
|
|
12
|
+
readonly events: ITimelineEvent[];
|
|
13
|
+
readonly started: number;
|
|
14
|
+
protected ended: boolean;
|
|
15
|
+
protected aborted: boolean;
|
|
16
|
+
constructor(request: Request);
|
|
17
|
+
protected onAbort: () => void;
|
|
18
|
+
/** Offsets mark completion/emission, not the beginning of a stage. */
|
|
19
|
+
record(stage: TRequestStage, detail?: Omit<ITimelineEvent, 'stage' | 'at'>): void;
|
|
20
|
+
abort(reason?: unknown): void;
|
|
21
|
+
/** Emit one JSON line only when explicitly requested in development. */
|
|
22
|
+
end(): void;
|
|
23
|
+
/** Observe final transformed bytes without reading ahead of the consumer. */
|
|
24
|
+
response(response: Response): Response;
|
|
25
|
+
}
|
|
26
|
+
/** Keep the constructor, event array and clock reads behind the enablement check. */
|
|
27
|
+
declare const createTimeline: (request: Request, diagnostics: boolean) => RequestTimeline | undefined;
|
|
28
|
+
export { createTimeline };
|
|
29
|
+
export type { ITimelineEvent, TRequestStage };
|
|
30
|
+
export default RequestTimeline;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const e=e=>{if(e instanceof Error)return e.message;if("string"==typeof e)return e;try{return JSON.stringify(e)??"Render cancelled"}catch{return"Unserializable abort reason"}};class t{request;events=[];started=performance.now();ended=!1;aborted=!1;constructor(e){this.request=e,e.signal.aborted?this.onAbort():e.signal.addEventListener("abort",this.onAbort,{once:!0})}onAbort=()=>this.abort(this.request.signal.reason);record(e,t){this.ended||this.events.push({stage:e,at:performance.now()-this.started,...t})}abort(t){this.aborted||(this.aborted=!0,this.record("abort",{reason:e(t)}))}end(){this.ended||(this.record("response.end"),this.ended=!0,this.request.signal.removeEventListener("abort",this.onAbort),"undefined"!=typeof process&&"1"===process.env.SSR_BOOST_TIMELINE&&"production"!==process.env.NODE_ENV&&console.info(JSON.stringify({type:"SSR_BOOST_TIMELINE",method:this.request.method,path:new URL(this.request.url).pathname,timeline:this.events})))}response(e){if(!e.body)return this.end(),e;const t=e.body.getReader();let r=!1;const s=()=>{r=!0,t.releaseLock(),this.end()},n=new ReadableStream({cancel:async e=>{r=!0,this.abort(e);try{await t.cancel(e)}finally{s()}},pull:async e=>{try{const n=await t.read();if(r)return;n.done?(s(),e.close()):e.enqueue(n.value)}catch(t){r||(this.abort(t),s(),e.error(t))}}},{highWaterMark:0});return new Response(n,e)}}const r=(e,r)=>r||"undefined"!=typeof process&&"1"===process.env.SSR_BOOST_TIMELINE?new t(e):void 0;export{r as createTimeline,t as default};
|
|
2
|
+
//# sourceMappingURL=request-timeline.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request-timeline.js","sources":["../../src/services/request-timeline.ts"],"sourcesContent":[null],"names":["describeReason","reason","Error","message","JSON","stringify","RequestTimeline","request","events","started","performance","now","ended","aborted","constructor","this","signal","onAbort","addEventListener","once","abort","record","stage","detail","push","at","end","removeEventListener","process","env","SSR_BOOST_TIMELINE","NODE_ENV","console","info","type","method","path","URL","url","pathname","timeline","response","body","reader","getReader","isStopped","finish","releaseLock","ReadableStream","cancel","async","pull","controller","chunk","read","done","close","enqueue","value","error","highWaterMark","Response","createTimeline","diagnostics","undefined"],"mappings":"AAoBA,MAAMA,EAAkBC,IACtB,GAAIA,aAAkBC,MACpB,OAAOD,EAAOE,QAGhB,GAAsB,iBAAXF,EACT,OAAOA,EAGT,IACE,OAAOG,KAAKC,UAAUJ,IAAW,kBACnC,CAAE,MACA,MAAO,6BACT,GAIF,MAAMK,EAMkCC,QALtBC,OAA2B,GAC3BC,QAAUC,YAAYC,MAC5BC,OAAQ,EACRC,SAAU,EAEpB,WAAAC,CAAsCP,GAAAQ,KAAAR,QAAAA,EAChCA,EAAQS,OAAOH,QACjBE,KAAKE,UAELV,EAAQS,OAAOE,iBAAiB,QAASH,KAAKE,QAAS,CAAEE,MAAM,GAEnE,CAEUF,QAAU,IAAYF,KAAKK,MAAML,KAAKR,QAAQS,OAAOf,QAGxD,MAAAoB,CAAOC,EAAsBC,GAC7BR,KAAKH,OACRG,KAAKP,OAAOgB,KAAK,CAAEF,QAAOG,GAAIf,YAAYC,MAAQI,KAAKN,WAAYc,GAEvE,CAEO,KAAAH,CAAMnB,GACNc,KAAKF,UACRE,KAAKF,SAAU,EACfE,KAAKM,OAAO,QAAS,CAAEpB,OAAQD,EAAeC,KAElD,CAGO,GAAAyB,GACDX,KAAKH,QAITG,KAAKM,OAAO,gBACZN,KAAKH,OAAQ,EACbG,KAAKR,QAAQS,OAAOW,oBAAoB,QAASZ,KAAKE,SAGjC,oBAAZW,SAC4B,MAAnCA,QAAQC,IAAIC,oBACa,eAAzBF,QAAQC,IAAIE,UAEZC,QAAQC,KACN7B,KAAKC,UAAU,CACb6B,KAAM,qBACNC,OAAQpB,KAAKR,QAAQ4B,OACrBC,KAAM,IAAIC,IAAItB,KAAKR,QAAQ+B,KAAKC,SAChCC,SAAUzB,KAAKP,UAIvB,CAGO,QAAAiC,CAASA,GACd,IAAKA,EAASC,KAGZ,OAFA3B,KAAKW,MAEEe,EAGT,MAAME,EAASF,EAASC,KAAKE,YAC7B,IAAIC,GAAY,EAChB,MAAMC,EAAS,KACbD,GAAY,EACZF,EAAOI,cACPhC,KAAKW,OAEDgB,EAAO,IAAIM,eACf,CACEC,OAAQC,MAAOjD,IACb4C,GAAY,EACZ9B,KAAKK,MAAMnB,GAEX,UACQ0C,EAAOM,OAAOhD,EACtB,SACE6C,GACF,GAEFK,KAAMD,MAAOE,IACX,IACE,MAAMC,QAAcV,EAAOW,OAE3B,GAAIT,EACF,OAGEQ,EAAME,MACRT,IACAM,EAAWI,SAEXJ,EAAWK,QAAQJ,EAAMK,MAE7B,CAAE,MAAOC,GACFd,IACH9B,KAAKK,MAAMuC,GACXb,IACAM,EAAWO,MAAMA,GAErB,IAGJ,CAAEC,cAAe,IAGnB,OAAO,IAAIC,SAASnB,EAAMD,EAC5B,EAIF,MAAMqB,EAAiB,CAACvD,EAAkBwD,IACxCA,GAAmC,oBAAZnC,SAA8D,MAAnCA,QAAQC,IAAIC,mBAC1D,IAAIxB,EAAgBC,QACpByD"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ICreateHandlerOptions } from '../core/handler.js';
|
|
2
|
+
import type RouteAssets from './route-assets-memory.js';
|
|
3
|
+
/**
|
|
4
|
+
* Share route injection across runtimes, computing hints only for supported transports.
|
|
5
|
+
*/
|
|
6
|
+
declare const createAssetPreparer: <TAppProps = Record<string, any>>(assets: RouteAssets) => NonNullable<ICreateHandlerOptions<TAppProps>["prepare"]>;
|
|
7
|
+
export default createAssetPreparer;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"route-asset-preparer.js","sources":["../../src/services/route-asset-preparer.ts"],"sourcesContent":[null],"names":["createAssetPreparer","assets","async","context","executionContext","hints","injectAssets","Boolean","onEarlyHints","has"],"mappings":"AAMA,MAAMA,EACJC,GAEOC,OAASC,UAASC,uBACvB,MAAMC,EAAQJ,EAAOK,aAAaH,EAASI,QAAQH,GAAkBI,eAEjEH,EAAMI,IAAI,eACNL,GAAkBI,eAAeH"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type { RouterState, StaticHandlerContext } from 'react-router';
|
|
2
|
+
declare enum AssetType {
|
|
3
|
+
style = "style",
|
|
4
|
+
script = "script",
|
|
5
|
+
image = "image",
|
|
6
|
+
font = "font"
|
|
7
|
+
}
|
|
8
|
+
interface IAsset {
|
|
9
|
+
type: string;
|
|
10
|
+
url: string;
|
|
11
|
+
weight: number;
|
|
12
|
+
isNested: boolean;
|
|
13
|
+
isPreload: boolean;
|
|
14
|
+
content?: string;
|
|
15
|
+
}
|
|
16
|
+
type TAssets = {
|
|
17
|
+
[id: string]: IAsset;
|
|
18
|
+
};
|
|
19
|
+
/** Parsed build/client/assets-manifest.json; accepts a JSON module directly. */
|
|
20
|
+
type TRouteAssetsManifest = Readonly<Record<string, readonly IAsset[]>>;
|
|
21
|
+
interface IInjectAssetsContext {
|
|
22
|
+
html: {
|
|
23
|
+
header: string;
|
|
24
|
+
};
|
|
25
|
+
routerContext?: StaticHandlerContext;
|
|
26
|
+
matches?: RouterState['matches'];
|
|
27
|
+
isSpa?: boolean;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Load and inject route assets with an independent cache for one build.
|
|
31
|
+
*/
|
|
32
|
+
declare class RouteAssets {
|
|
33
|
+
protected readonly modulePreload: boolean;
|
|
34
|
+
protected routesAssets: TRouteAssetsManifest | null;
|
|
35
|
+
constructor(manifest: TRouteAssetsManifest, modulePreload?: boolean);
|
|
36
|
+
/**
|
|
37
|
+
* Development manifests override this to inject inline styles.
|
|
38
|
+
*/
|
|
39
|
+
protected get isDev(): boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Read the manifest without requiring a filesystem.
|
|
42
|
+
*/
|
|
43
|
+
protected loadAssetsManifest(): TRouteAssetsManifest;
|
|
44
|
+
/**
|
|
45
|
+
* Sort assets
|
|
46
|
+
*/
|
|
47
|
+
protected sortAssets(assets: IAsset[]): IAsset[];
|
|
48
|
+
/**
|
|
49
|
+
* Get route assets
|
|
50
|
+
*/
|
|
51
|
+
protected getAssets(routes?: RouterState['matches'], _isSpa?: boolean): IAsset[];
|
|
52
|
+
/**
|
|
53
|
+
* Build preload hints without depending on a particular HTTP transport.
|
|
54
|
+
*/
|
|
55
|
+
getEarlyHints(assets: IAsset[]): Headers;
|
|
56
|
+
/**
|
|
57
|
+
* Inject route assets to head html
|
|
58
|
+
*/
|
|
59
|
+
injectAssets({ routerContext, matches, html, isSpa }: IInjectAssetsContext, earlyHints?: boolean): Headers;
|
|
60
|
+
}
|
|
61
|
+
export { AssetType };
|
|
62
|
+
export type { IAsset, TAssets, TRouteAssetsManifest };
|
|
63
|
+
export default RouteAssets;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var e;!function(e){e.style="style",e.script="script",e.image="image",e.font="font"}(e||(e={}));let t=class{modulePreload;routesAssets;constructor(e,t=!1){this.routesAssets=e,this.modulePreload=t}get isDev(){return!1}loadAssetsManifest(){return this.routesAssets??{}}sortAssets(e){return e.sort((e,t)=>e.weight===t.weight?Number(e.isNested)-Number(t.isNested):e.weight-t.weight)}getAssets(e,t){const s=e?.map(({route:e})=>e.id).filter(Boolean)??[];if(!s.length)return[];const r=this.loadAssetsManifest();return this.sortAssets(s.map(e=>r[e]).flat().filter(Boolean))}getEarlyHints(e){const t=new Headers;return e.forEach(({type:e,url:s})=>{e&&["style","script"].includes(e)&&t.append("Link",`<${s}>; rel=preload; as=${e}`)}),t}injectAssets({routerContext:e,matches:t,html:s,isSpa:r},i=!0){const l=this.getAssets(t??e?.matches,r),n=l.map(({type:e,url:t,isPreload:s,content:i=""})=>{switch(e){case"style":return this.isDev?`<style data-vite-dev-id="${t}">${i}</style>`:`<link rel="stylesheet" href="${t}">`;case"script":return s?this.modulePreload||r?`<link rel="modulepreload" as="script" crossorigin href="${t}">`:null:`<script async type="module" crossorigin src="${t}"><\/script>`}return null}).filter(Boolean);return s.header=s.header.replace("</head>",`${n.join("\n")}</head>`),i?this.getEarlyHints(l):new Headers}};export{e as AssetType,t as default};
|
|
2
|
+
//# sourceMappingURL=route-assets-memory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"route-assets-memory.js","sources":["../../src/services/route-assets-memory.ts"],"sourcesContent":[null],"names":["AssetType","RouteAssets$1","modulePreload","routesAssets","constructor","manifest","this","isDev","loadAssetsManifest","sortAssets","assets","sort","a","b","weight","Number","isNested","getAssets","routes","_isSpa","routeIds","map","route","id","filter","Boolean","length","routeId","flat","getEarlyHints","headers","Headers","forEach","type","url","includes","append","injectAssets","routerContext","matches","html","isSpa","earlyHints","htmlAssets","isPreload","content","header","replace","join"],"mappings":"AAEA,IAAKA,GAAL,SAAKA,GACHA,EAAA,MAAA,QACAA,EAAA,OAAA,SACAA,EAAA,MAAA,QACAA,EAAA,KAAA,MACD,CALD,CAAKA,IAAAA,EAAS,CAAA,IAiCd,IAAAC,EAAA,MACqBC,cAETC,aAEV,WAAAC,CAAYC,EAAgCH,GAAgB,GAC1DI,KAAKH,aAAeE,EACpBC,KAAKJ,cAAgBA,CACvB,CAKA,SAAcK,GACZ,OAAO,CACT,CAKU,kBAAAC,GACR,OAAOF,KAAKH,cAAgB,CAAA,CAC9B,CAKU,UAAAM,CAAWC,GACnB,OAAOA,EAAOC,KAAK,CAACC,EAAGC,IACrBD,EAAEE,SAAWD,EAAEC,OAASC,OAAOH,EAAEI,UAAYD,OAAOF,EAAEG,UAAYJ,EAAEE,OAASD,EAAEC,OAEnF,CAOU,SAAAG,CAAUC,EAAiCC,GACnD,MAAMC,EAAWF,GAAQG,IAAI,EAAGC,WAAYA,EAAMC,IAAIC,OAAOC,UAAY,GAEzE,IAAKL,EAASM,OACZ,MAAO,GAGT,MAAMvB,EAAeG,KAAKE,qBAE1B,OAAOF,KAAKG,WACVW,EACGC,IAAKM,GAAYxB,EAAawB,IAC9BC,OACAJ,OAAOC,SAEd,CAKO,aAAAI,CAAcnB,GACnB,MAAMoB,EAAU,IAAIC,QAUpB,OARArB,EAAOsB,QAAQ,EAAGC,OAAMC,UACjBD,GAAS,CAAC,QAAS,UAAUE,SAASF,IAI3CH,EAAQM,OAAO,OAAQ,IAAIF,uBAAyBD,OAG/CH,CACT,CAKO,YAAAO,EACLC,cAAEA,EAAaC,QAAEA,EAAOC,KAAEA,EAAIC,MAAEA,GAChCC,GAAa,GAEb,MAAMhC,EAASJ,KAAKW,UAAUsB,GAAWD,GAAeC,QAASE,GAC3DE,EAAajC,EAChBW,IAAI,EAAGY,OAAMC,MAAKU,YAAWC,UAAU,OACtC,OAAQZ,GACN,IAAK,QACH,OAAO3B,KAAKC,MACR,4BAA4B2B,MAAQW,YACpC,gCAAgCX,MAEtC,IAAK,SACH,OAAOU,EACHtC,KAAKJ,eAAiBuC,EAEpB,2DAA2DP,MAC3D,KACF,gDAAgDA,gBAGxD,OAAO,OAERV,OAAOC,SAIV,OAFAe,EAAKM,OAASN,EAAKM,OAAOC,QAAQ,UAAW,GAAGJ,EAAWK,KAAK,gBAEzDN,EAAapC,KAAKuB,cAAcnB,GAAU,IAAIqB,OACvD"}
|
|
@@ -1,66 +1,20 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
style = "style",
|
|
4
|
-
script = "script",
|
|
5
|
-
image = "image",
|
|
6
|
-
font = "font"
|
|
7
|
-
}
|
|
8
|
-
interface IAsset {
|
|
9
|
-
type: AssetType;
|
|
10
|
-
url: string;
|
|
11
|
-
weight: number;
|
|
12
|
-
isNested: boolean;
|
|
13
|
-
isPreload: boolean;
|
|
14
|
-
content?: string;
|
|
15
|
-
}
|
|
16
|
-
type TAssets = {
|
|
17
|
-
[id: string]: IAsset;
|
|
18
|
-
};
|
|
19
|
-
interface IInjectAssetsContext {
|
|
20
|
-
html: {
|
|
21
|
-
header: string;
|
|
22
|
-
};
|
|
23
|
-
routerContext?: StaticHandlerContext;
|
|
24
|
-
matches?: RouterState['matches'];
|
|
25
|
-
isSpa?: boolean;
|
|
26
|
-
}
|
|
1
|
+
import MemoryRouteAssets from './route-assets-memory.js';
|
|
2
|
+
import type { TRouteAssetsManifest } from './route-assets-memory.js';
|
|
27
3
|
/**
|
|
28
|
-
*
|
|
4
|
+
* Keep the Node manifest cache while also accepting a parsed JSON manifest.
|
|
29
5
|
*/
|
|
30
|
-
declare class RouteAssets {
|
|
6
|
+
declare class RouteAssets extends MemoryRouteAssets {
|
|
31
7
|
protected readonly outputDir: string;
|
|
32
|
-
|
|
33
|
-
protected routesAssets: Record<string, IAsset[]> | null;
|
|
34
|
-
constructor(buildDir: string, modulePreload?: boolean);
|
|
35
|
-
/**
|
|
36
|
-
* Development manifests override this to inject inline styles.
|
|
37
|
-
*/
|
|
38
|
-
protected get isDev(): boolean;
|
|
8
|
+
constructor(buildDir: string | TRouteAssetsManifest, modulePreload?: boolean);
|
|
39
9
|
/**
|
|
40
10
|
* Get assets manifest file name.
|
|
41
11
|
*/
|
|
42
12
|
protected getAssetsManifestFile(): string;
|
|
43
13
|
/**
|
|
44
|
-
* Load
|
|
45
|
-
*/
|
|
46
|
-
protected loadAssetsManifest(): Record<string, IAsset[]>;
|
|
47
|
-
/**
|
|
48
|
-
* Sort assets
|
|
49
|
-
*/
|
|
50
|
-
protected sortAssets(assets: IAsset[]): IAsset[];
|
|
51
|
-
/**
|
|
52
|
-
* Get route assets
|
|
53
|
-
*/
|
|
54
|
-
protected getAssets(routes?: RouterState['matches'], _isSpa?: boolean): IAsset[];
|
|
55
|
-
/**
|
|
56
|
-
* Build preload hints without depending on a particular HTTP transport.
|
|
57
|
-
*/
|
|
58
|
-
getEarlyHints(assets: IAsset[]): Headers;
|
|
59
|
-
/**
|
|
60
|
-
* Inject route assets to head html
|
|
14
|
+
* Load and cache the Node manifest on first use.
|
|
61
15
|
*/
|
|
62
|
-
|
|
16
|
+
protected loadAssetsManifest(): TRouteAssetsManifest;
|
|
63
17
|
}
|
|
64
|
-
export { AssetType };
|
|
65
|
-
export type { IAsset, TAssets };
|
|
18
|
+
export { AssetType } from './route-assets-memory.js';
|
|
19
|
+
export type { IAsset, TAssets, TRouteAssetsManifest } from './route-assets-memory.js';
|
|
66
20
|
export default RouteAssets;
|
package/services/route-assets.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import
|
|
1
|
+
import s from"node:fs";import t from"node:path";import e from"./route-assets-memory.js";export{AssetType}from"./route-assets-memory.js";class r extends e{outputDir;constructor(s,e=!1){super("string"==typeof s?{}:s,e),this.outputDir="string"==typeof s?t.resolve(s):"",this.routesAssets="string"==typeof s?null:s}getAssetsManifestFile(){return t.join(this.outputDir,"server","assets-manifest.json")}loadAssetsManifest(){if(null!==this.routesAssets)return this.routesAssets;const t=this.getAssetsManifestFile();return s.existsSync(t)?(this.routesAssets=JSON.parse(s.readFileSync(t,"utf8")),this.routesAssets):{}}}export{r as default};
|
|
2
2
|
//# sourceMappingURL=route-assets.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"route-assets.js","sources":["../../src/services/route-assets.ts"],"sourcesContent":[null],"names":["
|
|
1
|
+
{"version":3,"file":"route-assets.js","sources":["../../src/services/route-assets.ts"],"sourcesContent":[null],"names":["RouteAssets","MemoryRouteAssets","outputDir","constructor","buildDir","modulePreload","super","this","path","resolve","routesAssets","getAssetsManifestFile","join","loadAssetsManifest","manifestFile","fs","existsSync","JSON","parse","readFileSync"],"mappings":"wIAQA,MAAMA,UAAoBC,EACLC,UAEnB,WAAAC,CAAYC,EAAyCC,GAAgB,GACnEC,MAA0B,iBAAbF,EAAwB,CAAA,EAAKA,EAAUC,GACpDE,KAAKL,UAAgC,iBAAbE,EAAwBI,EAAKC,QAAQL,GAAY,GACzEG,KAAKG,aAAmC,iBAAbN,EAAwB,KAAOA,CAC5D,CAKU,qBAAAO,GACR,OAAOH,EAAKI,KAAKL,KAAKL,UAAW,SAAU,uBAC7C,CAKU,kBAAAW,GACR,GAA0B,OAAtBN,KAAKG,aACP,OAAOH,KAAKG,aAGd,MAAMI,EAAeP,KAAKI,wBAE1B,OAAKI,EAAGC,WAAWF,IAInBP,KAAKG,aAAeO,KAAKC,MAAMH,EAAGI,aAAaL,EAAc,SAEtDP,KAAKG,cALH,CAAA,CAMX"}
|
package/services/ssr-manifest.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import e from"node:fs";import t from"node:path";import s from"chalk";import i from"./parse-routes.js";import r from"./path-normalize.js";import o
|
|
1
|
+
import e from"node:fs";import t from"node:path";import s from"chalk";import i from"./parse-routes.js";import r from"./path-normalize.js";import o from"./route-assets.js";import{AssetType as a}from"./route-assets-memory.js";class n extends o{static instance=null;config;pathNormalize;root;buildDir;manifestName="manifest.json";viteAliases;basename;renderBuiltUrl;constructor(e,{buildDir:s,viteAliases:i,basename:o,renderBuiltUrl:a}={}){super(t.resolve(e.getParams().root,s||""),e.isModulePreload),this.config=e,this.root=e.getParams().root,this.buildDir=s,this.viteAliases=i??e.getVite()?.config?.resolve.alias,this.pathNormalize=new r(e,i),this.basename=o,this.renderBuiltUrl=a}static get(e,t={}){return null===n.instance&&(n.instance=new n(e,t)),n.instance}get isDev(){return Boolean(this.config.getVite())}getOutDir(){return t.resolve(this.root,this.buildDir||"")}getAssetsManifestFile(){return`${this.getOutDir()}/server/assets-manifest.json`}loadClientManifest(){const s=t.resolve(this.root,`${this.buildDir||""}/client/.vite`),i=`${s}/${this.manifestName}`;if(!e.existsSync(i))return{};const r=JSON.parse(e.readFileSync(i,{encoding:"utf-8"}));return e.rmSync(i),0===e.readdirSync(s).length&&e.rmSync(s,{recursive:!0}),r}getRoutesTreeIds(e,t){const s={};return e.forEach(e=>{const i=[t,String(e.index)].filter(Boolean).join("-"),r=e.id??i;e.import&&(s[r]=this.pathNormalize.getAppPath(e.import)),e.children.length>0&&Object.assign(s,this.getRoutesTreeIds(e.children,i))}),s}getRouteAssets(e,s,i=!1){const r=[...s?.assets??[],...s?.css??[],s?.file].reduce((e,r)=>{if(r){const o=this.getAssetType(r),a=s.isEntry&&s.file===r;if(o){const s=t.posix.normalize(`${this.basename}/${r}`),n=this.renderBuiltUrl?.(s,{type:"asset",ssr:!0,hostId:"",hostType:s.split(".").at(-1)?.toLowerCase()});e[r]={url:"string"==typeof n?n:s,weight:a?1.9:this.getAssetWeight(r),type:o,isNested:i,isPreload:!a}}}return e},{});return s?.imports?.length&&s.imports.forEach(t=>{const s=e[t];s&&Object.assign(r,this.getRouteAssets(e,s,!0))}),r}buildRoutesManifest(){const s=this.loadClientManifest(),r=new i(this.config,this.viteAliases),o=this.getRoutesTreeIds(r.parse()),a=this.pathNormalize.getImportPostfix(),n={};Object.entries(o).forEach(([e,t])=>{const i=a.find(e=>void 0!==s[`${t}${e}`]),r=s[`${t}${i||""}`];n[e]=this.sortAssets(Object.values(this.getRouteAssets(s,r)))});const l=JSON.stringify(n,null,2);e.writeFileSync(this.getAssetsManifestFile(),l,{encoding:"utf-8"});const c=t.join(this.getOutDir(),"client");e.existsSync(c)&&e.writeFileSync(t.join(c,"assets-manifest.json"),l,{encoding:"utf-8"})}getAssets(e,t){return this.isDev?this.getAssetsDev(e,t):super.getAssets(e)}getDevRouteIds(e){return e?.map(({route:e})=>this.pathNormalize.getAppPath(e?.pathId,!0)).filter(Boolean)??[]}getDevModules(e){const s=this.getDevRouteIds(e),i=this.pathNormalize.getImportPostfix(),r=this.config.getPluginConfig(),o=[r?.clientFile??"client.ts",r?.serverFile??"server.ts"].map(e=>t.resolve(this.root,e)),a=[];return[...o,...s].forEach(e=>{for(const t of i){const s=this.config.getVite()?.moduleGraph.getModuleById(`${e}${t}`);if(s){a.push(s);break}}}),a}async prepareDevAssets(e,t=!1){const s=this.config.getVite();if(!s)return;t&&await Promise.all(this.getDevRouteIds(e).map(async e=>{const t=this.pathNormalize.findAppFile(e);t&&await s.transformRequest(`/@fs/${t}`)}));const i=new Set,r=async e=>{i.has(e.url)||(i.add(e.url),e.file&&/\.(?:css|less|s[ac]ss|styl(?:us)?|pcss|postcss)$/.test(e.file)&&await s.transformRequest(e.url),await Promise.all([...e.importedModules].map(r)))};await Promise.all(this.getDevModules(e).map(r))}getAssetsDev(e,t=!1){const s=Object.assign({},...this.getDevModules(e).map(e=>this.getModuleAssets(e))),i=t?this.getDevRouteIds(e).flatMap(e=>{const t=this.pathNormalize.getImportPostfix().map(t=>this.config.getVite()?.moduleGraph.getModuleById(`${e}${t}`)).find(Boolean);return t?[{type:a.script,url:t.url,weight:2,isNested:!1,isPreload:!0}]:[]}):[];return[...Object.values(s),...i]}getModuleAssets(e,t=new Set){const i=e?.importedModules??e?.clientImportedModules;if(!i?.size||t.has(e.file))return{};let r={};return t.add(e.file),i.forEach(e=>{const{file:i,transformResult:o}=e,n=i?.split(".").at(-1);if(i&&n&&["css","scss","sass","less","styl","stylus","pcss","postcss"].includes(n)){const e=o?.code.match(/__vite__css\s+=\s+"(?<css>.+)"/)?.groups?.css;if(e)try{r[i]={type:a.style,url:i,weight:this.getAssetWeight(i),content:JSON.parse(`{"style": "${e}"}`).style,isNested:Boolean(t.size),isPreload:!1}}catch{console.warn(s.yellowBright("Failed to parse style: ",i))}}else r={...r,...this.getModuleAssets(e,t)}}),r}getAssetWeight(e){switch(this.getAssetType(e)){case a.style:return 1;case a.script:return 2;default:return 3}}getAssetType(e){const t=e.split(".").at(-1)?.toLowerCase();switch(t){case"css":case"scss":return a.style;case"js":return a.script;case"svg":case"jpg":case"jpeg":case"png":case"webp":case"gif":case"ico":return a.image;case"ttf":case"otf":case"woff":case"woff2":return a.font;default:return null}}}export{n as default};
|
|
2
2
|
//# sourceMappingURL=ssr-manifest.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ssr-manifest.js","sources":["../../src/services/ssr-manifest.ts"],"sourcesContent":[null],"names":["SsrManifest","RouteAssets","static","config","pathNormalize","root","buildDir","manifestName","viteAliases","basename","renderBuiltUrl","constructor","super","path","resolve","getParams","isModulePreload","this","getVite","alias","PathNormalize","get","params","instance","isDev","Boolean","getOutDir","getAssetsManifestFile","loadClientManifest","clientManifestDir","clientSsrManifest","fs","existsSync","result","JSON","parse","readFileSync","encoding","rmSync","readdirSync","length","recursive","getRoutesTreeIds","routes","index","forEach","route","position","String","filter","join","routeId","id","import","getAppPath","children","Object","assign","getRouteAssets","manifest","module","isNested","assets","css","file","reduce","res","asset","type","getAssetType","isEntry","filename","posix","normalize","modifiedFilename","ssr","hostId","hostType","split","at","toLowerCase","url","weight","getAssetWeight","isPreload","imports","nestedAsset","nestedModule","buildRoutesManifest","routesService","ParseRoutes","routesPaths","postfixes","getImportPostfix","entries","routePath","routePostfix","find","postfix","undefined","routeMeta","sortAssets","values","
|
|
1
|
+
{"version":3,"file":"ssr-manifest.js","sources":["../../src/services/ssr-manifest.ts"],"sourcesContent":[null],"names":["SsrManifest","RouteAssets","static","config","pathNormalize","root","buildDir","manifestName","viteAliases","basename","renderBuiltUrl","constructor","super","path","resolve","getParams","isModulePreload","this","getVite","alias","PathNormalize","get","params","instance","isDev","Boolean","getOutDir","getAssetsManifestFile","loadClientManifest","clientManifestDir","clientSsrManifest","fs","existsSync","result","JSON","parse","readFileSync","encoding","rmSync","readdirSync","length","recursive","getRoutesTreeIds","routes","index","forEach","route","position","String","filter","join","routeId","id","import","getAppPath","children","Object","assign","getRouteAssets","manifest","module","isNested","assets","css","file","reduce","res","asset","type","getAssetType","isEntry","filename","posix","normalize","modifiedFilename","ssr","hostId","hostType","split","at","toLowerCase","url","weight","getAssetWeight","isPreload","imports","nestedAsset","nestedModule","buildRoutesManifest","routesService","ParseRoutes","routesPaths","postfixes","getImportPostfix","entries","routePath","routePostfix","find","postfix","undefined","routeMeta","sortAssets","values","json","stringify","writeFileSync","clientDir","getAssets","isSpa","getAssetsDev","getDevRouteIds","map","pathId","getDevModules","routeIds","pluginConfig","getPluginConfig","rootIds","clientFile","serverFile","modules","moduleId","ext","moduleGraph","getModuleById","push","prepareDevAssets","vite","Promise","all","async","findAppFile","transformRequest","visited","Set","visit","has","add","test","importedModules","getModuleAssets","scripts","flatMap","AssetType","script","skipModules","clientImportedModules","size","subModule","transformResult","includes","code","match","groups","style","content","console","warn","chalk","yellowBright","image","font"],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
interface IBrowserTimelineEvent {
|
|
2
|
+
stage: 'shell' | 'router.ready' | 'init' | 'resolve' | 'reject' | 'response.end';
|
|
3
|
+
at: number;
|
|
4
|
+
id?: number;
|
|
5
|
+
}
|
|
6
|
+
interface IBrowserObservation {
|
|
7
|
+
events: IBrowserTimelineEvent[];
|
|
8
|
+
errors: string[];
|
|
9
|
+
roots: Record<string, string>;
|
|
10
|
+
seen: WeakMap<Element, number>;
|
|
11
|
+
shellAt?: number;
|
|
12
|
+
}
|
|
13
|
+
declare global {
|
|
14
|
+
interface Window {
|
|
15
|
+
__ssrBoostTest?: IBrowserObservation;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
/** Serialized by addInitScript: keep every runtime dependency inside this function. */
|
|
19
|
+
declare const installBrowserObserver: () => void;
|
|
20
|
+
interface IHydrationInspection {
|
|
21
|
+
ready: boolean;
|
|
22
|
+
consumed: boolean;
|
|
23
|
+
pending: number;
|
|
24
|
+
duplicates: string[];
|
|
25
|
+
errors: string[];
|
|
26
|
+
}
|
|
27
|
+
/** Compare server text multiplicities to the hydrated root, allowing existing repeats. */
|
|
28
|
+
declare const inspectHydration: (selector: string) => IHydrationInspection;
|
|
29
|
+
export { installBrowserObserver, inspectHydration };
|
|
30
|
+
export type { IBrowserTimelineEvent, IHydrationInspection };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const e=()=>{if(window.__ssrBoostTest)return;const e={events:[],errors:[],roots:{},seen:new WeakMap};window.__ssrBoostTest=e;const t=(t,o)=>{e.events.push({stage:t,at:performance.now(),...void 0===o?{}:{id:o}})},o=()=>{const o=performance.now();for(const r of document.querySelectorAll("body *")){const n=r.getBoundingClientRect();!r.closest("script, style, template, [hidden]")&&n.width>0&&n.height>0&&"hidden"!==getComputedStyle(r).visibility&&(void 0===e.shellAt&&(e.shellAt=o,t("shell")),e.seen.has(r)||e.seen.set(r,o))}};new MutationObserver(o).observe(document,{childList:!0,subtree:!0,attributes:!0});const r=console.error;console.error=(...t)=>{e.errors.push(t.map(String).join(" ")),r(...t)},window.addEventListener("error",t=>e.errors.push(t.message)),window.addEventListener("unhandledrejection",t=>e.errors.push(String(t.reason))),window.addEventListener("ssr-boost:router-ready",r=>{const{rootId:n}=r.detail,s=document.getElementById(n);s&&(e.roots[n]=s.innerHTML),o(),t("router.ready")}),window.addEventListener("load",()=>t("response.end"),{once:!0});const n=[];let s=Array.prototype.push;const d=new WeakSet;Object.defineProperty(n,"push",{configurable:!0,get:()=>(...e)=>{for(const o of e){if(d.has(o))continue;d.add(o);const[e,r]=o;"init"!==e&&"resolve"!==e&&"reject"!==e||t(e,"number"==typeof r?r:void 0)}return s.apply(n,e)},set:e=>{s=e}}),Reflect.set(window,"__ssrBoostStream",n)},t=e=>{const t=window.__ssrBoostTest,o=document.querySelector(e),r=o?t?.roots[o.id]:void 0,n=document.createElement("div");n.innerHTML=r??"";const s=e=>{const t=new Map;for(const o of[e,...e.querySelectorAll("*")]){if(o.closest("script, style, template, [hidden]"))continue;const e=[...o.childNodes].filter(e=>e.nodeType===Node.TEXT_NODE).map(e=>e.textContent).join("").replace(/\s+/g," ").trim();e&&t.set(e,(t.get(e)??0)+1)}return t},d=s(n),i=o?s(o):new Map,c=(e,t)=>{let o=0;for(const[r,n]of e){const e=r.length/t.length;Number.isInteger(e)&&t.repeat(e)===r&&(o+=e*n)}return o},l=[...d].filter(([e])=>c(i,e)>c(d,e)).map(([e])=>e),a=o?document.createTreeWalker(o,NodeFilter.SHOW_COMMENT):void 0;let u=0;for(;a?.nextNode();)"$?"===a.currentNode.textContent&&u++;return{ready:void 0!==r,consumed:void 0===Reflect.get(window,"__staticRouterHydrationData"),pending:u,duplicates:l,errors:t?.errors.filter(e=>/(?:#|errors\/)(418|423|425)\b|hydrat(?:ion|ing|e|ed)|server rendered HTML|did not match/i.test(e))??[]}};export{t as inspectHydration,e as installBrowserObserver};
|
|
2
|
+
//# sourceMappingURL=browser-observer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser-observer.js","sources":["../../src/testing/browser-observer.ts"],"sourcesContent":[null],"names":["installBrowserObserver","window","__ssrBoostTest","state","events","errors","roots","seen","WeakMap","record","stage","id","push","at","performance","now","undefined","scan","element","document","querySelectorAll","rect","getBoundingClientRect","closest","width","height","getComputedStyle","visibility","shellAt","has","set","MutationObserver","observe","childList","subtree","attributes","originalError","console","error","args","map","String","join","addEventListener","event","message","reason","rootId","detail","root","getElementById","innerHTML","once","queue","downstream","Array","prototype","observed","WeakSet","Object","defineProperty","configurable","get","frames","frame","add","apply","replacement","Reflect","inspectHydration","selector","querySelector","html","server","createElement","texts","counts","Map","child","text","childNodes","filter","node","nodeType","Node","TEXT_NODE","textContent","replace","trim","before","after","multiplicity","total","candidate","count","copies","length","Number","isInteger","repeat","duplicates","walker","createTreeWalker","NodeFilter","SHOW_COMMENT","pending","nextNode","currentNode","ready","consumed","test"],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { FC, PropsWithChildren } from 'react';
|
|
2
|
+
import type { RouteObject } from 'react-router';
|
|
3
|
+
import { createStaticHandler } from 'react-router';
|
|
4
|
+
import type { ICreateHandlerOptions, IHtmlShell } from '../core/handler.js';
|
|
5
|
+
import type { TRenderToStream } from '../core/render.js';
|
|
6
|
+
import type { TRouteObject } from '../interfaces/route-object.js';
|
|
7
|
+
import type { ILoadHtmlShellOptions } from '../node/production.js';
|
|
8
|
+
import TestResponse from './response.js';
|
|
9
|
+
interface ITestRequestInit extends RequestInit {
|
|
10
|
+
isStream?: boolean;
|
|
11
|
+
/** Whole-request deadline, including loaders and body consumption. */
|
|
12
|
+
timeout?: number;
|
|
13
|
+
}
|
|
14
|
+
interface ITestHandlerOptions<TAppProps> extends Omit<ICreateHandlerOptions<TAppProps>, 'getHtml'> {
|
|
15
|
+
routes: TRouteObject[] | RouteObject[];
|
|
16
|
+
App?: FC<PropsWithChildren<{
|
|
17
|
+
server: TAppProps;
|
|
18
|
+
}>>;
|
|
19
|
+
shell?: IHtmlShell | ILoadHtmlShellOptions;
|
|
20
|
+
routerOptions?: Parameters<typeof createStaticHandler>[1];
|
|
21
|
+
renderToStream?: TRenderToStream;
|
|
22
|
+
signal?: AbortSignal;
|
|
23
|
+
timeout?: number;
|
|
24
|
+
}
|
|
25
|
+
interface ITestHandler {
|
|
26
|
+
fetch: (input: string | Request, init?: ITestRequestInit) => Promise<TestResponse>;
|
|
27
|
+
}
|
|
28
|
+
type TLoadShell = (options: ILoadHtmlShellOptions) => Promise<() => IHtmlShell>;
|
|
29
|
+
/** Share the Fetch-only implementation between Node and conditional edge exports. */
|
|
30
|
+
declare const testHandlerFactory: (renderer: TRenderToStream, loadShell: TLoadShell) => <TAppProps = Record<string, any>>({ routes, App, shell, routerOptions, renderToStream, signal: defaultSignal, timeout: defaultTimeout, onContext, onRouterReady, ...options }: ITestHandlerOptions<TAppProps>) => ITestHandler;
|
|
31
|
+
export type { ITestHandler, ITestHandlerOptions, ITestRequestInit };
|
|
32
|
+
export default testHandlerFactory;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import e from"react";import{createStaticHandler as t}from"react-router";import r from"../core/handler.js";import{TEST_ORIGIN as o}from"./requests.js";import n from"./response.js";const i={header:'<!doctype html><html><head></head><body><div id="root">',footer:'</div><script type="module">/* test browser entry */<\/script></body></html>'},a=(a,s)=>({routes:m,App:c,shell:l=i,routerOptions:d,renderToStream:u=a,signal:p,timeout:f,onContext:h,onRouterReady:b,...w})=>{const y=t(m,d);let g;const v=async()=>"indexFile"in l?(g??=s(l),(await g)()):{...l};return{fetch:async(t,{isStream:i,timeout:a=f,signal:s,...m}={})=>{const l=performance.now(),d=new AbortController,g=[d.signal,p,s,t instanceof Request?t.signal:void 0].filter(e=>Boolean(e)),R=AbortSignal.any(g),S=new Request("string"==typeof t?new URL(t,o):t,{...m,signal:R});let x,E,A;const T=new Promise((e,t)=>{A=t}),C=()=>A(R.reason),j=()=>{clearTimeout(x),R.removeEventListener("abort",C)};if(R.addEventListener("abort",C,{once:!0}),void 0!==a){if(!Number.isFinite(a)||a<0)throw j(),new RangeError("timeout must be a finite, non-negative number of milliseconds.");x=setTimeout(()=>d.abort(new DOMException(`SSR test timed out after ${a}ms`,"TimeoutError")),a)}try{R.throwIfAborted();const t=r({handler:y,renderToStream:u,createApp:(t,r)=>c?e.createElement(c,{server:r.appProps},t):t},{...w,getHtml:v,onContext:e=>{({timeline:E}=e.context),h?.(e)},onRouterReady:async e=>{const t=await(b?.(e));return void 0===i?t??{}:{...t,isStream:i}}})(S);t.then(e=>{if(R.aborted)return e.body?.cancel(R.reason)}).catch(()=>{});const o=await Promise.race([t,T]);return new n(o,{started:l,timeline:E,signal:R,onComplete:j})}catch(e){throw j(),E?.abort(e),E?.end(),e}}}};export{a as default};
|
|
2
|
+
//# sourceMappingURL=create-handler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-handler.js","sources":["../../src/testing/create-handler.tsx"],"sourcesContent":[null],"names":["DEFAULT_SHELL","header","footer","testHandlerFactory","renderer","loadShell","routes","App","shell","routerOptions","renderToStream","signal","defaultSignal","timeout","defaultTimeout","onContext","onRouterReady","options","handler","createStaticHandler","fileShell","getHtml","async","fetch","input","isStream","init","started","performance","now","controller","AbortController","signals","Request","undefined","filter","item","Boolean","combined","AbortSignal","any","request","URL","TEST_ORIGIN","timer","timeline","rejectAbort","aborted","Promise","_","reject","onAbort","reason","cleanup","clearTimeout","removeEventListener","addEventListener","once","Number","isFinite","RangeError","setTimeout","abort","DOMException","throwIfAborted","pending","createHandler","createApp","children","context","React","createElement","server","appProps","params","result","then","response","body","cancel","catch","race","TestResponse","onComplete","error","end"],"mappings":"mLAmCA,MAAMA,EAA4B,CAChCC,OAAQ,0DACRC,OAAQ,gFAIJC,EACJ,CAACC,EAA2BC,IAC5B,EACEC,SACAC,MACAC,QAAQR,EACRS,gBACAC,iBAAiBN,EACjBO,OAAQC,EACRC,QAASC,EACTC,YACAC,mBACGC,MAEH,MAAMC,EAAUC,EAAoBb,EAAyBG,GAC7D,IAAIW,EACJ,MAAMC,EAAUC,SACV,cAAed,GACjBY,IAAcf,EAAUG,UAEVY,MAGT,IAAKZ,GAGd,MAAO,CACLe,MAAOD,MAAOE,GAASC,WAAUZ,UAAUC,EAAgBH,YAAWe,GAAS,MAC7E,MAAMC,EAAUC,YAAYC,MACtBC,EAAa,IAAIC,gBACjBC,EAAU,CACdF,EAAWnB,OACXC,EACAD,EACAa,aAAiBS,QAAUT,EAAMb,YAASuB,GAC1CC,OAAQC,GAA8BC,QAAQD,IAC1CE,EAAWC,YAAYC,IAAIR,GAC3BS,EAAU,IAAIR,QACD,iBAAVT,EAAqB,IAAIkB,IAAIlB,EAAOmB,GAAenB,EAC1D,IACKE,EACHf,OAAQ2B,IAGZ,IAAIM,EACAC,EACAC,EACJ,MAAMC,EAAU,IAAIC,QAAe,CAACC,EAAGC,KACrCJ,EAAcI,IAEVC,EAAU,IAAYL,EAAYR,EAASc,QAC3CC,EAAU,KACdC,aAAaV,GACbN,EAASiB,oBAAoB,QAASJ,IAKxC,GAFAb,EAASkB,iBAAiB,QAASL,EAAS,CAAEM,MAAM,SAEpCvB,IAAZrB,EAAuB,CACzB,IAAK6C,OAAOC,SAAS9C,IAAYA,EAAU,EAEzC,MADAwC,IACM,IAAIO,WAAW,kEAGvBhB,EAAQiB,WACN,IACE/B,EAAWgC,MACT,IAAIC,aAAa,4BAA4BlD,MAAa,iBAE9DA,EAEJ,CAEA,IACEyB,EAAS0B,iBACT,MAqBMC,EArBQC,EACZ,CACEhD,UACAR,iBACAyD,UAAW,CAACC,EAAUC,IACpB9D,EAAM+D,EAAAC,cAAChE,EAAG,CAACiE,OAAQH,EAAQI,UAAWL,GAAkBA,GAE5D,IACKnD,EACHI,UACAN,UAAY2D,MACP7B,YAAa6B,EAAOL,SACvBtD,IAAY2D,IAEd1D,cAAeM,MAAOoD,IACpB,MAAMC,QAAe3D,IAAgB0D,IAErC,YAAoBxC,IAAbT,EAA0BkD,GAAU,CAAA,EAAM,IAAKA,EAAQlD,cAIpDF,CAAMkB,GAGjBwB,EACFW,KAAMC,IACL,GAAIvC,EAASS,QACX,OAAO8B,EAASC,MAAMC,OAAOzC,EAASc,UAKzC4B,MAAM,QAET,MAAMH,QAAiB7B,QAAQiC,KAAK,CAAChB,EAASlB,IAE9C,OAAO,IAAImC,EAAaL,EAAU,CAChClD,UACAkB,WACAlC,OAAQ2B,EACR6C,WAAY9B,GAEhB,CAAE,MAAO+B,GAIP,MAHA/B,IACAR,GAAUiB,MAAMsB,GAChBvC,GAAUwC,MACJD,CACR"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
interface IDeferred<T> {
|
|
2
|
+
promise: Promise<T>;
|
|
3
|
+
resolve: (value: T | PromiseLike<T>) => void;
|
|
4
|
+
reject: (reason?: unknown) => void;
|
|
5
|
+
}
|
|
6
|
+
/** Control loader timing without sleeps or a running HTTP server. */
|
|
7
|
+
declare const createDeferred: <T>() => IDeferred<T>;
|
|
8
|
+
export type { IDeferred };
|
|
9
|
+
export default createDeferred;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deferred.js","sources":["../../src/testing/deferred.ts"],"sourcesContent":[null],"names":["createDeferred","resolve","reject","promise","Promise","res","rej","catch"],"mappings":"AAOA,MAAMA,EAAiB,KACrB,IAAIC,EACAC,EACJ,MAAMC,EAAU,IAAIC,QAAW,CAACC,EAAKC,KACnCL,EAAUI,EACVH,EAASI,IAMX,OAFKH,EAAQI,MAAM,QAEZ,CAAEJ,UAASF,UAASC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
declare const createTestHandler: <TAppProps = Record<string, any>>({ routes, App, shell, routerOptions, renderToStream, signal: defaultSignal, timeout: defaultTimeout, onContext, onRouterReady, ...options }: import("./create-handler.js").ITestHandlerOptions<TAppProps>) => import("./create-handler.js").ITestHandler;
|
|
2
|
+
export { createTestHandler };
|
|
3
|
+
export { default as createDeferred } from './deferred.js';
|
|
4
|
+
export { browserRequest, crawlerRequest } from './requests.js';
|
|
5
|
+
export { default as TestResponse } from './response.js';
|
|
6
|
+
export type { ITestHandler, ITestHandlerOptions, ITestRequestInit } from './create-handler.js';
|
|
7
|
+
export type { ITestChunk, ITestCookie, ITestResponseOptions } from './response.js';
|
|
8
|
+
export type { IRouterState, TStreamFrame } from './parse-response.js';
|
|
9
|
+
export type { ITimelineEvent, TRequestStage } from '../services/request-timeline.js';
|
package/testing/edge.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import e from"../edge/render-to-stream.js";import r from"./create-handler.js";export{default as createDeferred}from"./deferred.js";export{browserRequest,crawlerRequest}from"./requests.js";export{default as TestResponse}from"./response.js";const s=r(e,()=>{throw new Error("shell.indexFile requires Node. In edge tests pass shell: { header, footer }.")});export{s as createTestHandler};
|
|
2
|
+
//# sourceMappingURL=edge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"edge.js","sources":["../../src/testing/edge.ts"],"sourcesContent":[null],"names":["createTestHandler","testHandlerFactory","renderToStream","Error"],"mappings":"+OAGA,MAAMA,EAAoBC,EAAmBC,EAAgB,KAC3D,MAAM,IAAIC,MAAM"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
type TStreamFrame = ['init', string, boolean] | ['resolve' | 'reject', number, string] | ['shell'];
|
|
2
|
+
interface IRouterState {
|
|
3
|
+
loaderData: Record<string, any>;
|
|
4
|
+
actionData: Record<string, any> | null;
|
|
5
|
+
errors: Record<string, any> | null;
|
|
6
|
+
}
|
|
7
|
+
/** Frames contain only primitive tuple fields; encoded values are JSON strings. */
|
|
8
|
+
declare const streamFrames: (html: string) => TStreamFrame[];
|
|
9
|
+
/** Resolve nested identities and preserve native collections, holes and own keys. */
|
|
10
|
+
declare const routerState: (html: string) => IRouterState | undefined;
|
|
11
|
+
export { routerState, streamFrames };
|
|
12
|
+
export type { IRouterState, TStreamFrame };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{parse as e}from"devalue";import{parse as t}from"parse5";const r=e=>{const r=[],o=e=>{"tagName"in e&&"script"===e.tagName?r.push(e.childNodes.map(e=>"value"in e?e.value:"").join("")):"childNodes"in e&&e.childNodes.forEach(o)};return o(t(e)),r},o=e=>{const t=[];for(const o of r(e)){const e=/\(window\.__ssrBoostStream\s*=\s*window\.__ssrBoostStream\s*\|\|\s*\[\]\)\.push\((\[(?:"(?:\\.|[^"\\])*"|[^\]"\\])*\])\)/g;for(const r of o.matchAll(e)){const e=JSON.parse(r[1]);if(!Array.isArray(e)||!("shell"===e[0]&&1===e.length||"init"===e[0]&&3===e.length&&"string"==typeof e[1]&&"boolean"==typeof e[2]||["resolve","reject"].includes(e[0])&&3===e.length&&Number.isInteger(e[1])&&"string"==typeof e[2]))throw new Error("Invalid SSR Boost stream frame.");t.push(e)}}return t};class s{id;constructor(e){this.id=e}}const n=t=>e(t,{SSRBPromise:([e])=>new s(e),SSRBObject:e=>Object.fromEntries(e),SSRBError:e=>{const t=Object.fromEntries(e),r=Object.assign(new Error("Streamed loader/action rejection"),t);return t.stack||delete r.stack,r},SSRBUndefined:()=>{}}),a=e=>{const t=o(e),a=t.filter(e=>"init"===e[0]);if(!a.length){for(const t of r(e)){const e=t.match(/window\.__staticRouterHydrationData\s*=\s*JSON\.parse\(("(?:\\.|[^"\\])*")\)/);if(e)return JSON.parse(JSON.parse(e[1]))}return}if(1!==a.length)throw new Error("Expected exactly one SSR Boost init frame.");const i=new Map,c=new Set;for(const e of t)if("resolve"===e[0]||"reject"===e[0]){if(i.has(e[1]))throw new Error(`Duplicate settlement for SSR promise ${e[1]}.`);i.set(e[1],n(e[2])),"reject"===e[0]&&c.add(e[1])}const f=new WeakSet,l=new Set,d=new Map,h=e=>{if(e instanceof s){const{id:t}=e;if(!i.has(t))throw new Error(`Missing settlement for SSR promise ${t}.`);if(c.has(t))throw i.get(t);if(l.has(t))throw new Error(`Circular SSR promise ${t}.`);return d.has(t)||(l.add(t),d.set(t,h(i.get(t))),l.delete(t)),d.get(t)}if(!e||"object"!=typeof e||f.has(e))return e;if(f.add(e),e instanceof Map){const t=[...e];e.clear(),t.forEach(([t,r])=>e.set(h(t),h(r)))}else if(e instanceof Set){const t=[...e];e.clear(),t.forEach(t=>e.add(h(t)))}else for(const t of Object.keys(e))Object.defineProperty(e,t,{configurable:!0,enumerable:!0,writable:!0,value:h(Reflect.get(e,t))});return e};return h(n(a[0][1]))};export{a as routerState,o as streamFrames};
|
|
2
|
+
//# sourceMappingURL=parse-response.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse-response.js","sources":["../../src/testing/parse-response.ts"],"sourcesContent":[null],"names":["scripts","html","result","visit","node","tagName","push","childNodes","map","child","value","join","forEach","parse","streamFrames","frames","source","pattern","match","matchAll","frame","JSON","Array","isArray","length","includes","Number","isInteger","Error","Placeholder","id","constructor","this","payload","decode","SSRBPromise","SSRBObject","entries","Object","fromEntries","SSRBError","properties","error","assign","stack","SSRBUndefined","routerState","initial","filter","legacy","settlements","Map","rejected","Set","has","set","add","visited","WeakSet","resolving","resolved","resolve","item","get","delete","clear","key","keys","defineProperty","configurable","enumerable","writable","Reflect"],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Page } from '@playwright/test';
|
|
2
|
+
import type { IBrowserTimelineEvent } from './browser-observer.js';
|
|
3
|
+
interface IHydratedOptions {
|
|
4
|
+
root?: string;
|
|
5
|
+
timeout?: number;
|
|
6
|
+
}
|
|
7
|
+
interface IStreamTimelineCollector {
|
|
8
|
+
read: () => Promise<IBrowserTimelineEvent[]>;
|
|
9
|
+
}
|
|
10
|
+
/** Install before navigation so console failures and the original SSR DOM cannot be missed. */
|
|
11
|
+
declare const collectStreamTimeline: (page: Page) => Promise<IStreamTimelineCollector>;
|
|
12
|
+
/** Wait for router creation, all streamed boundaries and a browser rendering opportunity. */
|
|
13
|
+
declare const expectHydrated: (page: Page, { root, timeout }?: IHydratedOptions) => Promise<void>;
|
|
14
|
+
/** Require an observed shell before this element first became visible. */
|
|
15
|
+
declare const expectStreamed: (page: Page, selector: string) => Promise<void>;
|
|
16
|
+
export { collectStreamTimeline, expectHydrated, expectStreamed };
|
|
17
|
+
export type { IBrowserTimelineEvent, IHydratedOptions, IStreamTimelineCollector };
|