@lomray/vite-ssr-boost 2.0.2 → 2.0.3

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 CHANGED
@@ -30,10 +30,11 @@
30
30
  ## Table of contents
31
31
  - [Getting started](#getting-started)
32
32
  - [How to use](#how-to-use)
33
+ - [Example](#how-to-use)
33
34
  - [Plugin options](#plugin-options)
34
35
  - [Useful imports](#useful-imports)
35
36
  - [CLI](#cli)
36
- - [Example](#demo)
37
+ - [Warning](#warning)
37
38
  - [Bugs and feature requests](#bugs-and-feature-requests)
38
39
  - [License](#license)
39
40
 
@@ -47,6 +48,8 @@ npm i --save @lomray/vite-ssr-boost
47
48
 
48
49
  ## How to use
49
50
 
51
+ Explore [demo app](https://github.com/Lomray-Software/vite-template) to more understand or:
52
+
50
53
  1. Add plugin to vite config:
51
54
  ```typescript
52
55
  /**
@@ -255,9 +258,6 @@ const routes: RouteObject[] = [
255
258
  ];
256
259
  ```
257
260
 
258
- ## Demo
259
- Explore [demo app](https://github.com/Lomray-Software/vite-template) to more understand.
260
-
261
261
  ## Bugs and feature requests
262
262
 
263
263
  Bug or a feature request, [please open a new issue](https://github.com/Lomray-Software/vite-ssr-boost/issues/new).
package/node/render.js CHANGED
@@ -1,2 +1,2 @@
1
- import e from"chalk";import r from"react";import{renderToPipeableStream as t}from"react-dom/server";import{createStaticRouter as o,StaticRouterProvider as n}from"react-router-dom/server.mjs";import s from"../constants/stream-error.js";import{ServerProvider as a}from"../context/server.js";import m from"../helpers/handle-response.js";import i from"../helpers/obtain-stream-error.js";import c from"./create-fetch-request.js";import d from"./write-response.js";import l from"../services/ssr-manifest.js";async function p({App:p,handler:u},f,h,{onRouterReady:x,onShellReady:S,onResponse:R,onShellError:g,onError:y,getState:C,abortDelay:E=15e3}){const{req:j,res:v}=h,w=c(j);h.routerContext=await u.query(w,{requestContext:h});const b=m(v,h.routerContext);if(!b)return;l.get(f).injectAssets(h);const{isStream:q=!0}=await(x?.({context:h}))??{};h.isStream=q,h.serverContext={response:null,isServer:!0};const T=o(u.dataRoutes,h.routerContext),A=v.write.bind(v),$=f.getLogger();let B;v.write=(e,...r)=>{const t="string"==typeof e,o=t?e:Buffer.from(e).toString(),n=R?.({context:h,html:o});return n?A(t?`${n}${e}`:Buffer.concat([Buffer.from(n),e]),...r):A(e,...r)};const{serverContext:k,routerContext:D,appProps:H}=h,{pipe:L,abort:P}=t(r.createElement(a,{context:k},r.createElement(p,{server:{...H,req:j}},r.createElement(n,{router:T,context:D,hydrate:!1}))),{onShellReady(){q&&d(h,{pipe:L,statusCode:b,onShellReady:S,getState:C})},onAllReady(){clearTimeout(B),q||d(h,{pipe:L,statusCode:b,onShellReady:S,getState:C})},onShellError(e){const r=g?.({context:h,error:e})||`<!doctype html><p>Something went wrong: ${e.message}</p>`;v.status(500),v.setHeader("content-type","text/html"),v.send(r)},onError(r){clearTimeout(B);const t=i(r),{code:o,message:n}=t,{didError:a}=h;h.didError=a??o,y?.({context:h,error:t}),$.info(e.red(`Stream error. Code: ${o}`)),[s.RenderAborted,s.RenderTimeout,s.RenderCancel].includes(o)?$.info(e.dim(n)):$.error(r)}});B=setTimeout((()=>{h.didError=s.RenderTimeout,P()}),E),j.on("close",(()=>{h.didError=s.RenderCancel,P()}))}export{p as default};
1
+ import e from"chalk";import r from"react";import{renderToPipeableStream as t}from"react-dom/server";import{createStaticRouter as o,StaticRouterProvider as n}from"react-router-dom/server.mjs";import s from"../constants/stream-error.js";import{ServerProvider as a}from"../context/server.js";import m from"../helpers/handle-response.js";import i from"../helpers/obtain-stream-error.js";import c from"./create-fetch-request.js";import d from"./write-response.js";import l from"../services/ssr-manifest.js";async function p({App:p,handler:u},f,h,{onRouterReady:x,onShellReady:S,onResponse:R,onShellError:g,onError:y,getState:C,abortDelay:E=15e3}){const{req:j,res:v}=h,w=c(j);h.routerContext=await u.query(w,{requestContext:h});const b=m(v,h.routerContext);if(!b)return;l.get(f).injectAssets(h);const{isStream:q=!0}=await(x?.({context:h}))??{};h.isStream=q,h.serverContext={response:null,isServer:!0};const T=o(u.dataRoutes,h.routerContext),A=v.write.bind(v),B=f.getLogger();let $;v.write=(e,...r)=>{const t="string"==typeof e,o=t?e:Buffer.from(e).toString(),n=R?.({context:h,html:o});return n?A(t?n:Buffer.from(n),...r):A(e,...r)};const{serverContext:k,routerContext:D,appProps:H}=h,{pipe:L,abort:P}=t(r.createElement(a,{context:k},r.createElement(p,{server:{...H,req:j}},r.createElement(n,{router:T,context:D,hydrate:!1}))),{onShellReady(){q&&d(h,{pipe:L,statusCode:b,onShellReady:S,getState:C})},onAllReady(){clearTimeout($),q||d(h,{pipe:L,statusCode:b,onShellReady:S,getState:C})},onShellError(e){const r=g?.({context:h,error:e})||`<!doctype html><p>Something went wrong: ${e.message}</p>`;v.status(500),v.setHeader("content-type","text/html"),v.send(r)},onError(r){clearTimeout($);const t=i(r),{code:o,message:n}=t,{didError:a}=h;h.didError=a??o,y?.({context:h,error:t}),B.info(e.red(`Stream error. Code: ${o}`)),[s.RenderAborted,s.RenderTimeout,s.RenderCancel].includes(o)?B.info(e.dim(n)):B.error(r)}});$=setTimeout((()=>{h.didError=s.RenderTimeout,P()}),E),j.on("close",(()=>{h.didError=s.RenderCancel,P()}))}export{p as default};
2
2
  //# sourceMappingURL=render.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"render.js","sources":["../../src/node/render.tsx"],"sourcesContent":["import type { StaticHandler } from '@remix-run/router';\nimport chalk from 'chalk';\nimport type { Request, Response as ExpressResponse } from 'express';\nimport React from 'react';\nimport { renderToPipeableStream } from 'react-dom/server';\nimport type { StaticHandlerContext } from 'react-router-dom/server';\nimport { createStaticRouter, StaticRouterProvider } from 'react-router-dom/server.mjs';\nimport StreamError from '@constants/stream-error';\nimport type { IServerContext } from '@context/server';\nimport { ServerProvider } from '@context/server';\nimport handleResponse from '@helpers/handle-response';\nimport type { IObtainStreamErrorOut } from '@helpers/obtain-stream-error';\nimport obtainStreamError from '@helpers/obtain-stream-error';\nimport createFetchRequest from '@node/create-fetch-request';\nimport type { TApp } from '@node/entry';\nimport writeResponse from '@node/write-response';\nimport type ServerConfig from '@services/server-config';\nimport SsrManifest from '@services/ssr-manifest';\n\nexport interface IRequestContext<TAppProps = Record<any, any>> {\n req: Request;\n res: ExpressResponse;\n appProps: NonNullable<TAppProps>;\n html: { header: string; footer: string };\n routerContext?: StaticHandlerContext;\n serverContext?: IServerContext;\n isStream?: boolean;\n hasEarlyHints?: boolean;\n didError?: StreamError;\n}\n\nexport type TRender<TAppProps = Record<any, any>> = (\n config: ServerConfig,\n context: IRequestContext<TAppProps>,\n options: IRenderOptions,\n) => Promise<void>;\n\nexport interface IRenderParams<TAppProps = Record<string, any>> {\n App: TApp<TAppProps>;\n handler: StaticHandler;\n}\n\nexport interface IRenderOptions<TAppProps = Record<string, any>> {\n abortDelay?: number;\n onRouterReady?: (params: {\n context: IRequestContext<TAppProps>;\n }) => Promise<IRouterReadyOut> | IRouterReadyOut;\n onShellReady?: (params: { context: IRequestContext<TAppProps> }) => IShellReadyOut;\n onShellError?: (params: {\n context: IRequestContext<TAppProps>;\n error: Error;\n }) => string | undefined | void; // return html or undefined\n onError?: (params: { context: IRequestContext<TAppProps>; error: IObtainStreamErrorOut }) => void;\n onResponse?: (params: {\n context: IRequestContext<TAppProps>;\n html: string;\n }) => string | undefined | void;\n getState?: (params: {\n context: IRequestContext<TAppProps>;\n }) => Record<string, Record<string, any>> | undefined | void;\n}\n\nexport interface IRouterReadyOut {\n isStream?: boolean;\n}\n\nexport interface IShellReadyOut {\n header?: string;\n footer?: string;\n}\n\n/**\n * Render application\n */\nasync function render(\n { App, handler }: IRenderParams, // @see entry (bind)\n config: ServerConfig,\n context: IRequestContext,\n {\n onRouterReady,\n onShellReady,\n onResponse,\n onShellError,\n onError,\n getState,\n abortDelay = 15000,\n }: IRenderOptions,\n): Promise<void> {\n const { req, res } = context;\n const fetchRequest = createFetchRequest(req);\n\n context.routerContext = (await handler.query(fetchRequest, {\n requestContext: context,\n })) as StaticHandlerContext;\n\n /**\n * Handle response from page loader, router context can be Response\n */\n const statusCode = handleResponse(res, context.routerContext);\n\n if (!statusCode) {\n return;\n }\n\n SsrManifest.get(config).injectAssets(context);\n\n const { isStream = true } = (await onRouterReady?.({ context })) ?? {};\n\n context.isStream = isStream;\n context.serverContext = { response: null, isServer: true };\n\n const router = createStaticRouter(handler.dataRoutes, context.routerContext);\n const write = res.write.bind(res);\n const Logger = config.getLogger();\n let abortTimer: NodeJS.Timer | undefined = undefined;\n\n /**\n * Listen response and stream to add possibility modify html on fly\n * E.g. listen stream and append some data\n */\n res.write = (data: string | Uint8Array, ...args): boolean => {\n const isString = typeof data === 'string';\n const html = isString ? data : Buffer.from(data).toString();\n const additionalHtml = onResponse?.({ context, html });\n\n if (additionalHtml) {\n return write(\n isString ? `${additionalHtml}${data}` : Buffer.concat([Buffer.from(additionalHtml), data]),\n ...args,\n ) as boolean;\n }\n\n return write(data, ...args) as boolean;\n };\n\n const { serverContext, routerContext, appProps } = context;\n\n const { pipe, abort } = renderToPipeableStream(\n <ServerProvider context={serverContext}>\n <App server={{ ...appProps, req }}>\n <StaticRouterProvider router={router} context={routerContext} hydrate={false} />\n </App>\n </ServerProvider>,\n {\n onShellReady(): void {\n if (!isStream) {\n return;\n }\n\n writeResponse(context, {\n pipe,\n statusCode,\n onShellReady,\n getState,\n });\n },\n onAllReady(): void {\n clearTimeout(abortTimer);\n\n if (isStream) {\n return;\n }\n\n writeResponse(context, {\n pipe,\n statusCode,\n onShellReady,\n getState,\n });\n },\n onShellError(e: Error): void {\n const htmlError =\n onShellError?.({ context, error: e }) ||\n `<!doctype html><p>Something went wrong: ${e.message}</p>`;\n\n res.status(500);\n res.setHeader('content-type', 'text/html');\n res.send(htmlError);\n },\n onError(err): void {\n clearTimeout(abortTimer);\n\n const error = obtainStreamError(err);\n const { code, message } = error;\n const { didError } = context;\n\n context.didError = didError ?? code;\n\n onError?.({ context, error });\n Logger.info(chalk.red(`Stream error. Code: ${code}`));\n\n if (\n [StreamError.RenderAborted, StreamError.RenderTimeout, StreamError.RenderCancel].includes(\n code,\n )\n ) {\n Logger.info(chalk.dim(message));\n\n return;\n }\n\n Logger.error(err as string);\n },\n },\n );\n\n // Abandon and switch to client rendering if enough time passes.\n abortTimer = setTimeout(() => {\n context.didError = StreamError.RenderTimeout;\n abort();\n }, abortDelay);\n\n // Detect cancel request\n req.on('close', () => {\n context.didError = StreamError.RenderCancel;\n abort();\n });\n}\n\nexport default render;\n"],"names":["async","render","App","handler","config","context","onRouterReady","onShellReady","onResponse","onShellError","onError","getState","abortDelay","req","res","fetchRequest","createFetchRequest","routerContext","query","requestContext","statusCode","handleResponse","SsrManifest","get","injectAssets","isStream","serverContext","response","isServer","router","createStaticRouter","dataRoutes","write","bind","Logger","getLogger","abortTimer","data","args","isString","html","Buffer","from","toString","additionalHtml","concat","appProps","pipe","abort","renderToPipeableStream","React","createElement","ServerProvider","server","StaticRouterProvider","hydrate","writeResponse","onAllReady","clearTimeout","e","htmlError","error","message","status","setHeader","send","err","obtainStreamError","code","didError","info","chalk","red","StreamError","RenderAborted","RenderTimeout","RenderCancel","includes","dim","setTimeout","on"],"mappings":"sfA0EAA,eAAeC,GACbC,IAAEA,EAAGC,QAAEA,GACPC,EACAC,GACAC,cACEA,EAAaC,aACbA,EAAYC,WACZA,EAAUC,aACVA,EAAYC,QACZA,EAAOC,SACPA,EAAQC,WACRA,EAAa,OAGf,MAAMC,IAAEA,EAAGC,IAAEA,GAAQT,EACfU,EAAeC,EAAmBH,GAExCR,EAAQY,oBAAuBd,EAAQe,MAAMH,EAAc,CACzDI,eAAgBd,IAMlB,MAAMe,EAAaC,EAAeP,EAAKT,EAAQY,eAE/C,IAAKG,EACH,OAGFE,EAAYC,IAAInB,GAAQoB,aAAanB,GAErC,MAAMoB,SAAEA,GAAW,SAAgBnB,IAAgB,CAAED,cAAe,GAEpEA,EAAQoB,SAAWA,EACnBpB,EAAQqB,cAAgB,CAAEC,SAAU,KAAMC,UAAU,GAEpD,MAAMC,EAASC,EAAmB3B,EAAQ4B,WAAY1B,EAAQY,eACxDe,EAAQlB,EAAIkB,MAAMC,KAAKnB,GACvBoB,EAAS9B,EAAO+B,YACtB,IAAIC,EAMJtB,EAAIkB,MAAQ,CAACK,KAA8BC,KACzC,MAAMC,EAA2B,iBAATF,EAClBG,EAAOD,EAAWF,EAAOI,OAAOC,KAAKL,GAAMM,WAC3CC,EAAiBpC,IAAa,CAAEH,UAASmC,SAE/C,OAAII,EACKZ,EACLO,EAAW,GAAGK,IAAiBP,IAASI,OAAOI,OAAO,CAACJ,OAAOC,KAAKE,GAAiBP,OACjFC,GAIAN,EAAMK,KAASC,EAAgB,EAGxC,MAAMZ,cAAEA,EAAaT,cAAEA,EAAa6B,SAAEA,GAAazC,GAE7C0C,KAAEA,EAAIC,MAAEA,GAAUC,EACtBC,EAACC,cAAAC,EAAe,CAAA/C,QAASqB,GACvBwB,EAACC,cAAAjD,GAAImD,OAAQ,IAAKP,EAAUjC,QAC1BqC,EAAAC,cAACG,EAAqB,CAAAzB,OAAQA,EAAQxB,QAASY,EAAesC,SAAS,MAG3E,CACEhD,eACOkB,GAIL+B,EAAcnD,EAAS,CACrB0C,OACA3B,aACAb,eACAI,YAEH,EACD8C,aACEC,aAAatB,GAETX,GAIJ+B,EAAcnD,EAAS,CACrB0C,OACA3B,aACAb,eACAI,YAEH,EACDF,aAAakD,GACX,MAAMC,EACJnD,IAAe,CAAEJ,UAASwD,MAAOF,KACjC,2CAA2CA,EAAEG,cAE/ChD,EAAIiD,OAAO,KACXjD,EAAIkD,UAAU,eAAgB,aAC9BlD,EAAImD,KAAKL,EACV,EACDlD,QAAQwD,GACNR,aAAatB,GAEb,MAAMyB,EAAQM,EAAkBD,IAC1BE,KAAEA,EAAIN,QAAEA,GAAYD,GACpBQ,SAAEA,GAAahE,EAErBA,EAAQgE,SAAWA,GAAYD,EAE/B1D,IAAU,CAAEL,UAASwD,UACrB3B,EAAOoC,KAAKC,EAAMC,IAAI,uBAAuBJ,MAG3C,CAACK,EAAYC,cAAeD,EAAYE,cAAeF,EAAYG,cAAcC,SAC/ET,GAGFlC,EAAOoC,KAAKC,EAAMO,IAAIhB,IAKxB5B,EAAO2B,MAAMK,EACd,IAKL9B,EAAa2C,YAAW,KACtB1E,EAAQgE,SAAWI,EAAYE,cAC/B3B,GAAO,GACNpC,GAGHC,EAAImE,GAAG,SAAS,KACd3E,EAAQgE,SAAWI,EAAYG,aAC/B5B,GAAO,GAEX"}
1
+ {"version":3,"file":"render.js","sources":["../../src/node/render.tsx"],"sourcesContent":["import type { StaticHandler } from '@remix-run/router';\nimport chalk from 'chalk';\nimport type { Request, Response as ExpressResponse } from 'express';\nimport React from 'react';\nimport { renderToPipeableStream } from 'react-dom/server';\nimport type { StaticHandlerContext } from 'react-router-dom/server';\nimport { createStaticRouter, StaticRouterProvider } from 'react-router-dom/server.mjs';\nimport StreamError from '@constants/stream-error';\nimport type { IServerContext } from '@context/server';\nimport { ServerProvider } from '@context/server';\nimport handleResponse from '@helpers/handle-response';\nimport type { IObtainStreamErrorOut } from '@helpers/obtain-stream-error';\nimport obtainStreamError from '@helpers/obtain-stream-error';\nimport createFetchRequest from '@node/create-fetch-request';\nimport type { TApp } from '@node/entry';\nimport writeResponse from '@node/write-response';\nimport type ServerConfig from '@services/server-config';\nimport SsrManifest from '@services/ssr-manifest';\n\nexport interface IRequestContext<TAppProps = Record<any, any>> {\n req: Request;\n res: ExpressResponse;\n appProps: NonNullable<TAppProps>;\n html: { header: string; footer: string };\n routerContext?: StaticHandlerContext;\n serverContext?: IServerContext;\n isStream?: boolean;\n hasEarlyHints?: boolean;\n didError?: StreamError;\n}\n\nexport type TRender<TAppProps = Record<any, any>> = (\n config: ServerConfig,\n context: IRequestContext<TAppProps>,\n options: IRenderOptions,\n) => Promise<void>;\n\nexport interface IRenderParams<TAppProps = Record<string, any>> {\n App: TApp<TAppProps>;\n handler: StaticHandler;\n}\n\nexport interface IRenderOptions<TAppProps = Record<string, any>> {\n abortDelay?: number;\n onRouterReady?: (params: {\n context: IRequestContext<TAppProps>;\n }) => Promise<IRouterReadyOut> | IRouterReadyOut;\n onShellReady?: (params: { context: IRequestContext<TAppProps> }) => IShellReadyOut;\n onShellError?: (params: {\n context: IRequestContext<TAppProps>;\n error: Error;\n }) => string | undefined | void; // return html or undefined\n onError?: (params: { context: IRequestContext<TAppProps>; error: IObtainStreamErrorOut }) => void;\n onResponse?: (params: {\n context: IRequestContext<TAppProps>;\n html: string;\n }) => string | undefined | void;\n getState?: (params: {\n context: IRequestContext<TAppProps>;\n }) => Record<string, Record<string, any>> | undefined | void;\n}\n\nexport interface IRouterReadyOut {\n isStream?: boolean;\n}\n\nexport interface IShellReadyOut {\n header?: string;\n footer?: string;\n}\n\n/**\n * Render application\n */\nasync function render(\n { App, handler }: IRenderParams, // @see entry (bind)\n config: ServerConfig,\n context: IRequestContext,\n {\n onRouterReady,\n onShellReady,\n onResponse,\n onShellError,\n onError,\n getState,\n abortDelay = 15000,\n }: IRenderOptions,\n): Promise<void> {\n const { req, res } = context;\n const fetchRequest = createFetchRequest(req);\n\n context.routerContext = (await handler.query(fetchRequest, {\n requestContext: context,\n })) as StaticHandlerContext;\n\n /**\n * Handle response from page loader, router context can be Response\n */\n const statusCode = handleResponse(res, context.routerContext);\n\n if (!statusCode) {\n return;\n }\n\n SsrManifest.get(config).injectAssets(context);\n\n const { isStream = true } = (await onRouterReady?.({ context })) ?? {};\n\n context.isStream = isStream;\n context.serverContext = { response: null, isServer: true };\n\n const router = createStaticRouter(handler.dataRoutes, context.routerContext);\n const write = res.write.bind(res);\n const Logger = config.getLogger();\n let abortTimer: NodeJS.Timer | undefined = undefined;\n\n /**\n * Listen response and stream to add possibility modify html on fly\n * E.g. listen stream and append some data\n */\n res.write = (data: string | Uint8Array, ...args): boolean => {\n const isString = typeof data === 'string';\n const html = isString ? data : Buffer.from(data).toString();\n const modifiedHtml = onResponse?.({ context, html });\n\n if (modifiedHtml) {\n return write(isString ? modifiedHtml : Buffer.from(modifiedHtml), ...args) as boolean;\n }\n\n return write(data, ...args) as boolean;\n };\n\n const { serverContext, routerContext, appProps } = context;\n\n const { pipe, abort } = renderToPipeableStream(\n <ServerProvider context={serverContext}>\n <App server={{ ...appProps, req }}>\n <StaticRouterProvider router={router} context={routerContext} hydrate={false} />\n </App>\n </ServerProvider>,\n {\n onShellReady(): void {\n if (!isStream) {\n return;\n }\n\n writeResponse(context, {\n pipe,\n statusCode,\n onShellReady,\n getState,\n });\n },\n onAllReady(): void {\n clearTimeout(abortTimer);\n\n if (isStream) {\n return;\n }\n\n writeResponse(context, {\n pipe,\n statusCode,\n onShellReady,\n getState,\n });\n },\n onShellError(e: Error): void {\n const htmlError =\n onShellError?.({ context, error: e }) ||\n `<!doctype html><p>Something went wrong: ${e.message}</p>`;\n\n res.status(500);\n res.setHeader('content-type', 'text/html');\n res.send(htmlError);\n },\n onError(err): void {\n clearTimeout(abortTimer);\n\n const error = obtainStreamError(err);\n const { code, message } = error;\n const { didError } = context;\n\n context.didError = didError ?? code;\n\n onError?.({ context, error });\n Logger.info(chalk.red(`Stream error. Code: ${code}`));\n\n if (\n [StreamError.RenderAborted, StreamError.RenderTimeout, StreamError.RenderCancel].includes(\n code,\n )\n ) {\n Logger.info(chalk.dim(message));\n\n return;\n }\n\n Logger.error(err as string);\n },\n },\n );\n\n // Abandon and switch to client rendering if enough time passes.\n abortTimer = setTimeout(() => {\n context.didError = StreamError.RenderTimeout;\n abort();\n }, abortDelay);\n\n // Detect cancel request\n req.on('close', () => {\n context.didError = StreamError.RenderCancel;\n abort();\n });\n}\n\nexport default render;\n"],"names":["async","render","App","handler","config","context","onRouterReady","onShellReady","onResponse","onShellError","onError","getState","abortDelay","req","res","fetchRequest","createFetchRequest","routerContext","query","requestContext","statusCode","handleResponse","SsrManifest","get","injectAssets","isStream","serverContext","response","isServer","router","createStaticRouter","dataRoutes","write","bind","Logger","getLogger","abortTimer","data","args","isString","html","Buffer","from","toString","modifiedHtml","appProps","pipe","abort","renderToPipeableStream","React","createElement","ServerProvider","server","StaticRouterProvider","hydrate","writeResponse","onAllReady","clearTimeout","e","htmlError","error","message","status","setHeader","send","err","obtainStreamError","code","didError","info","chalk","red","StreamError","RenderAborted","RenderTimeout","RenderCancel","includes","dim","setTimeout","on"],"mappings":"sfA0EAA,eAAeC,GACbC,IAAEA,EAAGC,QAAEA,GACPC,EACAC,GACAC,cACEA,EAAaC,aACbA,EAAYC,WACZA,EAAUC,aACVA,EAAYC,QACZA,EAAOC,SACPA,EAAQC,WACRA,EAAa,OAGf,MAAMC,IAAEA,EAAGC,IAAEA,GAAQT,EACfU,EAAeC,EAAmBH,GAExCR,EAAQY,oBAAuBd,EAAQe,MAAMH,EAAc,CACzDI,eAAgBd,IAMlB,MAAMe,EAAaC,EAAeP,EAAKT,EAAQY,eAE/C,IAAKG,EACH,OAGFE,EAAYC,IAAInB,GAAQoB,aAAanB,GAErC,MAAMoB,SAAEA,GAAW,SAAgBnB,IAAgB,CAAED,cAAe,GAEpEA,EAAQoB,SAAWA,EACnBpB,EAAQqB,cAAgB,CAAEC,SAAU,KAAMC,UAAU,GAEpD,MAAMC,EAASC,EAAmB3B,EAAQ4B,WAAY1B,EAAQY,eACxDe,EAAQlB,EAAIkB,MAAMC,KAAKnB,GACvBoB,EAAS9B,EAAO+B,YACtB,IAAIC,EAMJtB,EAAIkB,MAAQ,CAACK,KAA8BC,KACzC,MAAMC,EAA2B,iBAATF,EAClBG,EAAOD,EAAWF,EAAOI,OAAOC,KAAKL,GAAMM,WAC3CC,EAAepC,IAAa,CAAEH,UAASmC,SAE7C,OAAII,EACKZ,EAAMO,EAAWK,EAAeH,OAAOC,KAAKE,MAAkBN,GAGhEN,EAAMK,KAASC,EAAgB,EAGxC,MAAMZ,cAAEA,EAAaT,cAAEA,EAAa4B,SAAEA,GAAaxC,GAE7CyC,KAAEA,EAAIC,MAAEA,GAAUC,EACtBC,EAACC,cAAAC,EAAe,CAAA9C,QAASqB,GACvBuB,EAACC,cAAAhD,GAAIkD,OAAQ,IAAKP,EAAUhC,QAC1BoC,EAAAC,cAACG,EAAqB,CAAAxB,OAAQA,EAAQxB,QAASY,EAAeqC,SAAS,MAG3E,CACE/C,eACOkB,GAIL8B,EAAclD,EAAS,CACrByC,OACA1B,aACAb,eACAI,YAEH,EACD6C,aACEC,aAAarB,GAETX,GAIJ8B,EAAclD,EAAS,CACrByC,OACA1B,aACAb,eACAI,YAEH,EACDF,aAAaiD,GACX,MAAMC,EACJlD,IAAe,CAAEJ,UAASuD,MAAOF,KACjC,2CAA2CA,EAAEG,cAE/C/C,EAAIgD,OAAO,KACXhD,EAAIiD,UAAU,eAAgB,aAC9BjD,EAAIkD,KAAKL,EACV,EACDjD,QAAQuD,GACNR,aAAarB,GAEb,MAAMwB,EAAQM,EAAkBD,IAC1BE,KAAEA,EAAIN,QAAEA,GAAYD,GACpBQ,SAAEA,GAAa/D,EAErBA,EAAQ+D,SAAWA,GAAYD,EAE/BzD,IAAU,CAAEL,UAASuD,UACrB1B,EAAOmC,KAAKC,EAAMC,IAAI,uBAAuBJ,MAG3C,CAACK,EAAYC,cAAeD,EAAYE,cAAeF,EAAYG,cAAcC,SAC/ET,GAGFjC,EAAOmC,KAAKC,EAAMO,IAAIhB,IAKxB3B,EAAO0B,MAAMK,EACd,IAKL7B,EAAa0C,YAAW,KACtBzE,EAAQ+D,SAAWI,EAAYE,cAC/B3B,GAAO,GACNnC,GAGHC,EAAIkE,GAAG,SAAS,KACd1E,EAAQ+D,SAAWI,EAAYG,aAC/B5B,GAAO,GAEX"}
@@ -1 +1 @@
1
- {"version":3,"file":"write-response.js","sources":["../../src/node/write-response.ts"],"sourcesContent":["import type { Response as ExpressResponse } from 'express';\nimport type { PipeableStream } from 'react-dom/server';\nimport buildCustomState from '@helpers/build-custom-state';\nimport buildRouterState from '@helpers/build-router-state';\nimport handleResponse from '@helpers/handle-response';\nimport type { IRenderOptions, IRequestContext } from '@node/render';\n\ninterface IWriteResponseParams {\n pipe: PipeableStream['pipe'];\n onShellReady: IRenderOptions['onShellReady'];\n getState: IRenderOptions['getState'];\n statusCode?: number; // default status\n}\n\n/**\n * Send response to client\n */\nconst writeResponse = (context: IRequestContext, params: IWriteResponseParams): void => {\n const { res, didError, serverContext, routerContext, html } = context;\n const { pipe, onShellReady, getState } = params;\n let { statusCode } = params;\n\n // handle response from server components (navigate, status)\n statusCode = handleResponse(res, serverContext!.response, statusCode);\n\n if (!statusCode) {\n return;\n }\n\n // catch close connection from react and write footer\n if (didError) {\n const end = res.end.bind(res);\n\n res.end = (...args: unknown[]): ExpressResponse => {\n // send second part of app shell\n res.write(modifiedFooter || html.footer);\n\n return end(...args) as ExpressResponse;\n };\n }\n\n res.status(statusCode);\n res.setHeader('content-type', 'text/html');\n\n const { header: modifiedHeader, footer: modifiedFooter } = onShellReady?.({ context }) ?? {};\n const routerState = buildRouterState(routerContext!);\n const customState = buildCustomState(getState?.({ context }));\n\n html.footer = routerState + customState + html.footer;\n\n // send first part of app shell\n res.write(modifiedHeader || html.header);\n // start streaming app\n pipe(res);\n\n if (!didError) {\n // send second part of app shell\n res.write(modifiedFooter || html.footer);\n }\n};\n\nexport default writeResponse;\n"],"names":["writeResponse","context","params","res","didError","serverContext","routerContext","html","pipe","onShellReady","getState","statusCode","handleResponse","response","end","bind","args","write","modifiedFooter","footer","status","setHeader","header","modifiedHeader","routerState","buildRouterState","customState","buildCustomState"],"mappings":"6IAiBA,MAAMA,EAAgB,CAACC,EAA0BC,KAC/C,MAAMC,IAAEA,EAAGC,SAAEA,EAAQC,cAAEA,EAAaC,cAAEA,EAAaC,KAAEA,GAASN,GACxDO,KAAEA,EAAIC,aAAEA,EAAYC,SAAEA,GAAaR,EACzC,IAAIS,WAAEA,GAAeT,EAKrB,GAFAS,EAAaC,EAAeT,EAAKE,EAAeQ,SAAUF,IAErDA,EACH,OAIF,GAAIP,EAAU,CACZ,MAAMU,EAAMX,EAAIW,IAAIC,KAAKZ,GAEzBA,EAAIW,IAAM,IAAIE,KAEZb,EAAIc,MAAMC,GAAkBX,EAAKY,QAE1BL,KAAOE,GAEjB,CAEDb,EAAIiB,OAAOT,GACXR,EAAIkB,UAAU,eAAgB,aAE9B,MAAQC,OAAQC,EAAgBJ,OAAQD,GAAmBT,IAAe,CAAER,aAAc,GACpFuB,EAAcC,EAAiBnB,GAC/BoB,EAAcC,EAAiBjB,IAAW,CAAET,aAElDM,EAAKY,OAASK,EAAcE,EAAcnB,EAAKY,OAG/ChB,EAAIc,MAAMM,GAAkBhB,EAAKe,QAEjCd,EAAKL,GAEAC,GAEHD,EAAIc,MAAMC,GAAkBX,EAAKY,OAClC"}
1
+ {"version":3,"file":"write-response.js","sources":["../../src/node/write-response.ts"],"sourcesContent":["import type { Response as ExpressResponse } from 'express';\nimport type { PipeableStream } from 'react-dom/server';\nimport buildCustomState from '@helpers/build-custom-state';\nimport buildRouterState from '@helpers/build-router-state';\nimport handleResponse from '@helpers/handle-response';\nimport type { IRenderOptions, IRequestContext } from '@node/render';\n\ninterface IWriteResponseParams {\n pipe: PipeableStream['pipe'];\n onShellReady: IRenderOptions['onShellReady'];\n getState: IRenderOptions['getState'];\n statusCode?: number; // default status\n}\n\n/**\n * Send response to client\n */\nconst writeResponse = (context: IRequestContext, params: IWriteResponseParams): void => {\n const { res, didError, serverContext, routerContext, html } = context;\n const { pipe, onShellReady, getState } = params;\n let { statusCode } = params;\n\n // handle response from server components (navigate, status)\n statusCode = handleResponse(res, serverContext!.response, statusCode);\n\n if (!statusCode) {\n return;\n }\n\n // catch close connection from React and write footer\n if (didError) {\n const end = res.end.bind(res);\n\n res.end = (...args: unknown[]): ExpressResponse => {\n // send second part of app shell\n res.write(modifiedFooter || html.footer);\n\n return end(...args) as ExpressResponse;\n };\n }\n\n res.status(statusCode);\n res.setHeader('content-type', 'text/html');\n\n const { header: modifiedHeader, footer: modifiedFooter } = onShellReady?.({ context }) ?? {};\n const routerState = buildRouterState(routerContext!);\n const customState = buildCustomState(getState?.({ context }));\n\n html.footer = routerState + customState + html.footer;\n\n // send first part of app shell\n res.write(modifiedHeader || html.header);\n // start streaming app\n pipe(res);\n\n if (!didError) {\n // send second part of app shell\n res.write(modifiedFooter || html.footer);\n }\n};\n\nexport default writeResponse;\n"],"names":["writeResponse","context","params","res","didError","serverContext","routerContext","html","pipe","onShellReady","getState","statusCode","handleResponse","response","end","bind","args","write","modifiedFooter","footer","status","setHeader","header","modifiedHeader","routerState","buildRouterState","customState","buildCustomState"],"mappings":"6IAiBA,MAAMA,EAAgB,CAACC,EAA0BC,KAC/C,MAAMC,IAAEA,EAAGC,SAAEA,EAAQC,cAAEA,EAAaC,cAAEA,EAAaC,KAAEA,GAASN,GACxDO,KAAEA,EAAIC,aAAEA,EAAYC,SAAEA,GAAaR,EACzC,IAAIS,WAAEA,GAAeT,EAKrB,GAFAS,EAAaC,EAAeT,EAAKE,EAAeQ,SAAUF,IAErDA,EACH,OAIF,GAAIP,EAAU,CACZ,MAAMU,EAAMX,EAAIW,IAAIC,KAAKZ,GAEzBA,EAAIW,IAAM,IAAIE,KAEZb,EAAIc,MAAMC,GAAkBX,EAAKY,QAE1BL,KAAOE,GAEjB,CAEDb,EAAIiB,OAAOT,GACXR,EAAIkB,UAAU,eAAgB,aAE9B,MAAQC,OAAQC,EAAgBJ,OAAQD,GAAmBT,IAAe,CAAER,aAAc,GACpFuB,EAAcC,EAAiBnB,GAC/BoB,EAAcC,EAAiBjB,IAAW,CAAET,aAElDM,EAAKY,OAASK,EAAcE,EAAcnB,EAAKY,OAG/ChB,EAAIc,MAAMM,GAAkBhB,EAAKe,QAEjCd,EAAKL,GAEAC,GAEHD,EAAIc,MAAMC,GAAkBX,EAAKY,OAClC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lomray/vite-ssr-boost",
3
- "version": "2.0.2",
3
+ "version": "2.0.3",
4
4
  "description": "Vite plugin for create awesome SSR or SPA applications on React.",
5
5
  "type": "module",
6
6
  "keywords": [
@@ -44,7 +44,7 @@
44
44
  "@commitlint/cli": "^18.4.3",
45
45
  "@commitlint/config-conventional": "^18.4.3",
46
46
  "@lomray/eslint-config": "^4.0.1",
47
- "@lomray/prettier-config": "^1.2.0",
47
+ "@lomray/prettier-config": "^2.0.1",
48
48
  "@rollup/plugin-terser": "^0.4.4",
49
49
  "@types/chai": "^4.3.11",
50
50
  "@types/compression": "^1.7.5",
@@ -54,20 +54,20 @@
54
54
  "@types/react-dom": "^18.2.17",
55
55
  "@types/sinon": "^17.0.2",
56
56
  "@types/sinon-chai": "^3.2.12",
57
- "@typescript-eslint/eslint-plugin": "^6.13.1",
57
+ "@typescript-eslint/eslint-plugin": "^6.14.0",
58
58
  "@zerollup/ts-transform-paths": "^1.7.18",
59
59
  "c8": "^8.0.1",
60
60
  "chai": "^4.3.10",
61
61
  "eslint": "^8.55.0",
62
62
  "eslint-config-prettier": "^9.1.0",
63
- "eslint-plugin-import": "^2.29.0",
63
+ "eslint-plugin-import": "^2.29.1",
64
64
  "eslint-plugin-jsx-a11y": "^6.8.0",
65
65
  "eslint-plugin-prettier": "^5.0.1",
66
66
  "husky": "^8.0.3",
67
67
  "lint-staged": "^15.2.0",
68
68
  "mocha": "^10.2.0",
69
- "prettier": "^3.1.0",
70
- "rollup": "^4.6.1",
69
+ "prettier": "^3.1.1",
70
+ "rollup": "^4.9.0",
71
71
  "rollup-plugin-copy": "^3.5.0",
72
72
  "rollup-plugin-folder-input": "^1.0.1",
73
73
  "rollup-plugin-peer-deps-external": "^2.2.4",
@@ -76,9 +76,9 @@
76
76
  "semantic-release": "^21.1.2",
77
77
  "sinon": "^17.0.1",
78
78
  "sinon-chai": "^3.7.0",
79
- "ts-node": "^10.9.1",
79
+ "ts-node": "^10.9.2",
80
80
  "tsconfig-paths": "^4.2.0",
81
- "typescript": "^5.3.2"
81
+ "typescript": "^5.3.3"
82
82
  },
83
83
  "peerDependencies": {
84
84
  "@types/express": ">=4.17.21",