@lomray/vite-ssr-boost 8.0.0-beta.5 → 8.0.0
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 +43 -38
- package/adapters/express/render.d.ts +1 -0
- package/adapters/express/render.js +1 -1
- package/adapters/express/render.js.map +1 -1
- package/core/render.d.ts +1 -0
- package/core/render.js +1 -1
- package/core/render.js.map +1 -1
- package/core/transform-html.d.ts +1 -1
- package/core/transform-html.js +1 -1
- package/core/transform-html.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,60 +1,65 @@
|
|
|
1
1
|
# Vite SSR BOOST
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
<img src="https://raw.githubusercontent.com/Lomray-Software/vite-ssr-boost/prod/logo.png" alt="Vite SSR BOOST logo" width="250" height="250">
|
|
5
|
-
</p>
|
|
3
|
+
SSR for React Router apps in [Data mode](https://reactrouter.com/start/modes), without moving to Framework mode and without rewriting the app. `@lomray/vite-ssr-boost` adds server rendering to your Vite project while keeping your route objects and components. Build SSR and SPA output from the same app, and choose a managed Express server or a Fetch handler for your own transport.
|
|
6
4
|
|
|
7
|
-
|
|
5
|
+
## Who this is for
|
|
8
6
|
|
|
9
|
-
|
|
7
|
+
- Teams adding SSR to a Vite SPA with React Router route objects.
|
|
8
|
+
- Teams that need server rendering and SPA output from one application.
|
|
9
|
+
- Teams that want to control request hooks, response headers and deployment.
|
|
10
10
|
|
|
11
|
-
##
|
|
11
|
+
## What you keep
|
|
12
12
|
|
|
13
|
-
-
|
|
14
|
-
- React Router
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
- response-aware helpers such as redirects and status codes
|
|
19
|
-
- custom entrypoints for mobile, embedded and service-worker-friendly shells
|
|
13
|
+
- Your Vite configuration and plugins, with the SSR plugin added.
|
|
14
|
+
- Your React Router route objects.
|
|
15
|
+
- Your components, after removing browser globals from server execution.
|
|
16
|
+
- Your React version within the package's peer range: React and React DOM `>=18.2.0`.
|
|
17
|
+
- Your hosting choice, provided it can run the selected SSR transport or serve SPA files.
|
|
20
18
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
</p>
|
|
19
|
+
## What you add
|
|
20
|
+
|
|
21
|
+
Add `SsrBoost()` to the Vite plugins, wire `client.ts` and `server.ts`, and replace the Vite scripts with `ssr-boost` commands. The [migration guide](./docs/guide/migrate-existing-spa.md) includes these entries and the HTML outlet, copied from the minimal example.
|
|
22
|
+
|
|
23
|
+
## Choose your server
|
|
24
|
+
|
|
25
|
+
**Managed CLI (default).** Use `ssr-boost dev` for Express with Vite development and HMR, then `ssr-boost build` and `ssr-boost start` for production assets and SSR. The server entry is `@lomray/vite-ssr-boost/adapters/express/entry`, with hooks for requests, rendering and responses.
|
|
26
|
+
|
|
27
|
+
**Fetch handler.** Import `createHandler` from `@lomray/vite-ssr-boost/core/handler` and connect it through `adapters/node`, `adapters/express`, `adapters/fastify`, `adapters/hono` or `adapters/edge`. Your transport owns the development server, static assets and route-asset injection; follow [Runtime adapters](./docs/guide/runtime-adapters.md) when you need this control.
|
|
31
28
|
|
|
32
|
-
##
|
|
29
|
+
## Not a fit when
|
|
30
|
+
|
|
31
|
+
- You need an implementation of React Server Components and Server Actions.
|
|
32
|
+
- You want the package to impose file-system routing conventions.
|
|
33
|
+
- You want zero server ownership for SSR.
|
|
34
|
+
|
|
35
|
+
## Install and template quick start
|
|
33
36
|
|
|
34
37
|
```bash
|
|
35
38
|
npm i @lomray/vite-ssr-boost
|
|
36
39
|
```
|
|
37
40
|
|
|
38
|
-
|
|
39
|
-
Start with the [React template](https://github.com/Lomray-Software/vite-template):
|
|
41
|
+
The package declares `engines.node: ">=22.12.0"`. The example uses Node 22.23.2; React Router and build tools can raise the required Node version.
|
|
40
42
|
|
|
41
|
-
|
|
42
|
-
git clone https://github.com/Lomray-Software/vite-template.git
|
|
43
|
-
cd vite-template
|
|
44
|
-
npm ci
|
|
45
|
-
npm run develop
|
|
46
|
-
```
|
|
43
|
+
Start with the [minimal template](https://github.com/Lomray-Software/vite-template/tree/example/minimal): run `git clone --branch example/minimal https://github.com/Lomray-Software/vite-template.git`, then `cd vite-template`, `npm ci` and `npm run develop`. Its six direct runtime dependencies are React, React DOM, React Router, vite-ssr-boost, `@lomray/react-head-manager` and `isbot`.
|
|
47
44
|
|
|
48
|
-
For production, run `npm run build` and `npm run start:ssr`. For a
|
|
49
|
-
|
|
45
|
+
For production, run `npm run build` and `npm run start:ssr`. For a SPA build, run `npm run build:spa` and `npm run start:spa`. See [Example projects](./docs/examples/index.md) for the `prod` template with state management and deployment workflows.
|
|
46
|
+
|
|
47
|
+
Already running this in production? Point our [free performance audit](https://audit.lomray.com/?utm_source=github&utm_medium=readme-vite-ssr-boost&utm_campaign=owned-surface-github) at the URL. It reports Core Web Vitals, JavaScript bundle weight and whether the HTML really arrives server-rendered. No signup.
|
|
50
48
|
|
|
51
49
|
## Documentation
|
|
52
50
|
|
|
53
|
-
|
|
51
|
+
Read the [documentation site](https://lomray-software.github.io/vite-ssr-boost/), the [comparison guide](./docs/guide/choosing.md) and the [FAQ](./docs/reference/faq.md).
|
|
54
52
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
53
|
+
<p align="center">
|
|
54
|
+
<img src="https://sonarcloud.io/api/project_badges/measure?project=vite-ssr-boost&metric=reliability_rating" alt="reliability">
|
|
55
|
+
<img src="https://sonarcloud.io/api/project_badges/measure?project=vite-ssr-boost&metric=security_rating" alt="Security Rating">
|
|
56
|
+
<img src="https://sonarcloud.io/api/project_badges/measure?project=vite-ssr-boost&metric=sqale_rating" alt="Maintainability Rating">
|
|
57
|
+
<img src="https://sonarcloud.io/api/project_badges/measure?project=vite-ssr-boost&metric=vulnerabilities" alt="Vulnerabilities">
|
|
58
|
+
<img src="https://sonarcloud.io/api/project_badges/measure?project=vite-ssr-boost&metric=bugs" alt="Bugs">
|
|
59
|
+
<img src="https://sonarcloud.io/api/project_badges/measure?project=vite-ssr-boost&metric=ncloc" alt="Lines of Code">
|
|
60
|
+
<img src="https://sonarcloud.io/api/project_badges/measure?project=vite-ssr-boost&metric=coverage" alt="code coverage">
|
|
61
|
+
<img src="https://img.shields.io/npm/v/@lomray/vite-ssr-boost?label=semantic%20release&logo=semantic-release" alt="semantic version">
|
|
62
|
+
</p>
|
|
58
63
|
|
|
59
64
|
## License
|
|
60
65
|
|
|
@@ -45,6 +45,7 @@ export interface IRenderOptions<TAppProps = Record<string, any>> {
|
|
|
45
45
|
onResponse?: (params: {
|
|
46
46
|
context: IRequestContext<TAppProps>;
|
|
47
47
|
html: string;
|
|
48
|
+
isEnd: boolean;
|
|
48
49
|
}) => string | undefined | void;
|
|
49
50
|
getState?: (params: {
|
|
50
51
|
context: IRequestContext<TAppProps>;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import e from"chalk";import r from"react";import t from"./create-request.js";import o from"../../constants/stream-error.js";import s from"../../core/early-hints.js";import{getHeaderEntries as n,getSetCookieHeaders as a}from"../../core/headers.js";import i from"../../core/render.js";import d from"../../node/render-to-stream.js";import c from"../../node/request-signal.js";import m from"../../node/write-early-hints.js";import p,{writeFetchHeaders as l}from"../../node/write-fetch-response.js";import u from"../../services/ssr-manifest.js";const h=(e,r,o)=>{const s={signal:r};return o&&"GET"!==e.method&&"HEAD"!==e.method&&(s.body=o(e)??null),t(e,s)};async function f({App:t,handler:f},x,y,{onRouterReady:g,onShellReady:
|
|
1
|
+
import e from"chalk";import r from"react";import t from"./create-request.js";import o from"../../constants/stream-error.js";import s from"../../core/early-hints.js";import{getHeaderEntries as n,getSetCookieHeaders as a}from"../../core/headers.js";import i from"../../core/render.js";import d from"../../node/render-to-stream.js";import c from"../../node/request-signal.js";import m from"../../node/write-early-hints.js";import p,{writeFetchHeaders as l}from"../../node/write-fetch-response.js";import u from"../../services/ssr-manifest.js";const h=(e,r,o)=>{const s={signal:r};return o&&"GET"!==e.method&&"HEAD"!==e.method&&(s.body=o(e)??null),t(e,s)};async function f({App:t,handler:f},x,y,{onRouterReady:g,onShellReady:E,onResponse:S,onShellError:j,onError:w,getBody:C,getState:v,abortDelay:R=15e3}){const{appProps:b,html:q,req:A,res:H}=y,k=x.getLogger(),D=c(A,H);try{const c=Object.assign(y,{request:h(A,D.signal,C)}),L={appProps:b,html:q,request:c.request,response:{headers:new Headers}},P=e=>(c.request=e.request,c.didError=e.didError,c.html=e.html,c.isStream=e.isStream,c.routerContext=e.routerContext,c.serverContext=e.serverContext,c),T=await i({createApp:(e,o)=>r.createElement(t,{server:{...o.appProps,req:A}},e),handler:f,renderToStream:d},L,{abortDelay:R,getState:v?({context:e})=>v({context:P(e)}):void 0,onError:({context:r,error:t})=>{const{code:s,message:n}=t;if(w?.({context:P(r),error:t}),k.info(e.red(`Stream error. Code: ${s}`)),[o.RenderAborted,o.RenderTimeout,o.RenderCancel].includes(s))return void k.info(e.dim(n));const{original:a}=t;k.error(a)},onResponse:S?({context:e,html:r,isEnd:t})=>S({context:P(e),html:r,isEnd:t}):void 0,onRouterReady:g?({context:e})=>g({context:P(e)}):void 0,onShellError:j?({context:e,error:r})=>j({context:P(e),error:r}):void 0,onShellReady:({context:e})=>{const r=P(e);((e,r)=>{if(r.headersSent||r.writableEnded)return;r.status(e.response.status??200),n(e.response.headers).forEach(([e,t])=>r.setHeader(e,t));const t=a(e.response.headers);t.length&&r.setHeader("Set-Cookie",t)})(e,H);const t=E?.({context:r});return((e,r)=>{const t=new Headers(e.response.headers);t.delete("Set-Cookie");for(const[e,o]of Object.entries(r.getHeaders()))if("set-cookie"!==e.toLowerCase()&&void 0!==o)if(Array.isArray(o))for(const r of o)t.append(e,r);else t.set(e,"number"==typeof o?String(o):o);e.response.headers=t,e.response.status=r.statusCode})(e,H),t??{}},prepare:async({context:e,executionContext:r})=>{const t=P(e),o=u.get(x);await o.prepareDevAssets(e.routerContext?.matches);const n=o.injectAssets(t);t.hasEarlyHints&&await s(r,n)},routerRequestContext:c},{onEarlyHints:e=>m(H,e)});P(L),await(async(e,r)=>{const t=r.headers.get("Location");if(t&&r.status>=300&&r.status<400&&!e.headersSent&&!e.writableEnded&&!e.destroyed)return l(e,r),await(r.body?.cancel()),void e.redirect(r.status,t);await p(e,r)})(H,T)}finally{D.dispose()}}export{f as default};
|
|
2
2
|
//# sourceMappingURL=render.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render.js","sources":["../../../src/adapters/express/render.tsx"],"sourcesContent":[null],"names":["createRenderRequest","req","signal","getBody","options","method","body","createFetchRequest","async","render","App","handler","config","initialContext","onRouterReady","onShellReady","onResponse","onShellError","onError","getState","abortDelay","appProps","html","shellHtml","res","Logger","getLogger","requestSignal","createRequestSignal","context","Object","assign","request","coreContext","response","headers","Headers","syncContext","updated","didError","isStream","routerContext","serverContext","coreRender","createApp","children","React","createElement","server","renderToStream","undefined","error","code","message","info","chalk","red","StreamError","RenderAborted","RenderTimeout","RenderCancel","includes","dim","original","legacyContext","headersSent","writableEnded","status","getHeaderEntries","forEach","name","value","setHeader","cookies","getSetCookieHeaders","length","prepareResponse","shell","delete","entries","getHeaders","toLowerCase","Array","isArray","item","append","set","String","statusCode","syncResponse","prepare","executionContext","manifest","SsrManifest","get","prepareDevAssets","matches","hints","injectAssets","hasEarlyHints","emitEarlyHints","routerRequestContext","onEarlyHints","writeEarlyHints","location","destroyed","writeFetchHeaders","cancel","redirect","writeFetchResponse","writeResponse","dispose"],"mappings":"
|
|
1
|
+
{"version":3,"file":"render.js","sources":["../../../src/adapters/express/render.tsx"],"sourcesContent":[null],"names":["createRenderRequest","req","signal","getBody","options","method","body","createFetchRequest","async","render","App","handler","config","initialContext","onRouterReady","onShellReady","onResponse","onShellError","onError","getState","abortDelay","appProps","html","shellHtml","res","Logger","getLogger","requestSignal","createRequestSignal","context","Object","assign","request","coreContext","response","headers","Headers","syncContext","updated","didError","isStream","routerContext","serverContext","coreRender","createApp","children","React","createElement","server","renderToStream","undefined","error","code","message","info","chalk","red","StreamError","RenderAborted","RenderTimeout","RenderCancel","includes","dim","original","isEnd","legacyContext","headersSent","writableEnded","status","getHeaderEntries","forEach","name","value","setHeader","cookies","getSetCookieHeaders","length","prepareResponse","shell","delete","entries","getHeaders","toLowerCase","Array","isArray","item","append","set","String","statusCode","syncResponse","prepare","executionContext","manifest","SsrManifest","get","prepareDevAssets","matches","hints","injectAssets","hasEarlyHints","emitEarlyHints","routerRequestContext","onEarlyHints","writeEarlyHints","location","destroyed","writeFetchHeaders","cancel","redirect","writeFetchResponse","writeResponse","dispose"],"mappings":"4hBA8EA,MAAMA,EAAsB,CAC1BC,EACAC,EACAC,KAEA,MAAMC,EAA2D,CAAEF,UAMnE,OAJIC,GAA0B,QAAfF,EAAII,QAAmC,SAAfJ,EAAII,SACzCD,EAAQE,KAAOH,EAAQF,IAAQ,MAG1BM,EAAmBN,EAAKG,IA0EjCI,eAAeC,GACbC,IAAEA,EAAGC,QAAEA,GACPC,EACAC,GACAC,cACEA,EAAaC,aACbA,EAAYC,WACZA,EAAUC,aACVA,EAAYC,QACZA,EAAOf,QACPA,EAAOgB,SACPA,EAAQC,WACRA,EAAa,OAGf,MAAMC,SAAEA,EAAUC,KAAMC,EAAStB,IAAEA,EAAGuB,IAAEA,GAAQX,EAC1CY,EAASb,EAAOc,YAChBC,EAAgBC,EAAoB3B,EAAKuB,GAC/C,IACE,MAAMK,EAA2BC,OAAOC,OAAOlB,EAAgB,CAC7DmB,QAAShC,EAAoBC,EAAK0B,EAAczB,OAAQC,KAEpD8B,EAAkC,CACtCZ,WACAC,KAAMC,EACNS,QAASH,EAAQG,QACjBE,SAAU,CACRC,QAAS,IAAIC,UAOXC,EAAeC,IACnBT,EAAQG,QAAUM,EAAQN,QAC1BH,EAAQU,SAAWD,EAAQC,SAC3BV,EAAQP,KAAOgB,EAAQhB,KACvBO,EAAQW,SAAWF,EAAQE,SAC3BX,EAAQY,cAAgBH,EAAQG,cAChCZ,EAAQa,cAAgBJ,EAAQI,cAEzBb,GAEHK,QAAiBS,EACrB,CAIEC,UAAW,CAACC,EAAUP,IACpBQ,EAAAC,cAACrC,EAAG,CAACsC,OAAQ,IAAKV,EAAQjB,SAAUpB,QAAQ4C,GAE9ClC,UACAsC,kBAEFhB,EACA,CACEb,aAKAD,SAAUA,EACN,EAAGU,QAASS,KAAcnB,EAAS,CAAEU,QAASQ,EAAYC,UAC1DY,EAKJhC,QAAS,EAAGW,QAASS,EAASa,YAC5B,MAAMC,KAAEA,EAAIC,QAAEA,GAAYF,EAK1B,GAHAjC,IAAU,CAAEW,QAASQ,EAAYC,GAAUa,UAC3C1B,EAAO6B,KAAKC,EAAMC,IAAI,uBAAuBJ,MAG3C,CACEK,EAAYC,cACZD,EAAYE,cACZF,EAAYG,cACZC,SAAST,GAIX,YAFA3B,EAAO6B,KAAKC,EAAMO,IAAIT,IAKxB,MAAMU,SAAEA,GAAaZ,EAErB1B,EAAO0B,MAAMY,IAMf/C,WAAYA,EACR,EAAGa,QAASS,EAAShB,OAAM0C,WACzBhD,EAAW,CAAEa,QAASQ,EAAYC,GAAUhB,OAAM0C,eACpDd,EAKJpC,cAAeA,EACX,EAAGe,QAASS,KAAcxB,EAAc,CAAEe,QAASQ,EAAYC,UAC/DY,EAKJjC,aAAcA,EACV,EAAGY,QAASS,EAASa,WAAYlC,EAAa,CAAEY,QAASQ,EAAYC,GAAUa,eAC/ED,EAKJnC,aAAc,EAAGc,QAASS,MACxB,MAAM2B,EAAgB5B,EAAYC,GA1LpB,EAACT,EAA6BL,KACpD,GAAIA,EAAI0C,aAAe1C,EAAI2C,cACzB,OAGF3C,EAAI4C,OAAOvC,EAAQK,SAASkC,QAAU,KACtCC,EAAiBxC,EAAQK,SAASC,SAASmC,QAAQ,EAAEC,EAAMC,KAAWhD,EAAIiD,UAAUF,EAAMC,IAE1F,MAAME,EAAUC,EAAoB9C,EAAQK,SAASC,SAEjDuC,EAAQE,QACVpD,EAAIiD,UAAU,aAAcC,IAiLtBG,CAAgBvC,EAASd,GAEzB,MAAMsD,EAAQ/D,IAAe,CAAEc,QAASoC,IAIxC,MAhLW,EAACpC,EAA6BL,KACjD,MAAMW,EAAU,IAAIC,QAAQP,EAAQK,SAASC,SAE7CA,EAAQ4C,OAAO,cAEf,IAAK,MAAOR,EAAMC,KAAU1C,OAAOkD,QAAQxD,EAAIyD,cAC7C,GAA2B,eAAvBV,EAAKW,oBAA4ChC,IAAVsB,EAI3C,GAAIW,MAAMC,QAAQZ,GAChB,IAAK,MAAMa,KAAQb,EACjBrC,EAAQmD,OAAOf,EAAMc,QAGvBlD,EAAQoD,IAAIhB,EAAuB,iBAAVC,EAAqBgB,OAAOhB,GAASA,GAIlE3C,EAAQK,SAASC,QAAUA,EAC3BN,EAAQK,SAASkC,OAAS5C,EAAIiE,YA0JtBC,CAAapD,EAASd,GAEfsD,GAAS,CAAA,GAMlBa,QAASnF,OAASqB,QAASS,EAASsD,uBAClC,MAAM3B,EAAgB5B,EAAYC,GAC5BuD,EAAWC,EAAYC,IAAInF,SAE3BiF,EAASG,iBAAiB1D,EAAQG,eAAewD,SAEvD,MAAMC,EAAQL,EAASM,aAAalC,GAEhCA,EAAcmC,qBACVC,EAAeT,EAAkBM,IAG3CI,qBAAsBzE,GAExB,CAIE0E,aAAepE,GAAYqE,EAAgBhF,EAAKW,KAIpDE,EAAYJ,QAlLMzB,OAAOgB,EAAsBU,KACjD,MAAMuE,EAAWvE,EAASC,QAAQ4D,IAAI,YAEtC,GACEU,GACAvE,EAASkC,QAAU,KACnBlC,EAASkC,OAAS,MACjB5C,EAAI0C,cACJ1C,EAAI2C,gBACJ3C,EAAIkF,UAML,OAJAC,EAAkBnF,EAAKU,SACjBA,EAAS5B,MAAMsG,eACrBpF,EAAIqF,SAAS3E,EAASkC,OAAQqC,SAK1BK,EAAmBtF,EAAKU,IAkKtB6E,CAAcvF,EAAKU,EAC3B,SACEP,EAAcqF,SAChB,CACF"}
|
package/core/render.d.ts
CHANGED
|
@@ -70,6 +70,7 @@ export interface ICoreRenderOptions<TAppProps = Record<string, any>> {
|
|
|
70
70
|
onResponse?: (params: {
|
|
71
71
|
context: ISsrRequestContext<TAppProps>;
|
|
72
72
|
html: string;
|
|
73
|
+
isEnd: boolean;
|
|
73
74
|
}) => string | undefined | void;
|
|
74
75
|
onRouterReady?: (params: {
|
|
75
76
|
context: ISsrRequestContext<TAppProps>;
|
package/core/render.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import e from"react";import{createStaticRouter as t,StaticRouterProvider as r}from"react-router";import o from"../constants/stream-error.js";import{ServerProvider as s}from"../context/server.js";import a from"./compose-html.js";import n from"./head-response.js";import{mergeResponseHeaders as c}from"./headers.js";import d from"./transform-html.js";import l from"../helpers/build-custom-state.js";import u from"../helpers/build-router-state.js";import i from"../helpers/obtain-stream-error.js";const m="text/html",h="Content-Type",p=async({createApp:p,handler:x,renderToStream:f},R,{abortDelay:C=15e3,getState:w,onError:E,onResponse:y,onRouterReady:b,onShellError:q,onShellReady:S,prepare:g,routerRequestContext:v},j)=>{const T=await x.query(R.request,{requestContext:v??R});if(T instanceof Response)return n(R.request,c(T,R.response.headers));R.routerContext=T,await(g?.({context:R,executionContext:j}));const{isStream:A=!0}=await(b?.({context:R}))??{};R.isStream=A,R.serverContext={basename:R.routerContext.basename,isServer:!0,response:null};const H=t(x.dataRoutes,R.routerContext),D=e.createElement(s,{context:R.serverContext},p(e.createElement(r,{router:H,context:R.routerContext,hydrate:!1}),R)),L=new AbortController;let k,B,I=!1;const z=()=>J(R.request.signal.reason),F=()=>clearTimeout(K),G=()=>{F(),R.request.signal.removeEventListener("abort",z)},J=e=>{I||(I=!0,k=e,G(),R.didError??=o.RenderCancel,L.abort(e),B?.abort(e))},K=setTimeout(()=>{R.didError=o.RenderTimeout,J()},C);R.request.signal.aborted?J(R.request.signal.reason):R.request.signal.addEventListener("abort",z,{once:!0});try{B=await f(D,{onError:e=>{const t=i(e);!I||t.code!==o.RenderAborted&&e!==L.signal.reason||(t.code=R.didError===o.RenderTimeout?o.RenderTimeout:o.RenderCancel);const{code:r}=t;R.didError??=r,E?.({context:R,error:t})},signal:L.signal}),I&&B.abort(k),B.allReady.then(F,F),await(A?B.shellReady:B.allReady)}catch(e){return J(e),await(B?.stream.cancel(e).catch(()=>{})),((e,t,r)=>{const o=t instanceof Error?t:new Error(String(t)),s=r?.({context:e,error:o})||"<!doctype html><p>Internal Server Error</p>",a=new Headers(e.response.headers);return a.set(h,m),new Response("HEAD"===e.request.method?null:s,{headers:a,status:500})})(R,e,q)}try{const e=R.serverContext.response;if(e&&(M=e,Boolean(M&&M.status>=300&&M.status<400&&M.headers.has("Location"))))return J(),await B.stream.cancel().catch(()=>{}),n(R.request,c(e,R.response.headers));const{header:t,footer:r,headers:o,status:s}=((e,{getState:t,onShellReady:r})=>{const o=e.serverContext.response;e.response.status=o?.status??e.response.status??e.routerContext.statusCode??200,e.response.headers.has(h)||e.response.headers.set(h,m);const s=r?.({context:e})??{},a=u(e.routerContext),n=l(t?.({context:e}));return{header:s.header||e.html.header,footer:n+a+(s.footer||e.html.footer),headers:new Headers(e.response.headers),status:e.response.status}})(R,{getState:w,onShellReady:S});if("HEAD"===R.request.method||[204,205,304].includes(s))return J(),await B.stream.cancel().catch(()=>{}),new Response(null,{headers:o,status:s});const i=a(t,B.stream,r,J,G),p=d(i,y?e=>y({context:R,html:e}):void 0);return B.start(),new Response(p,{headers:o,status:s})}catch(e){throw J(e),B.stream.locked||await B.stream.cancel(e).catch(()=>{}),e}var M};export{p as default};
|
|
1
|
+
import e from"react";import{createStaticRouter as t,StaticRouterProvider as r}from"react-router";import o from"../constants/stream-error.js";import{ServerProvider as s}from"../context/server.js";import a from"./compose-html.js";import n from"./head-response.js";import{mergeResponseHeaders as c}from"./headers.js";import d from"./transform-html.js";import l from"../helpers/build-custom-state.js";import u from"../helpers/build-router-state.js";import i from"../helpers/obtain-stream-error.js";const m="text/html",h="Content-Type",p=async({createApp:p,handler:x,renderToStream:f},R,{abortDelay:C=15e3,getState:w,onError:E,onResponse:y,onRouterReady:b,onShellError:q,onShellReady:S,prepare:g,routerRequestContext:v},j)=>{const T=await x.query(R.request,{requestContext:v??R});if(T instanceof Response)return n(R.request,c(T,R.response.headers));R.routerContext=T,await(g?.({context:R,executionContext:j}));const{isStream:A=!0}=await(b?.({context:R}))??{};R.isStream=A,R.serverContext={basename:R.routerContext.basename,isServer:!0,response:null};const H=t(x.dataRoutes,R.routerContext),D=e.createElement(s,{context:R.serverContext},p(e.createElement(r,{router:H,context:R.routerContext,hydrate:!1}),R)),L=new AbortController;let k,B,I=!1;const z=()=>J(R.request.signal.reason),F=()=>clearTimeout(K),G=()=>{F(),R.request.signal.removeEventListener("abort",z)},J=e=>{I||(I=!0,k=e,G(),R.didError??=o.RenderCancel,L.abort(e),B?.abort(e))},K=setTimeout(()=>{R.didError=o.RenderTimeout,J()},C);R.request.signal.aborted?J(R.request.signal.reason):R.request.signal.addEventListener("abort",z,{once:!0});try{B=await f(D,{onError:e=>{const t=i(e);!I||t.code!==o.RenderAborted&&e!==L.signal.reason||(t.code=R.didError===o.RenderTimeout?o.RenderTimeout:o.RenderCancel);const{code:r}=t;R.didError??=r,E?.({context:R,error:t})},signal:L.signal}),I&&B.abort(k),B.allReady.then(F,F),await(A?B.shellReady:B.allReady)}catch(e){return J(e),await(B?.stream.cancel(e).catch(()=>{})),((e,t,r)=>{const o=t instanceof Error?t:new Error(String(t)),s=r?.({context:e,error:o})||"<!doctype html><p>Internal Server Error</p>",a=new Headers(e.response.headers);return a.set(h,m),new Response("HEAD"===e.request.method?null:s,{headers:a,status:500})})(R,e,q)}try{const e=R.serverContext.response;if(e&&(M=e,Boolean(M&&M.status>=300&&M.status<400&&M.headers.has("Location"))))return J(),await B.stream.cancel().catch(()=>{}),n(R.request,c(e,R.response.headers));const{header:t,footer:r,headers:o,status:s}=((e,{getState:t,onShellReady:r})=>{const o=e.serverContext.response;e.response.status=o?.status??e.response.status??e.routerContext.statusCode??200,e.response.headers.has(h)||e.response.headers.set(h,m);const s=r?.({context:e})??{},a=u(e.routerContext),n=l(t?.({context:e}));return{header:s.header||e.html.header,footer:n+a+(s.footer||e.html.footer),headers:new Headers(e.response.headers),status:e.response.status}})(R,{getState:w,onShellReady:S});if("HEAD"===R.request.method||[204,205,304].includes(s))return J(),await B.stream.cancel().catch(()=>{}),new Response(null,{headers:o,status:s});const i=a(t,B.stream,r,J,G),p=d(i,y?(e,t)=>y({context:R,html:e,isEnd:t}):void 0);return B.start(),new Response(p,{headers:o,status:s})}catch(e){throw J(e),B.stream.locked||await B.stream.cancel(e).catch(()=>{}),e}var M};export{p as default};
|
|
2
2
|
//# sourceMappingURL=render.js.map
|
package/core/render.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render.js","sources":["../../src/core/render.tsx"],"sourcesContent":[null],"names":["HTML_CONTENT_TYPE","CONTENT_TYPE","render","async","createApp","handler","renderToStream","context","abortDelay","getState","onError","onResponse","onRouterReady","onShellError","onShellReady","prepare","routerRequestContext","executionContext","queried","query","request","requestContext","Response","headResponse","mergeResponseHeaders","response","headers","routerContext","isStream","serverContext","basename","isServer","router","createStaticRouter","dataRoutes","node","React","createElement","ServerProvider","StaticRouterProvider","hydrate","renderController","AbortController","abortReason","output","hasAborted","onRequestAbort","abort","signal","reason","clearAbortTimer","clearTimeout","abortTimer","cleanup","removeEventListener","didError","StreamError","RenderCancel","setTimeout","RenderTimeout","aborted","addEventListener","once","error","streamError","obtainStreamError","code","RenderAborted","allReady","then","shellReady","stream","cancel","catch","shellError","Error","String","html","Headers","set","method","status","createShellErrorResponse","serverResponse","Boolean","has","header","footer","statusCode","shell","routerState","buildRouterState","customState","buildCustomState","prepareHtmlResponse","includes","body","composeHtml","transformed","transformHtml","undefined","start","locked"],"mappings":"
|
|
1
|
+
{"version":3,"file":"render.js","sources":["../../src/core/render.tsx"],"sourcesContent":[null],"names":["HTML_CONTENT_TYPE","CONTENT_TYPE","render","async","createApp","handler","renderToStream","context","abortDelay","getState","onError","onResponse","onRouterReady","onShellError","onShellReady","prepare","routerRequestContext","executionContext","queried","query","request","requestContext","Response","headResponse","mergeResponseHeaders","response","headers","routerContext","isStream","serverContext","basename","isServer","router","createStaticRouter","dataRoutes","node","React","createElement","ServerProvider","StaticRouterProvider","hydrate","renderController","AbortController","abortReason","output","hasAborted","onRequestAbort","abort","signal","reason","clearAbortTimer","clearTimeout","abortTimer","cleanup","removeEventListener","didError","StreamError","RenderCancel","setTimeout","RenderTimeout","aborted","addEventListener","once","error","streamError","obtainStreamError","code","RenderAborted","allReady","then","shellReady","stream","cancel","catch","shellError","Error","String","html","Headers","set","method","status","createShellErrorResponse","serverResponse","Boolean","has","header","footer","statusCode","shell","routerState","buildRouterState","customState","buildCustomState","prepareHtmlResponse","includes","body","composeHtml","transformed","transformHtml","isEnd","undefined","start","locked"],"mappings":"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"}
|
package/core/transform-html.d.ts
CHANGED
package/core/transform-html.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=(e,
|
|
1
|
+
const e=(e,n)=>{if(!n)return e;const r=new TextDecoder,o=new TextEncoder,t=(e,r)=>{e&&r.enqueue(o.encode(n(e,!1)??e))};return e.pipeThrough(new TransformStream({flush:e=>{t(r.decode(),e);const c=n("",!0);c&&e.enqueue(o.encode(c))},transform:(e,n)=>t(r.decode(e,{stream:!0}),n)}))};export{e as default};
|
|
2
2
|
//# sourceMappingURL=transform-html.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transform-html.js","sources":["../../src/core/transform-html.ts"],"sourcesContent":[null],"names":["transformHtml","stream","transform","decoder","TextDecoder","encoder","TextEncoder","apply","html","controller","enqueue","encode","pipeThrough","TransformStream","flush","decode","chunk"],"mappings":"AAKA,MAAMA,EAAgB,CACpBC,EACAC,KAEA,IAAKA,EACH,OAAOD,EAGT,MAAME,EAAU,IAAIC,YACdC,EAAU,IAAIC,YAKdC,EAAQ,CAACC,EAAcC,KACtBD,GAILC,EAAWC,QAAQL,EAAQM,OAAOT,EAAUM,
|
|
1
|
+
{"version":3,"file":"transform-html.js","sources":["../../src/core/transform-html.ts"],"sourcesContent":[null],"names":["transformHtml","stream","transform","decoder","TextDecoder","encoder","TextEncoder","apply","html","controller","enqueue","encode","pipeThrough","TransformStream","flush","decode","chunk"],"mappings":"AAKA,MAAMA,EAAgB,CACpBC,EACAC,KAEA,IAAKA,EACH,OAAOD,EAGT,MAAME,EAAU,IAAIC,YACdC,EAAU,IAAIC,YAKdC,EAAQ,CAACC,EAAcC,KACtBD,GAILC,EAAWC,QAAQL,EAAQM,OAAOT,EAAUM,GAAM,IAAUA,KAG9D,OAAOP,EAAOW,YACZ,IAAIC,gBAAwC,CAI1CC,MAAQL,IACNF,EAAMJ,EAAQY,SAAUN,GAExB,MAAMD,EAAON,EAAU,IAAI,GAEvBM,GACFC,EAAWC,QAAQL,EAAQM,OAAOH,KAOtCN,UAAW,CAACc,EAAOP,IAAeF,EAAMJ,EAAQY,OAAOC,EAAO,CAAEf,QAAQ,IAASQ"}
|