@lomray/vite-ssr-boost 1.0.0-beta.8 → 1.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.
Files changed (71) hide show
  1. package/README.md +72 -12
  2. package/cli/build.d.ts +7 -5
  3. package/cli/build.js +1 -1
  4. package/cli/build.js.map +1 -1
  5. package/cli/helpers/keyboard-input.js +2 -0
  6. package/cli/helpers/keyboard-input.js.map +1 -0
  7. package/cli/helpers/vite-reset-cache.js.map +1 -0
  8. package/cli/run-docker-build.js +1 -1
  9. package/cli/run-docker-build.js.map +1 -1
  10. package/cli/run-prod.d.ts +2 -1
  11. package/cli/run-prod.js +1 -1
  12. package/cli/run-prod.js.map +1 -1
  13. package/cli.js +1 -1
  14. package/cli.js.map +1 -1
  15. package/components/scroll-to-top.d.ts +10 -0
  16. package/components/scroll-to-top.js +2 -0
  17. package/components/scroll-to-top.js.map +1 -0
  18. package/helpers/get-server-state.d.ts +5 -0
  19. package/helpers/get-server-state.js +2 -0
  20. package/helpers/get-server-state.js.map +1 -0
  21. package/helpers/import-route.d.ts +1 -1
  22. package/helpers/import-route.js +1 -1
  23. package/helpers/import-route.js.map +1 -1
  24. package/helpers/is-route-file.d.ts +5 -0
  25. package/helpers/is-route-file.js +2 -0
  26. package/helpers/is-route-file.js.map +1 -0
  27. package/helpers/process-stop.d.ts +1 -1
  28. package/helpers/process-stop.js +1 -1
  29. package/helpers/process-stop.js.map +1 -1
  30. package/helpers/vite-aliases.js +1 -1
  31. package/helpers/vite-aliases.js.map +1 -1
  32. package/interfaces/fc-route.d.ts +9 -0
  33. package/interfaces/fc-route.js.map +1 -1
  34. package/interfaces/route-object.d.ts +1 -1
  35. package/node/entry.d.ts +6 -1
  36. package/node/entry.js +1 -1
  37. package/node/entry.js.map +1 -1
  38. package/node/render.d.ts +3 -2
  39. package/node/render.js +1 -1
  40. package/node/render.js.map +1 -1
  41. package/node/server.js +1 -1
  42. package/node/server.js.map +1 -1
  43. package/package.json +3 -3
  44. package/plugin.d.ts +1 -2
  45. package/plugin.js +1 -1
  46. package/plugin.js.map +1 -1
  47. package/plugins/normalize-route.d.ts +9 -3
  48. package/plugins/normalize-route.js +1 -1
  49. package/plugins/normalize-route.js.map +1 -1
  50. package/services/build.d.ts +94 -0
  51. package/services/build.js +2 -0
  52. package/services/build.js.map +1 -0
  53. package/services/prepare-server.d.ts +4 -3
  54. package/services/prepare-server.js +1 -1
  55. package/services/prepare-server.js.map +1 -1
  56. package/services/server-config.d.ts +6 -10
  57. package/services/server-config.js +1 -1
  58. package/services/server-config.js.map +1 -1
  59. package/services/ssr-manifest.d.ts +207 -0
  60. package/services/ssr-manifest.js +2 -0
  61. package/services/ssr-manifest.js.map +1 -0
  62. package/workflow/Dockerfile +0 -1
  63. package/cli/keyboard-input.js +0 -2
  64. package/cli/keyboard-input.js.map +0 -1
  65. package/cli/vite-reset-cache.js.map +0 -1
  66. package/helpers/unlock-robots.d.ts +0 -5
  67. package/helpers/unlock-robots.js +0 -2
  68. package/helpers/unlock-robots.js.map +0 -1
  69. /package/cli/{keyboard-input.d.ts → helpers/keyboard-input.d.ts} +0 -0
  70. /package/cli/{vite-reset-cache.d.ts → helpers/vite-reset-cache.d.ts} +0 -0
  71. /package/cli/{vite-reset-cache.js → helpers/vite-reset-cache.js} +0 -0
package/node/render.d.ts CHANGED
@@ -18,6 +18,7 @@ interface IRequestContext<TAppProps = Record<any, any>> {
18
18
  routerContext?: StaticHandlerContext;
19
19
  serverContext?: IServerContext;
20
20
  isStream?: boolean;
21
+ hasEarlyHints?: boolean;
21
22
  didError?: StreamError;
22
23
  }
23
24
  type TRender<TAppProps = Record<any, any>> = (config: ServerConfig, context: IRequestContext<TAppProps>, options: IRenderOptions) => Promise<void>;
@@ -26,7 +27,7 @@ interface IRenderParams<TAppProps = Record<string, any>> {
26
27
  handler: StaticHandler;
27
28
  }
28
29
  interface IRenderOptions<TAppProps = Record<string, any>> {
29
- appProps?: TAppProps;
30
+ abortDelay?: number;
30
31
  onRouterReady?: (params: {
31
32
  context: IRequestContext<TAppProps>;
32
33
  }) => Promise<IRouterReadyOut> | IRouterReadyOut;
@@ -60,5 +61,5 @@ interface IShellReadyOut {
60
61
  * Render application
61
62
  */
62
63
  declare function render({ App, handler }: IRenderParams, // @see entry (bind)
63
- config: ServerConfig, context: IRequestContext, { onRouterReady, onShellReady, onResponse, onShellError, onError, getState }: IRenderOptions): Promise<void>;
64
+ config: ServerConfig, context: IRequestContext, { onRouterReady, onShellReady, onResponse, onShellError, onError, getState, abortDelay, }: IRenderOptions): Promise<void>;
64
65
  export { render as default, IRequestContext, TRender, IRenderParams, IRenderOptions, IRouterReadyOut, IShellReadyOut };
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";async function l({App:l,handler:p},u,f,{onRouterReady:h,onShellReady:x,onResponse:S,onShellError:R,onError:g,getState:y}){const{req:C,res:E}=f,j=c(C);f.routerContext=await p.query(j);const v=m(E,f.routerContext);if(!v)return;const{isStream:w=!0}=await(h?.({context:f}))??{};f.isStream=w,f.serverContext={response:null,isServer:!0};const b=o(p.dataRoutes,f.routerContext),T=E.write.bind(E),q=u.getLogger();let $;E.write=(e,...r)=>{const t="string"==typeof e,o=t?e:Buffer.from(e).toString(),n=S?.({context:f,html:o});return n?T(t?`${n}${e}`:Buffer.concat([Buffer.from(n),e]),...r):T(e,...r)};const{serverContext:A,routerContext:B,appProps:P}=f,{pipe:k,abort:D}=t(r.createElement(a,{context:A},r.createElement(l,{server:{...P,req:C}},r.createElement(n,{router:b,context:B,hydrate:!1}))),{onShellReady(){w&&d(f,{pipe:k,statusCode:v,onShellReady:x,getState:y})},onAllReady(){clearTimeout($),w||d(f,{pipe:k,statusCode:v,onShellReady:x,getState:y})},onShellError(e){const r=R?.({context:f,error:e})||`<!doctype html><p>Something went wrong: ${e.message}</p>`;E.status(500),E.setHeader("content-type","text/html"),E.send(r)},onError(r){clearTimeout($);const t=i(r),{code:o,message:n}=t,{didError:a}=f;f.didError=a??o,g?.({context:f,error:t}),q.info(e.red(`Stream error. Code: ${o}`)),[s.RenderAborted,s.RenderTimeout,s.RenderCancel].includes(o)?q.info(e.dim(n)):q.error(r)}});$=setTimeout((()=>{f.didError=s.RenderTimeout,D()}),u.getParams().abortDelay),C.on("close",(()=>{f.didError=s.RenderCancel,D()}))}export{l 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),$=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};
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';\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 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 appProps?: TAppProps;\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 { onRouterReady, onShellReady, onResponse, onShellError, onError, getState }: IRenderOptions,\n): Promise<void> {\n const { req, res } = context;\n const fetchRequest = createFetchRequest(req);\n\n context.routerContext = (await handler.query(fetchRequest)) as StaticHandlerContext;\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 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 }, config.getParams().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","req","res","fetchRequest","createFetchRequest","routerContext","query","statusCode","handleResponse","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","getParams","abortDelay","on"],"mappings":"2cAwEAA,eAAeC,GACbC,IAAEA,EAAGC,QAAEA,GACPC,EACAC,GACAC,cAAEA,EAAaC,aAAEA,EAAYC,WAAEA,EAAUC,aAAEA,EAAYC,QAAEA,EAAOC,SAAEA,IAElE,MAAMC,IAAEA,EAAGC,IAAEA,GAAQR,EACfS,EAAeC,EAAmBH,GAExCP,EAAQW,oBAAuBb,EAAQc,MAAMH,GAI7C,MAAMI,EAAaC,EAAeN,EAAKR,EAAQW,eAE/C,IAAKE,EACH,OAGF,MAAME,SAAEA,GAAW,SAAgBd,IAAgB,CAAED,cAAe,GAEpEA,EAAQe,SAAWA,EACnBf,EAAQgB,cAAgB,CAAEC,SAAU,KAAMC,UAAU,GAEpD,MAAMC,EAASC,EAAmBtB,EAAQuB,WAAYrB,EAAQW,eACxDW,EAAQd,EAAIc,MAAMC,KAAKf,GACvBgB,EAASzB,EAAO0B,YACtB,IAAIC,EAMJlB,EAAIc,MAAQ,CAACK,KAA8BC,KACzC,MAAMC,EAA2B,iBAATF,EAClBG,EAAOD,EAAWF,EAAOI,OAAOC,KAAKL,GAAMM,WAC3CC,EAAiB/B,IAAa,CAAEH,UAAS8B,SAE/C,OAAII,EACKZ,EACLO,EAAW,GAAGK,IAAiBP,IAASI,OAAOI,OAAO,CAACJ,OAAOC,KAAKE,GAAiBP,OACjFC,GAIAN,EAAMK,KAASC,EAAgB,EAGxC,MAAMZ,cAAEA,EAAaL,cAAEA,EAAayB,SAAEA,GAAapC,GAE7CqC,KAAEA,EAAIC,MAAEA,GAAUC,EACtBC,EAACC,cAAAC,EAAe,CAAA1C,QAASgB,GACvBwB,EAACC,cAAA5C,GAAI8C,OAAQ,IAAKP,EAAU7B,QAC1BiC,EAAAC,cAACG,EAAqB,CAAAzB,OAAQA,EAAQnB,QAASW,EAAekC,SAAS,MAG3E,CACE3C,eACOa,GAIL+B,EAAc9C,EAAS,CACrBqC,OACAxB,aACAX,eACAI,YAEH,EACDyC,aACEC,aAAatB,GAETX,GAIJ+B,EAAc9C,EAAS,CACrBqC,OACAxB,aACAX,eACAI,YAEH,EACDF,aAAa6C,GACX,MAAMC,EACJ9C,IAAe,CAAEJ,UAASmD,MAAOF,KACjC,2CAA2CA,EAAEG,cAE/C5C,EAAI6C,OAAO,KACX7C,EAAI8C,UAAU,eAAgB,aAC9B9C,EAAI+C,KAAKL,EACV,EACD7C,QAAQmD,GACNR,aAAatB,GAEb,MAAMyB,EAAQM,EAAkBD,IAC1BE,KAAEA,EAAIN,QAAEA,GAAYD,GACpBQ,SAAEA,GAAa3D,EAErBA,EAAQ2D,SAAWA,GAAYD,EAE/BrD,IAAU,CAAEL,UAASmD,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,KACtBrE,EAAQ2D,SAAWI,EAAYE,cAC/B3B,GAAO,GACNvC,EAAOuE,YAAYC,YAGtBhE,EAAIiE,GAAG,SAAS,KACdxE,EAAQ2D,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 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"}
package/node/server.js CHANGED
@@ -1,2 +1,2 @@
1
- import e from"path";import r from"compression";import o from"express";import t from"../helpers/print-server-info.js";import s from"../services/prepare-server.js";async function n(n){const i=o();if(n.setApp(i),n.isProd){const{root:t,publicDir:s,isSPA:a}=n.getParams();i.use(r()),a||i.use(((e,r,o)=>{"/index.html"===e.url&&(e.url="/index-not-found.html"),o()})),i.use(o.static(e.resolve(`${t}/${s}`),{index:!!a&&void 0}))}else{const e=await(await import("vite")).createServer({server:{middlewareMode:!0,watch:{usePolling:!0,interval:100}},appType:"custom",mode:n.mode});i.use(e.middlewares),n.setVite(e)}const a=s.init(n);return n.isSPA?i.use("*",((e,r,o)=>{(async()=>{try{const o=(await a.loadHtml(e)).join("");r.send(o)}catch(e){o(e)}})()})):(await a.onAppCreated(),i.use("*",((e,r,o)=>{(async()=>{try{const[{render:o,onRequest:t,onRouterReady:s,onShellReady:i,onResponse:p,onShellError:l,onError:d,getState:m},c]=await Promise.all([a.loadEntrypoint(),a.loadHtml(e)]),{appProps:u}=await(t?.(e,r))??{},[h,f]=c,v={req:e,res:r,appProps:u??{},html:{header:h,footer:f}};await o(n,v,{onRouterReady:s,onShellReady:i,onShellError:l,onResponse:p,onError:d,getState:m})}catch(e){o(e)}})()}))),{run:({version:e,isPrintInfo:r=!0}={})=>{const{port:o,host:s}=n.getParams();n.isHost&&!n.isProd&&(n.getVite().config.server.host=s);const a=i.listen(o,s,(()=>{r&&t(a,n,{version:e})}));return a}}}export{n as default};
1
+ import e from"path";import r from"compression";import t from"express";import s from"../helpers/print-server-info.js";import o from"../services/prepare-server.js";async function i(i){const a=t().disable("x-powered-by");if(i.setApp(a),i.isProd){const{root:s,publicDir:o,isSPA:n}=i.getParams();a.use(r()),n||a.use(((e,r,t)=>{"/index.html"===e.url&&(e.url="/index-not-found.html"),t()})),a.use(t.static(e.resolve(`${s}/${o}`),{index:!!n&&void 0}))}else{const e=await(await import("vite")).createServer({server:{middlewareMode:!0,watch:{usePolling:!0,interval:100}},appType:"custom",mode:i.mode});a.use(e.middlewares),i.setVite(e)}const n=o.init(i);return i.isSPA?a.use("*",((e,r,t)=>{(async()=>{try{const t=(await n.loadHtml(e)).join("");r.send(t)}catch(e){t(e)}})()})):(await n.onAppCreated(),a.use("*",((e,r,t)=>{(async()=>{try{const[{render:t,onRequest:s,...o},a]=await Promise.all([n.loadEntrypoint(),n.loadHtml(e)]),{appProps:p,hasEarlyHints:l}=await(s?.(e,r))??{},[m,c]=a,d={req:e,res:r,hasEarlyHints:l,appProps:p??{},html:{header:m,footer:c}};await t(i,d,o)}catch(e){t(e)}})()}))),{run:({version:e,isPrintInfo:r=!0}={})=>{const{port:t,host:o}=i.getParams();i.isHost&&!i.isProd&&(i.getVite().config.server.host=o);const n=a.listen(t,o,(()=>{r&&s(n,i,{version:e})}));return n}}}export{i as default};
2
2
  //# sourceMappingURL=server.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","sources":["../../src/node/server.ts"],"sourcesContent":["import type { Server } from 'node:net';\nimport path from 'path';\nimport compression from 'compression';\nimport express from 'express';\nimport printServerInfo from '@helpers/print-server-info';\nimport type { IRequestContext } from '@node/render';\nimport PrepareServer from '@services/prepare-server';\nimport type ServerConfig from '@services/server-config';\n\nexport interface ICreateServerOut {\n run: (options?: { version?: string; isPrintInfo?: boolean }) => Server;\n}\n\n/**\n * Create SSR server\n */\nasync function createServer(config: ServerConfig): Promise<ICreateServerOut> {\n const app = express();\n\n config.setApp(app);\n\n if (!config.isProd) {\n // Create Vite server in middleware mode and configure the app type as\n // 'custom', disabling Vite's own HTML serving logic so parent server\n // can take control\n const vite = await (\n await import('vite')\n ).createServer({\n server: {\n middlewareMode: true,\n watch: {\n // During tests, we edit the files too fast and sometimes chokidar\n // misses change events, so enforce polling for consistency\n usePolling: true,\n interval: 100,\n },\n },\n appType: 'custom',\n mode: config.mode,\n });\n\n // Use vite's connect instance as middleware\n app.use(vite.middlewares);\n\n config.setVite(vite);\n } else {\n const { root, publicDir, isSPA } = config.getParams();\n\n app.use(compression());\n\n if (!isSPA) {\n // ignore index.html file in SSR mode\n app.use((req, res, next) => {\n if (req.url === '/index.html') {\n req.url = '/index-not-found.html';\n }\n\n next();\n });\n }\n\n app.use(\n express.static(path.resolve(`${root}/${publicDir}`), {\n index: isSPA ? undefined : false,\n }),\n );\n }\n\n const prepareServer = PrepareServer.init(config);\n\n // SSR mode\n if (!config.isSPA) {\n await prepareServer.onAppCreated();\n\n app.use('*', (req, res, next) => {\n void (async () => {\n try {\n const [\n {\n render,\n onRequest,\n onRouterReady,\n onShellReady,\n onResponse,\n onShellError,\n onError,\n getState,\n },\n clientHtml,\n ] = await Promise.all([prepareServer.loadEntrypoint(), prepareServer.loadHtml(req)]);\n const { appProps } = (await onRequest?.(req, res)) ?? {};\n const [header, footer] = clientHtml;\n\n const context: IRequestContext = {\n req,\n res,\n appProps: appProps ?? {},\n html: { header, footer },\n };\n\n await render(config, context, {\n onRouterReady,\n onShellReady,\n onShellError,\n onResponse,\n onError,\n getState,\n });\n } catch (e) {\n next(e);\n }\n })();\n });\n } else {\n // SPA mode, redirect any request to index.html\n app.use('*', (req, res, next) => {\n void (async () => {\n try {\n const html = (await prepareServer.loadHtml(req)).join('');\n\n res.send(html);\n } catch (e) {\n next(e);\n }\n })();\n });\n }\n\n return {\n run: ({ version, isPrintInfo = true } = {}): Server => {\n const { port, host } = config.getParams();\n\n // update resolved host for print network link\n if (config.isHost && !config.isProd) {\n config.getVite()!.config.server.host = host;\n }\n\n const server = app.listen(port, host, () => {\n if (!isPrintInfo) {\n return;\n }\n\n void printServerInfo(server, config, { version });\n });\n\n return server;\n },\n };\n}\n\nexport default createServer;\n"],"names":["async","createServer","config","app","express","setApp","isProd","root","publicDir","isSPA","getParams","use","compression","req","res","next","url","static","path","resolve","index","undefined","vite","import","server","middlewareMode","watch","usePolling","interval","appType","mode","middlewares","setVite","prepareServer","PrepareServer","init","html","loadHtml","join","send","e","onAppCreated","render","onRequest","onRouterReady","onShellReady","onResponse","onShellError","onError","getState","clientHtml","Promise","all","loadEntrypoint","appProps","header","footer","context","run","version","isPrintInfo","port","host","isHost","getVite","listen","printServerInfo"],"mappings":"kKAgBAA,eAAeC,EAAaC,GAC1B,MAAMC,EAAMC,IAIZ,GAFAF,EAAOG,OAAOF,GAETD,EAAOI,OAwBL,CACL,MAAMC,KAAEA,EAAIC,UAAEA,EAASC,MAAEA,GAAUP,EAAOQ,YAE1CP,EAAIQ,IAAIC,KAEHH,GAEHN,EAAIQ,KAAI,CAACE,EAAKC,EAAKC,KACD,gBAAZF,EAAIG,MACNH,EAAIG,IAAM,yBAGZD,GAAM,IAIVZ,EAAIQ,IACFP,EAAQa,OAAOC,EAAKC,QAAQ,GAAGZ,KAAQC,KAAc,CACnDY,QAAOX,QAAQY,IAGpB,KA7CmB,CAIlB,MAAMC,cACEC,OAAO,SACbtB,aAAa,CACbuB,OAAQ,CACNC,gBAAgB,EAChBC,MAAO,CAGLC,YAAY,EACZC,SAAU,MAGdC,QAAS,SACTC,KAAM5B,EAAO4B,OAIf3B,EAAIQ,IAAIW,EAAKS,aAEb7B,EAAO8B,QAAQV,EAChB,CAuBD,MAAMW,EAAgBC,EAAcC,KAAKjC,GA4DzC,OAzDKA,EAAOO,MA4CVN,EAAIQ,IAAI,KAAK,CAACE,EAAKC,EAAKC,KACjB,WACH,IACE,MAAMqB,SAAcH,EAAcI,SAASxB,IAAMyB,KAAK,IAEtDxB,EAAIyB,KAAKH,EACV,CAAC,MAAOI,GACPzB,EAAKyB,EACN,CACF,EARI,EAQD,WApDAP,EAAcQ,eAEpBtC,EAAIQ,IAAI,KAAK,CAACE,EAAKC,EAAKC,KACjB,WACH,IACE,OACE2B,OACEA,EAAMC,UACNA,EAASC,cACTA,EAAaC,aACbA,EAAYC,WACZA,EAAUC,aACVA,EAAYC,QACZA,EAAOC,SACPA,GAEFC,SACQC,QAAQC,IAAI,CAACnB,EAAcoB,iBAAkBpB,EAAcI,SAASxB,MACxEyC,SAAEA,SAAoBX,IAAY9B,EAAKC,KAAS,IAC/CyC,EAAQC,GAAUN,EAEnBO,EAA2B,CAC/B5C,MACAC,MACAwC,SAAUA,GAAY,CAAE,EACxBlB,KAAM,CAAEmB,SAAQC,iBAGZd,EAAOxC,EAAQuD,EAAS,CAC5Bb,gBACAC,eACAE,eACAD,aACAE,UACAC,YAEH,CAAC,MAAOT,GACPzB,EAAKyB,EACN,CACF,EApCI,EAoCD,KAiBD,CACLkB,IAAK,EAAGC,UAASC,eAAc,GAAS,CAAA,KACtC,MAAMC,KAAEA,EAAIC,KAAEA,GAAS5D,EAAOQ,YAG1BR,EAAO6D,SAAW7D,EAAOI,SAC3BJ,EAAO8D,UAAW9D,OAAOsB,OAAOsC,KAAOA,GAGzC,MAAMtC,EAASrB,EAAI8D,OAAOJ,EAAMC,GAAM,KAC/BF,GAIAM,EAAgB1C,EAAQtB,EAAQ,CAAEyD,WAAU,IAGnD,OAAOnC,CAAM,EAGnB"}
1
+ {"version":3,"file":"server.js","sources":["../../src/node/server.ts"],"sourcesContent":["import type { Server } from 'node:net';\nimport path from 'path';\nimport compression from 'compression';\nimport express from 'express';\nimport printServerInfo from '@helpers/print-server-info';\nimport type { IRequestContext } from '@node/render';\nimport PrepareServer from '@services/prepare-server';\nimport type ServerConfig from '@services/server-config';\n\nexport interface ICreateServerOut {\n run: (options?: { version?: string; isPrintInfo?: boolean }) => Server;\n}\n\n/**\n * Create SSR server\n */\nasync function createServer(config: ServerConfig): Promise<ICreateServerOut> {\n const app = express().disable('x-powered-by');\n\n config.setApp(app);\n\n if (!config.isProd) {\n // Create Vite server in middleware mode and configure the app type as\n // 'custom', disabling Vite's own HTML serving logic so parent server\n // can take control\n const vite = await (\n await import('vite')\n ).createServer({\n server: {\n middlewareMode: true,\n watch: {\n // During tests, we edit the files too fast and sometimes chokidar\n // misses change events, so enforce polling for consistency\n usePolling: true,\n interval: 100,\n },\n },\n appType: 'custom',\n mode: config.mode,\n });\n\n // Use vite's connect instance as middleware\n app.use(vite.middlewares);\n\n config.setVite(vite);\n } else {\n const { root, publicDir, isSPA } = config.getParams();\n\n app.use(compression());\n\n if (!isSPA) {\n // ignore index.html file in SSR mode\n app.use((req, res, next) => {\n if (req.url === '/index.html') {\n req.url = '/index-not-found.html';\n }\n\n next();\n });\n }\n\n app.use(\n express.static(path.resolve(`${root}/${publicDir}`), {\n index: isSPA ? undefined : false,\n }),\n );\n }\n\n const prepareServer = PrepareServer.init(config);\n\n // SSR mode\n if (!config.isSPA) {\n await prepareServer.onAppCreated();\n\n app.use('*', (req, res, next) => {\n void (async () => {\n try {\n const [{ render, onRequest, ...renderParams }, clientHtml] = await Promise.all([\n prepareServer.loadEntrypoint(),\n prepareServer.loadHtml(req),\n ]);\n const { appProps, hasEarlyHints } = (await onRequest?.(req, res)) ?? {};\n const [header, footer] = clientHtml;\n\n const context: IRequestContext = {\n req,\n res,\n hasEarlyHints,\n appProps: appProps ?? {},\n html: { header, footer },\n };\n\n await render(config, context, renderParams);\n } catch (e) {\n next(e);\n }\n })();\n });\n } else {\n // SPA mode, redirect any request to index.html\n app.use('*', (req, res, next) => {\n void (async () => {\n try {\n const html = (await prepareServer.loadHtml(req)).join('');\n\n res.send(html);\n } catch (e) {\n next(e);\n }\n })();\n });\n }\n\n return {\n run: ({ version, isPrintInfo = true } = {}): Server => {\n const { port, host } = config.getParams();\n\n // update resolved host for print network link\n if (config.isHost && !config.isProd) {\n config.getVite()!.config.server.host = host;\n }\n\n const server = app.listen(port, host, () => {\n if (!isPrintInfo) {\n return;\n }\n\n void printServerInfo(server, config, { version });\n });\n\n return server;\n },\n };\n}\n\nexport default createServer;\n"],"names":["async","createServer","config","app","express","disable","setApp","isProd","root","publicDir","isSPA","getParams","use","compression","req","res","next","url","static","path","resolve","index","undefined","vite","import","server","middlewareMode","watch","usePolling","interval","appType","mode","middlewares","setVite","prepareServer","PrepareServer","init","html","loadHtml","join","send","e","onAppCreated","render","onRequest","renderParams","clientHtml","Promise","all","loadEntrypoint","appProps","hasEarlyHints","header","footer","context","run","version","isPrintInfo","port","host","isHost","getVite","listen","printServerInfo"],"mappings":"kKAgBAA,eAAeC,EAAaC,GAC1B,MAAMC,EAAMC,IAAUC,QAAQ,gBAI9B,GAFAH,EAAOI,OAAOH,GAETD,EAAOK,OAwBL,CACL,MAAMC,KAAEA,EAAIC,UAAEA,EAASC,MAAEA,GAAUR,EAAOS,YAE1CR,EAAIS,IAAIC,KAEHH,GAEHP,EAAIS,KAAI,CAACE,EAAKC,EAAKC,KACD,gBAAZF,EAAIG,MACNH,EAAIG,IAAM,yBAGZD,GAAM,IAIVb,EAAIS,IACFR,EAAQc,OAAOC,EAAKC,QAAQ,GAAGZ,KAAQC,KAAc,CACnDY,QAAOX,QAAQY,IAGpB,KA7CmB,CAIlB,MAAMC,cACEC,OAAO,SACbvB,aAAa,CACbwB,OAAQ,CACNC,gBAAgB,EAChBC,MAAO,CAGLC,YAAY,EACZC,SAAU,MAGdC,QAAS,SACTC,KAAM7B,EAAO6B,OAIf5B,EAAIS,IAAIW,EAAKS,aAEb9B,EAAO+B,QAAQV,EAChB,CAuBD,MAAMW,EAAgBC,EAAcC,KAAKlC,GA6CzC,OA1CKA,EAAOQ,MA6BVP,EAAIS,IAAI,KAAK,CAACE,EAAKC,EAAKC,KACjB,WACH,IACE,MAAMqB,SAAcH,EAAcI,SAASxB,IAAMyB,KAAK,IAEtDxB,EAAIyB,KAAKH,EACV,CAAC,MAAOI,GACPzB,EAAKyB,EACN,CACF,EARI,EAQD,WArCAP,EAAcQ,eAEpBvC,EAAIS,IAAI,KAAK,CAACE,EAAKC,EAAKC,KACjB,WACH,IACE,OAAO2B,OAAEA,EAAMC,UAAEA,KAAcC,GAAgBC,SAAoBC,QAAQC,IAAI,CAC7Ed,EAAce,iBACdf,EAAcI,SAASxB,MAEnBoC,SAAEA,EAAQC,cAAEA,SAAyBP,IAAY9B,EAAKC,KAAS,IAC9DqC,EAAQC,GAAUP,EAEnBQ,EAA2B,CAC/BxC,MACAC,MACAoC,gBACAD,SAAUA,GAAY,CAAE,EACxBb,KAAM,CAAEe,SAAQC,iBAGZV,EAAOzC,EAAQoD,EAAST,EAC/B,CAAC,MAAOJ,GACPzB,EAAKyB,EACN,CACF,EArBI,EAqBD,KAiBD,CACLc,IAAK,EAAGC,UAASC,eAAc,GAAS,CAAA,KACtC,MAAMC,KAAEA,EAAIC,KAAEA,GAASzD,EAAOS,YAG1BT,EAAO0D,SAAW1D,EAAOK,SAC3BL,EAAO2D,UAAW3D,OAAOuB,OAAOkC,KAAOA,GAGzC,MAAMlC,EAAStB,EAAI2D,OAAOJ,EAAMC,GAAM,KAC/BF,GAIAM,EAAgBtC,EAAQvB,EAAQ,CAAEsD,WAAU,IAGnD,OAAO/B,CAAM,EAGnB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lomray/vite-ssr-boost",
3
- "version": "1.0.0-beta.8",
3
+ "version": "1.0.0",
4
4
  "description": "Vite plugin for create awesome SSR or SPA applications on React.",
5
5
  "type": "module",
6
6
  "keywords": [
@@ -46,7 +46,6 @@
46
46
  "@lomray/prettier-config": "^1.2.0",
47
47
  "@rollup/plugin-terser": "^0.4.3",
48
48
  "@types/compression": "^1.7.2",
49
- "@types/express": "^4.17.17",
50
49
  "@types/hjson": "^2.4.3",
51
50
  "@types/hoist-non-react-statics": "^3.3.1",
52
51
  "@types/react-dom": "^18.2.5",
@@ -70,9 +69,10 @@
70
69
  "typescript": "^4.9.5"
71
70
  },
72
71
  "peerDependencies": {
72
+ "@types/express": "^4.17.17",
73
73
  "react-dom": ">=18.2.0",
74
74
  "react-router-dom": ">=6.12.1",
75
- "vite": "^4.3.9"
75
+ "vite": "^4.4.6"
76
76
  },
77
77
  "bin": {
78
78
  "ssr-boost": "cli.js"
package/plugin.d.ts CHANGED
@@ -4,8 +4,7 @@ import { IPluginOptions as IMakeAliasesPluginOptions } from "./plugins/make-alia
4
4
  interface IPluginOptions {
5
5
  indexFile?: string;
6
6
  serverFile?: string;
7
- abortDelay?: number;
8
- hasLazyRoutePlugin?: boolean;
7
+ clientFile?: string;
9
8
  tsconfigAliases?: boolean | IMakeAliasesPluginOptions;
10
9
  customShortcuts?: {
11
10
  key: string;
package/plugin.js CHANGED
@@ -1,2 +1,2 @@
1
- import e from"node:path";import i from"./constants/cli-actions.js";import o from"./constants/plugin-name.js";import n from"./plugins/make-aliases.js";import s from"./plugins/normalize-route.js";const t={indexFile:"index.html",serverFile:"server.ts",abortDelay:1e4,hasLazyRoutePlugin:!0,tsconfigAliases:!0};function a(a={}){const r=new URL(import.meta.url),l=global.viteBoostAction,p={...t,...a},m=[{name:o,enforce:"pre",pluginOptions:{...p,pluginPath:e.dirname(r.pathname),action:l,isDev:l===i.dev},config:(e,{ssrBuild:i})=>(e.define={...e.define??{},__IS_SSR__:"1"===process.env.SSR_BOOST_IS_SSR||"dev"===l},i?{...e,publicDir:!1}:e)}],{hasLazyRoutePlugin:u,tsconfigAliases:c}=p;return u&&m.push(s()),c&&m.push(n("boolean"==typeof c?void 0:c)),m}export{a as default};
1
+ import e from"node:path";import i from"./constants/cli-actions.js";import s from"./constants/plugin-name.js";import n from"./plugins/make-aliases.js";import o from"./plugins/normalize-route.js";const t={indexFile:"index.html",serverFile:"server.ts",clientFile:"client.ts",tsconfigAliases:!0};function r(r={}){const l=new URL(import.meta.url),p=global.viteBoostAction||process.env.SSR_BOOST_ACTION,a={...t,...r},m="1"===process.env.SSR_BOOST_IS_SSR||"dev"===p,c=p===i.build,u=[{name:s,enforce:"pre",pluginOptions:{...a,pluginPath:e.dirname(l.pathname),action:p,isDev:p===i.dev},config:(e,{ssrBuild:i})=>(e.define={...e.define??{},__IS_SSR__:m},e.build={...e.build??{}},i?{...e,...c?{appType:"custom"}:{},publicDir:!1}:(m&&c&&(e.build.manifest=!0),e))}],{tsconfigAliases:d}=a;return d&&u.push(n("boolean"==typeof d?void 0:d)),u.push(o({isSSR:m})),u}export{r as default};
2
2
  //# sourceMappingURL=plugin.js.map
package/plugin.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.js","sources":["../src/plugin.ts"],"sourcesContent":["import path from 'node:path';\nimport type { Plugin } from 'vite';\nimport CliActions from '@constants/cli-actions';\nimport type { ICliContext } from '@constants/cli-context';\nimport PLUGIN_NAME from '@constants/plugin-name';\nimport ViteMakeAliasesPlugin from '@plugins/make-aliases';\nimport type { IPluginOptions as IMakeAliasesPluginOptions } from '@plugins/make-aliases';\nimport ViteNormalizeRouterPlugin from '@plugins/normalize-route';\n\nexport interface IPluginOptions {\n indexFile?: string; // default: index.html\n serverFile?: string; // default: server.ts\n abortDelay?: number; // How long the server waits for data before giving up. default: 10000 (10 sec)\n hasLazyRoutePlugin?: boolean; // Possibility to use custom export route component @see FCRoute interface\n tsconfigAliases?: boolean | IMakeAliasesPluginOptions; // Read aliases from tsconfig\n customShortcuts?: {\n key: string;\n description: string;\n action: (cliContext: ICliContext) => Promise<void> | void;\n isOnlyDev?: boolean;\n }[];\n}\n\nconst defaultOptions: IPluginOptions = {\n indexFile: 'index.html',\n serverFile: 'server.ts',\n abortDelay: 10000,\n hasLazyRoutePlugin: true,\n tsconfigAliases: true,\n};\n\n/**\n * Init plugin\n * @constructor\n */\nfunction ViteSsrBoostPlugin(options: IPluginOptions = {}): Plugin[] {\n const dirInfo = new URL(import.meta.url);\n const action = global.viteBoostAction as CliActions;\n const mergedOptions: IPluginOptions = { ...defaultOptions, ...options };\n\n const plugins: Plugin[] = [\n {\n name: PLUGIN_NAME,\n enforce: 'pre',\n // @ts-ignore save custom options\n pluginOptions: {\n ...mergedOptions,\n pluginPath: path.dirname(dirInfo.pathname),\n action,\n isDev: action === CliActions.dev,\n },\n config(config, { ssrBuild }) {\n config.define = {\n ...(config.define ?? {}),\n __IS_SSR__: process.env.SSR_BOOST_IS_SSR === '1' || action === 'dev',\n };\n\n if (!ssrBuild) {\n return config;\n }\n\n return {\n ...config,\n publicDir: false,\n };\n },\n },\n ];\n\n const { hasLazyRoutePlugin, tsconfigAliases } = mergedOptions;\n\n if (hasLazyRoutePlugin) {\n plugins.push(ViteNormalizeRouterPlugin());\n }\n\n if (tsconfigAliases) {\n plugins.push(\n ViteMakeAliasesPlugin(typeof tsconfigAliases === 'boolean' ? undefined : tsconfigAliases),\n );\n }\n\n return plugins;\n}\n\nexport default ViteSsrBoostPlugin;\n"],"names":["defaultOptions","indexFile","serverFile","abortDelay","hasLazyRoutePlugin","tsconfigAliases","ViteSsrBoostPlugin","options","dirInfo","URL","url","action","global","viteBoostAction","mergedOptions","plugins","name","PLUGIN_NAME","enforce","pluginOptions","pluginPath","path","dirname","pathname","isDev","CliActions","dev","config","ssrBuild","define","__IS_SSR__","process","env","SSR_BOOST_IS_SSR","publicDir","push","ViteNormalizeRouterPlugin","ViteMakeAliasesPlugin","undefined"],"mappings":"kMAuBA,MAAMA,EAAiC,CACrCC,UAAW,aACXC,WAAY,YACZC,WAAY,IACZC,oBAAoB,EACpBC,iBAAiB,GAOnB,SAASC,EAAmBC,EAA0B,IACpD,MAAMC,EAAU,IAAIC,gBAAgBC,KAC9BC,EAASC,OAAOC,gBAChBC,EAAgC,IAAKd,KAAmBO,GAExDQ,EAAoB,CACxB,CACEC,KAAMC,EACNC,QAAS,MAETC,cAAe,IACVL,EACHM,WAAYC,EAAKC,QAAQd,EAAQe,UACjCZ,SACAa,MAAOb,IAAWc,EAAWC,KAE/BC,OAAM,CAACA,GAAQC,SAAEA,MACfD,EAAOE,OAAS,IACVF,EAAOE,QAAU,GACrBC,WAA6C,MAAjCC,QAAQC,IAAIC,kBAAuC,QAAXtB,GAGjDiB,EAIE,IACFD,EACHO,WAAW,GALJP,MAWTvB,mBAAEA,EAAkBC,gBAAEA,GAAoBS,EAYhD,OAVIV,GACFW,EAAQoB,KAAKC,KAGX/B,GACFU,EAAQoB,KACNE,EAAiD,kBAApBhC,OAAgCiC,EAAYjC,IAItEU,CACT"}
1
+ {"version":3,"file":"plugin.js","sources":["../src/plugin.ts"],"sourcesContent":["import path from 'node:path';\nimport type { Plugin } from 'vite';\nimport CliActions from '@constants/cli-actions';\nimport type { ICliContext } from '@constants/cli-context';\nimport PLUGIN_NAME from '@constants/plugin-name';\nimport type { IPluginOptions as IMakeAliasesPluginOptions } from '@plugins/make-aliases';\nimport ViteMakeAliasesPlugin from '@plugins/make-aliases';\nimport ViteNormalizeRouterPlugin from '@plugins/normalize-route';\n\nexport interface IPluginOptions {\n indexFile?: string; // default: index.html\n serverFile?: string; // default: server.ts\n clientFile?: string; // default: client.ts\n tsconfigAliases?: boolean | IMakeAliasesPluginOptions; // Read aliases from tsconfig\n customShortcuts?: {\n key: string;\n description: string;\n action: (cliContext: ICliContext) => Promise<void> | void;\n isOnlyDev?: boolean;\n }[];\n}\n\nconst defaultOptions: IPluginOptions = {\n indexFile: 'index.html',\n serverFile: 'server.ts',\n clientFile: 'client.ts',\n tsconfigAliases: true,\n};\n\n/**\n * Init plugin\n * @constructor\n */\nfunction ViteSsrBoostPlugin(options: IPluginOptions = {}): Plugin[] {\n const dirInfo = new URL(import.meta.url);\n const action = (global.viteBoostAction || process.env.SSR_BOOST_ACTION) as CliActions;\n const mergedOptions: IPluginOptions = { ...defaultOptions, ...options };\n const isSSR = process.env.SSR_BOOST_IS_SSR === '1' || action === 'dev';\n const isBuild = action === CliActions.build;\n\n const plugins: Plugin[] = [\n {\n name: PLUGIN_NAME,\n enforce: 'pre',\n // @ts-ignore save custom options\n pluginOptions: {\n ...mergedOptions,\n pluginPath: path.dirname(dirInfo.pathname),\n action,\n isDev: action === CliActions.dev,\n },\n\n config(config, { ssrBuild }) {\n config.define = {\n ...(config.define ?? {}),\n __IS_SSR__: isSSR,\n };\n\n config.build = {\n ...(config.build ?? {}),\n // modulePreload: config.build?.modulePreload ?? false,\n };\n\n if (!ssrBuild) {\n if (isSSR && isBuild) {\n config.build!.manifest = true;\n }\n\n return config;\n }\n\n return {\n ...config,\n ...(isBuild ? { appType: 'custom' } : {}),\n publicDir: false,\n };\n },\n },\n ];\n\n const { tsconfigAliases } = mergedOptions;\n\n if (tsconfigAliases) {\n plugins.push(\n ViteMakeAliasesPlugin(typeof tsconfigAliases === 'boolean' ? undefined : tsconfigAliases),\n );\n }\n\n plugins.push(ViteNormalizeRouterPlugin({ isSSR }));\n\n return plugins;\n}\n\nexport default ViteSsrBoostPlugin;\n"],"names":["defaultOptions","indexFile","serverFile","clientFile","tsconfigAliases","ViteSsrBoostPlugin","options","dirInfo","URL","url","action","global","viteBoostAction","process","env","SSR_BOOST_ACTION","mergedOptions","isSSR","SSR_BOOST_IS_SSR","isBuild","CliActions","build","plugins","name","PLUGIN_NAME","enforce","pluginOptions","pluginPath","path","dirname","pathname","isDev","dev","config","ssrBuild","define","__IS_SSR__","appType","publicDir","manifest","push","ViteMakeAliasesPlugin","undefined","ViteNormalizeRouterPlugin"],"mappings":"kMAsBA,MAAMA,EAAiC,CACrCC,UAAW,aACXC,WAAY,YACZC,WAAY,YACZC,iBAAiB,GAOnB,SAASC,EAAmBC,EAA0B,IACpD,MAAMC,EAAU,IAAIC,gBAAgBC,KAC9BC,EAAUC,OAAOC,iBAAmBC,QAAQC,IAAIC,iBAChDC,EAAgC,IAAKhB,KAAmBM,GACxDW,EAAyC,MAAjCJ,QAAQC,IAAII,kBAAuC,QAAXR,EAChDS,EAAUT,IAAWU,EAAWC,MAEhCC,EAAoB,CACxB,CACEC,KAAMC,EACNC,QAAS,MAETC,cAAe,IACVV,EACHW,WAAYC,EAAKC,QAAQtB,EAAQuB,UACjCpB,SACAqB,MAAOrB,IAAWU,EAAWY,KAG/BC,OAAM,CAACA,GAAQC,SAAEA,MACfD,EAAOE,OAAS,IACVF,EAAOE,QAAU,GACrBC,WAAYnB,GAGdgB,EAAOZ,MAAQ,IACTY,EAAOZ,OAAS,IAIjBa,EAQE,IACFD,KACCd,EAAU,CAAEkB,QAAS,UAAa,CAAA,EACtCC,WAAW,IAVPrB,GAASE,IACXc,EAAOZ,MAAOkB,UAAW,GAGpBN,OAYT7B,gBAAEA,GAAoBY,EAU5B,OARIZ,GACFkB,EAAQkB,KACNC,EAAiD,kBAApBrC,OAAgCsC,EAAYtC,IAI7EkB,EAAQkB,KAAKG,EAA0B,CAAE1B,WAElCK,CACT"}
@@ -1,10 +1,16 @@
1
1
  import { Plugin } from 'vite';
2
+ interface IPluginOptions {
3
+ isSSR?: boolean;
4
+ }
2
5
  /**
3
6
  * Add possibility to export route components like FCRoute or FCCRoute
4
- * USAGE: { path: '/', lazyNR: () => import('./pages/home') }
7
+ * Add route path for generating manifest
8
+ * USAGE: { path: '/', lazy: () => import('./pages/home') }
5
9
  * @see FCRoute
6
10
  * @see FCCRoute
11
+ * @see SsrManifest.getRoutesIds
12
+ * @see importRoute
7
13
  * @constructor
8
14
  */
9
- declare function ViteNormalizeRouterPlugin(): Plugin;
10
- export { ViteNormalizeRouterPlugin as default };
15
+ declare function ViteNormalizeRouterPlugin(options?: IPluginOptions): Plugin;
16
+ export { ViteNormalizeRouterPlugin as default, IPluginOptions };
@@ -1,2 +1,2 @@
1
- import{extname as t}from"node:path";import o from"../constants/plugin-name.js";const s=t=>`import n from '${o}/helpers/import-route';${t}`.replace(/(lazyNR)(:\s*)(\(\)\s*=>\s*import\([^)]+\))/gs,"lazy$2()=>n($3)");function r(){return{name:`${o}-normalize-route`,transform:(o,r)=>{const e=t(r).split("?")[0];if(!r.includes("node_modules")&&[".js",".ts",".tsx"].includes(e)&&(t=>/\[.*{.*path:.*lazyNR:.+import/s.test(t))(o))return{code:s(o),map:{mappings:""}}}}}export{r as default};
1
+ import{extname as o}from"node:path";import s from"../constants/plugin-name.js";import r from"../helpers/is-route-file.js";const t=(o,r)=>`import n from '${s}/helpers/import-route';${o}`.replace(/(lazy)(:\s*)(\(\)\s*=>\s*import\(([^)]+)\))/gs,r?"lazy$2()=>n($3,$4)":"lazy$2()=>n($3)");function e(e={}){const{isSSR:n=!1}=e;return{name:`${s}-normalize-route`,transform:(s,e)=>{const i=o(e).split("?")[0];if(!e.includes("node_modules")&&[".js",".ts",".tsx"].includes(i)&&r(s))return{code:t(s,n),map:{mappings:""}}}}}export{e as default};
2
2
  //# sourceMappingURL=normalize-route.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"normalize-route.js","sources":["../../src/plugins/normalize-route.ts"],"sourcesContent":["import { extname } from 'node:path';\nimport type { Plugin } from 'vite';\nimport PLUGIN_NAME from '@constants/plugin-name';\n\n/**\n * Detect route file\n */\nconst isRoutesFile = (code: string): boolean => /\\[.*{.*path:.*lazyNR:.+import/s.test(code);\n\n/**\n * Add normalize wrapper to lazy imports\n */\nconst normalizeRoutes = (code: string): string =>\n `import n from '${PLUGIN_NAME}/helpers/import-route';${code}`.replace(\n /(lazyNR)(:\\s*)(\\(\\)\\s*=>\\s*import\\([^)]+\\))/gs,\n 'lazy$2()=>n($3)',\n );\n\n/**\n * Add possibility to export route components like FCRoute or FCCRoute\n * USAGE: { path: '/', lazyNR: () => import('./pages/home') }\n * @see FCRoute\n * @see FCCRoute\n * @constructor\n */\nfunction ViteNormalizeRouterPlugin(): Plugin {\n return {\n name: `${PLUGIN_NAME}-normalize-route`,\n transform: (code, id) => {\n const extName = extname(id).split('?')[0]!;\n\n if (\n id.includes('node_modules') ||\n !['.js', '.ts', '.tsx'].includes(extName) ||\n !isRoutesFile(code)\n ) {\n return;\n }\n\n return {\n code: normalizeRoutes(code),\n map: { mappings: '' },\n };\n },\n };\n}\n\nexport default ViteNormalizeRouterPlugin;\n"],"names":["normalizeRoutes","code","PLUGIN_NAME","replace","ViteNormalizeRouterPlugin","name","transform","id","extName","extname","split","includes","test","isRoutesFile","map","mappings"],"mappings":"+EAOA,MAKMA,EAAmBC,GACvB,kBAAkBC,2BAAqCD,IAAOE,QAC5D,gDACA,mBAUJ,SAASC,IACP,MAAO,CACLC,KAAM,GAAGH,oBACTI,UAAW,CAACL,EAAMM,KAChB,MAAMC,EAAUC,EAAQF,GAAIG,MAAM,KAAK,GAEvC,IACEH,EAAGI,SAAS,iBACX,CAAC,MAAO,MAAO,QAAQA,SAASH,IA1BpB,CAACP,GAA0B,iCAAiCW,KAAKX,GA2B7EY,CAAaZ,GAKhB,MAAO,CACLA,KAAMD,EAAgBC,GACtBa,IAAK,CAAEC,SAAU,IAClB,EAGP"}
1
+ {"version":3,"file":"normalize-route.js","sources":["../../src/plugins/normalize-route.ts"],"sourcesContent":["import { extname } from 'node:path';\nimport type { Plugin } from 'vite';\nimport PLUGIN_NAME from '@constants/plugin-name';\nimport isRoutesFile from '@helpers/is-route-file';\n\nexport interface IPluginOptions {\n isSSR?: boolean;\n}\n\n/**\n * Add normalize wrapper to lazy imports for client build\n */\nconst normalizeRoutes = (code: string, isSSR: boolean): string =>\n `import n from '${PLUGIN_NAME}/helpers/import-route';${code}`.replace(\n /(lazy)(:\\s*)(\\(\\)\\s*=>\\s*import\\(([^)]+)\\))/gs,\n isSSR ? 'lazy$2()=>n($3,$4)' : 'lazy$2()=>n($3)',\n );\n\n/**\n * Add possibility to export route components like FCRoute or FCCRoute\n * Add route path for generating manifest\n * USAGE: { path: '/', lazy: () => import('./pages/home') }\n * @see FCRoute\n * @see FCCRoute\n * @see SsrManifest.getRoutesIds\n * @see importRoute\n * @constructor\n */\nfunction ViteNormalizeRouterPlugin(options: IPluginOptions = {}): Plugin {\n const { isSSR = false } = options;\n\n return {\n name: `${PLUGIN_NAME}-normalize-route`,\n transform: (code, id) => {\n const extName = extname(id).split('?')[0]!;\n\n if (\n id.includes('node_modules') ||\n !['.js', '.ts', '.tsx'].includes(extName) ||\n !isRoutesFile(code)\n ) {\n return;\n }\n\n return {\n code: normalizeRoutes(code, isSSR),\n map: { mappings: '' },\n };\n },\n };\n}\n\nexport default ViteNormalizeRouterPlugin;\n"],"names":["normalizeRoutes","code","isSSR","PLUGIN_NAME","replace","ViteNormalizeRouterPlugin","options","name","transform","id","extName","extname","split","includes","isRoutesFile","map","mappings"],"mappings":"0HAYA,MAAMA,EAAkB,CAACC,EAAcC,IACrC,kBAAkBC,2BAAqCF,IAAOG,QAC5D,gDACAF,EAAQ,qBAAuB,mBAanC,SAASG,EAA0BC,EAA0B,IAC3D,MAAMJ,MAAEA,GAAQ,GAAUI,EAE1B,MAAO,CACLC,KAAM,GAAGJ,oBACTK,UAAW,CAACP,EAAMQ,KAChB,MAAMC,EAAUC,EAAQF,GAAIG,MAAM,KAAK,GAEvC,IACEH,EAAGI,SAAS,iBACX,CAAC,MAAO,MAAO,QAAQA,SAASH,IAChCI,EAAab,GAKhB,MAAO,CACLA,KAAMD,EAAgBC,EAAMC,GAC5Ba,IAAK,CAAEC,SAAU,IAClB,EAGP"}
@@ -0,0 +1,94 @@
1
+ /// <reference types="node" />
2
+ import childProcess from 'node:child_process';
3
+ import { ResolvedConfig } from 'vite';
4
+ import { IPluginConfig } from "../helpers/plugin-config.js";
5
+ interface IBuildParams {
6
+ mode: string;
7
+ }
8
+ /**
9
+ * Build service
10
+ */
11
+ declare class Build {
12
+ /**
13
+ * Is production build
14
+ */
15
+ isProd: boolean;
16
+ /**
17
+ * Node environment
18
+ */
19
+ nodeEnv: string;
20
+ /**
21
+ * Build folder
22
+ */
23
+ buildDir: string;
24
+ /**
25
+ * Relative build dir
26
+ */
27
+ outDir: string;
28
+ /**
29
+ * Server file
30
+ */
31
+ serverFile: string;
32
+ /**
33
+ * Vite config
34
+ */
35
+ viteConfig: ResolvedConfig;
36
+ /**
37
+ * Plugin config
38
+ */
39
+ pluginConfig: IPluginConfig;
40
+ /**
41
+ * Build params
42
+ */
43
+ protected params: IBuildParams;
44
+ /**
45
+ * @constructor
46
+ */
47
+ /**
48
+ * @constructor
49
+ */
50
+ constructor(params: IBuildParams);
51
+ /**
52
+ * Make config
53
+ */
54
+ /**
55
+ * Make config
56
+ */
57
+ makeConfig(): Promise<void>;
58
+ /**
59
+ * Clear build folder
60
+ */
61
+ /**
62
+ * Clear build folder
63
+ */
64
+ clearBuildFolder(): void;
65
+ /**
66
+ * Promisify spawn process
67
+ */
68
+ /**
69
+ * Promisify spawn process
70
+ */
71
+ promisifyProcess(command: childProcess.ChildProcess, isRejectWarnings?: boolean): Promise<unknown>;
72
+ /**
73
+ * Build assets manifest file
74
+ */
75
+ /**
76
+ * Build assets manifest file
77
+ */
78
+ buildManifest(): Promise<void>;
79
+ /**
80
+ * Change general directive Disallow to Allow in robots.txt.
81
+ */
82
+ /**
83
+ * Change general directive Disallow to Allow in robots.txt.
84
+ */
85
+ unlockRobots(): void;
86
+ /**
87
+ * Eject cli to run app via node
88
+ */
89
+ /**
90
+ * Eject cli to run app via node
91
+ */
92
+ eject(): void;
93
+ }
94
+ export { Build as default };
@@ -0,0 +1,2 @@
1
+ import i from"node:fs";import o from"node:path";import t from"chalk";import{resolveConfig as s}from"vite";import e from"../helpers/plugin-config.js";import n from"./server-config.js";import r from"./ssr-manifest.js";class l{isProd;nodeEnv;buildDir;outDir;serverFile;viteConfig;pluginConfig;params;constructor(i){this.params=i}async makeConfig(){const{mode:i}=this.params;this.viteConfig=await s({},"build",i,"production"===i?"production":"development"),this.pluginConfig=e(this.viteConfig),this.buildDir=o.resolve(this.viteConfig.root,this.viteConfig.build.outDir),this.outDir=this.viteConfig.build.outDir,this.serverFile=this.pluginConfig.serverFile,this.nodeEnv=process.env.NODE_ENV||"development",this.isProd="production"===this.nodeEnv}clearBuildFolder(){i.existsSync(this.buildDir)&&i.rmSync(this.buildDir,{recursive:!0})}promisifyProcess(i,o=!1){const t=new Promise(((t,s)=>{i.on("exit",(i=>{t(i)})),i.on("close",(i=>{t(i)})),i.on("error",(i=>{s(i)})),o&&i.stderr?.on("data",(i=>{const o=Buffer.from(i).toString();(o.includes("warning")||o.includes("WARNING"))&&t(1)}))}));return i.stdout?.pipe(process.stdout),i.stderr?.pipe(process.stderr),t.command=i,t}async buildManifest(){console.log(t.blue("Building routes manifest file..."));const i=n.init({isProd:this.isProd,mode:this.params.mode},{root:this.viteConfig.root});await r.get(i,{buildDir:this.viteConfig.build.outDir,viteAliases:this.viteConfig.resolve.alias}).buildRoutesManifest()}unlockRobots(){const o=`${this.buildDir}/client/robots.txt`;if(!i.existsSync(o))return void console.warn(`Failed to unlock robots.txt, file not exist: ${o}`);const s=i.readFileSync(o,{encoding:"utf-8"}).replace(/Disallow: \/$/m,"Allow: /");i.writeFileSync(o,s,{encoding:"utf-8"}),console.info(t.blue("\nrobots.txt unlocked."))}eject(){const o=`${this.buildDir}/server/start.js`;i.writeFileSync(o,"import runProd from '@lomray/vite-ssr-boost/cli/run-prod.js';\n\nconst VERSION = process.env.VERSION || \"1.0.0\";\nconst PORT = process.env.PORT || 3000;\nconst IS_HOST = process.env.IS_HOST || \"0\";\nconst ONLY_CLIENT = process.env.ONLY_CLIENT || \"0\";\n\nawait runProd({\n version: VERSION,\n isHost: IS_HOST === '1',\n isPrintInfo: true,\n port: PORT,\n onlyClient: ONLY_CLIENT === '1',\n });\n",{encoding:"utf-8"})}}export{l as default};
2
+ //# sourceMappingURL=build.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build.js","sources":["../../src/services/build.ts"],"sourcesContent":["import type childProcess from 'node:child_process';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport chalk from 'chalk';\nimport type { ResolvedConfig } from 'vite';\nimport { resolveConfig } from 'vite';\nimport type { IPluginConfig } from '@helpers/plugin-config';\nimport getPluginConfig from '@helpers/plugin-config';\nimport ServerConfig from '@services/server-config';\nimport SsrManifest from '@services/ssr-manifest';\n\ninterface IBuildParams {\n mode: string;\n}\n\n/**\n * Build service\n */\nclass Build {\n /**\n * Is production build\n */\n public isProd: boolean;\n\n /**\n * Node environment\n */\n public nodeEnv: string;\n\n /**\n * Build folder\n */\n public buildDir: string;\n\n /**\n * Relative build dir\n */\n public outDir: string;\n\n /**\n * Server file\n */\n public serverFile: string;\n\n /**\n * Vite config\n */\n public viteConfig: ResolvedConfig;\n\n /**\n * Plugin config\n */\n public pluginConfig: IPluginConfig;\n\n /**\n * Build params\n */\n protected params: IBuildParams;\n\n /**\n * @constructor\n */\n constructor(params: IBuildParams) {\n this.params = params;\n }\n\n /**\n * Make config\n */\n public async makeConfig(): Promise<void> {\n const { mode } = this.params;\n\n this.viteConfig = await resolveConfig(\n {},\n 'build',\n mode,\n mode === 'production' ? 'production' : 'development',\n );\n this.pluginConfig = getPluginConfig(this.viteConfig);\n this.buildDir = path.resolve(this.viteConfig.root, this.viteConfig.build.outDir);\n this.outDir = this.viteConfig.build.outDir;\n this.serverFile = this.pluginConfig.serverFile;\n this.nodeEnv = process.env.NODE_ENV || 'development';\n this.isProd = this.nodeEnv === 'production';\n }\n\n /**\n * Clear build folder\n */\n public clearBuildFolder(): void {\n // clear build folder\n if (fs.existsSync(this.buildDir)) {\n fs.rmSync(this.buildDir, { recursive: true });\n }\n }\n\n /**\n * Promisify spawn process\n */\n public promisifyProcess(\n command: childProcess.ChildProcess,\n isRejectWarnings = false,\n ): Promise<unknown> {\n const promise = new Promise((resolve, reject) => {\n command.on('exit', (code) => {\n resolve(code);\n });\n\n command.on('close', (code: number): void => {\n resolve(code);\n });\n\n command.on('error', (message: string): void => {\n reject(message);\n });\n\n if (isRejectWarnings) {\n command.stderr?.on('data', (buff: Uint8Array): void => {\n const msg = Buffer.from(buff).toString();\n\n if (msg.includes('warning') || msg.includes('WARNING')) {\n resolve(1);\n }\n });\n }\n });\n\n command.stdout?.pipe(process.stdout);\n command.stderr?.pipe(process.stderr);\n\n promise['command'] = command;\n\n return promise;\n }\n\n /**\n * Build assets manifest file\n */\n public async buildManifest(): Promise<void> {\n console.log(chalk.blue('Building routes manifest file...'));\n\n const serverConfig = ServerConfig.init(\n { isProd: this.isProd, mode: this.params.mode },\n { root: this.viteConfig.root },\n );\n\n await SsrManifest.get(serverConfig, {\n buildDir: this.viteConfig.build.outDir,\n viteAliases: this.viteConfig.resolve.alias,\n }).buildRoutesManifest();\n }\n\n /**\n * Change general directive Disallow to Allow in robots.txt.\n */\n public unlockRobots(): void {\n const robotsFile = `${this.buildDir}/client/robots.txt`;\n\n if (!fs.existsSync(robotsFile)) {\n console.warn(`Failed to unlock robots.txt, file not exist: ${robotsFile}`);\n\n return;\n }\n\n const data = fs\n .readFileSync(robotsFile, { encoding: 'utf-8' })\n .replace(/Disallow: \\/$/m, 'Allow: /');\n\n fs.writeFileSync(robotsFile, data, { encoding: 'utf-8' });\n\n console.info(chalk.blue('\\nrobots.txt unlocked.'));\n }\n\n /**\n * Eject cli to run app via node\n */\n public eject(): void {\n const entrypoint = `${this.buildDir}/server/start.js`;\n const script =\n \"import runProd from '@lomray/vite-ssr-boost/cli/run-prod.js';\\n\\n\" +\n 'const VERSION = process.env.VERSION || \"1.0.0\";\\n' +\n 'const PORT = process.env.PORT || 3000;\\n' +\n 'const IS_HOST = process.env.IS_HOST || \"0\";\\n' +\n 'const ONLY_CLIENT = process.env.ONLY_CLIENT || \"0\";\\n\\n' +\n `await runProd({\n version: VERSION,\n isHost: IS_HOST === '1',\n isPrintInfo: true,\n port: PORT,\n onlyClient: ONLY_CLIENT === '1',\n });\\n`;\n\n fs.writeFileSync(entrypoint, script, {\n encoding: 'utf-8',\n });\n }\n}\n\nexport default Build;\n"],"names":["Build","isProd","nodeEnv","buildDir","outDir","serverFile","viteConfig","pluginConfig","params","constructor","this","async","mode","resolveConfig","getPluginConfig","path","resolve","root","build","process","env","NODE_ENV","clearBuildFolder","fs","existsSync","rmSync","recursive","promisifyProcess","command","isRejectWarnings","promise","Promise","reject","on","code","message","stderr","buff","msg","Buffer","from","toString","includes","stdout","pipe","console","log","chalk","blue","serverConfig","ServerConfig","init","SsrManifest","get","viteAliases","alias","buildRoutesManifest","unlockRobots","robotsFile","warn","data","readFileSync","encoding","replace","writeFileSync","info","eject","entrypoint"],"mappings":"wNAkBA,MAAMA,EAIGC,OAKAC,QAKAC,SAKAC,OAKAC,WAKAC,WAKAC,aAKGC,OAKVC,YAAYD,GACVE,KAAKF,OAASA,CACf,CAKMG,mBACL,MAAMC,KAAEA,GAASF,KAAKF,OAEtBE,KAAKJ,iBAAmBO,EACtB,GACA,QACAD,EACS,eAATA,EAAwB,aAAe,eAEzCF,KAAKH,aAAeO,EAAgBJ,KAAKJ,YACzCI,KAAKP,SAAWY,EAAKC,QAAQN,KAAKJ,WAAWW,KAAMP,KAAKJ,WAAWY,MAAMd,QACzEM,KAAKN,OAASM,KAAKJ,WAAWY,MAAMd,OACpCM,KAAKL,WAAaK,KAAKH,aAAaF,WACpCK,KAAKR,QAAUiB,QAAQC,IAAIC,UAAY,cACvCX,KAAKT,OAA0B,eAAjBS,KAAKR,OACpB,CAKMoB,mBAEDC,EAAGC,WAAWd,KAAKP,WACrBoB,EAAGE,OAAOf,KAAKP,SAAU,CAAEuB,WAAW,GAEzC,CAKMC,iBACLC,EACAC,GAAmB,GAEnB,MAAMC,EAAU,IAAIC,SAAQ,CAACf,EAASgB,KACpCJ,EAAQK,GAAG,QAASC,IAClBlB,EAAQkB,EAAK,IAGfN,EAAQK,GAAG,SAAUC,IACnBlB,EAAQkB,EAAK,IAGfN,EAAQK,GAAG,SAAUE,IACnBH,EAAOG,EAAQ,IAGbN,GACFD,EAAQQ,QAAQH,GAAG,QAASI,IAC1B,MAAMC,EAAMC,OAAOC,KAAKH,GAAMI,YAE1BH,EAAII,SAAS,YAAcJ,EAAII,SAAS,aAC1C1B,EAAQ,EACT,GAEJ,IAQH,OALAY,EAAQe,QAAQC,KAAKzB,QAAQwB,QAC7Bf,EAAQQ,QAAQQ,KAAKzB,QAAQiB,QAE7BN,EAAiB,QAAIF,EAEdE,CACR,CAKMnB,sBACLkC,QAAQC,IAAIC,EAAMC,KAAK,qCAEvB,MAAMC,EAAeC,EAAaC,KAChC,CAAElD,OAAQS,KAAKT,OAAQW,KAAMF,KAAKF,OAAOI,MACzC,CAAEK,KAAMP,KAAKJ,WAAWW,aAGpBmC,EAAYC,IAAIJ,EAAc,CAClC9C,SAAUO,KAAKJ,WAAWY,MAAMd,OAChCkD,YAAa5C,KAAKJ,WAAWU,QAAQuC,QACpCC,qBACJ,CAKMC,eACL,MAAMC,EAAa,GAAGhD,KAAKP,6BAE3B,IAAKoB,EAAGC,WAAWkC,GAGjB,YAFAb,QAAQc,KAAK,gDAAgDD,KAK/D,MAAME,EAAOrC,EACVsC,aAAaH,EAAY,CAAEI,SAAU,UACrCC,QAAQ,iBAAkB,YAE7BxC,EAAGyC,cAAcN,EAAYE,EAAM,CAAEE,SAAU,UAE/CjB,QAAQoB,KAAKlB,EAAMC,KAAK,0BACzB,CAKMkB,QACL,MAAMC,EAAa,GAAGzD,KAAKP,2BAe3BoB,EAAGyC,cAAcG,EAbf,2bAamC,CACnCL,SAAU,SAEb"}
@@ -1,9 +1,12 @@
1
1
  import { Request } from 'express';
2
+ import { TRouteObject } from "../interfaces/route-object.js";
2
3
  import { IEntrypointOptions } from "../node/entry.js";
3
4
  import { TRender } from "../node/render.js";
4
5
  import ServerConfig from "./server-config.js";
5
6
  interface IPrepareServerEntrypointLoadOut<TAppProps = Record<string, any>> {
6
7
  render: TRender;
8
+ routes: TRouteObject[];
9
+ abortDelay?: number;
7
10
  onRequest?: IEntrypointOptions<TAppProps>['onRequest'];
8
11
  onRouterReady?: IEntrypointOptions<TAppProps>['onRouterReady'];
9
12
  onShellReady?: IEntrypointOptions<TAppProps>['onShellReady'];
@@ -35,11 +38,9 @@ declare class PrepareServer {
35
38
  protected html: string;
36
39
  /**
37
40
  * @constructor
38
- * @protected
39
41
  */
40
42
  /**
41
43
  * @constructor
42
- * @protected
43
44
  */
44
45
  protected constructor(config: ServerConfig);
45
46
  /**
@@ -55,7 +56,7 @@ declare class PrepareServer {
55
56
  /**
56
57
  * Resolve and return entrypoint params
57
58
  */
58
- loadEntrypoint(): Promise<IPrepareServerEntrypointLoadOut>;
59
+ loadEntrypoint(shouldInit?: boolean): Promise<IPrepareServerEntrypointLoadOut>;
59
60
  /**
60
61
  * Load and return html shell
61
62
  */
@@ -1,2 +1,2 @@
1
- import t from"fs";import e from"path";class r{config;entrypoint;onServerCreated;html;constructor(t){this.config=t}static init(t){return new r(t)}async loadEntrypoint(){if(this.entrypoint&&this.config.isProd)return this.entrypoint;const{root:t,isProd:r,serverFile:o}=this.config.getParams(),n=e.resolve(`${t}/${o}`);let i;i=r?(await import(n)).default:(await this.config.getVite().ssrLoadModule(n,{fixStacktrace:!0})).default;const{render:s,init:a}=i,{onServerCreated:l,onRequest:h,onRouterReady:c,onShellReady:d,onResponse:p,onShellError:f,onError:g,getState:u}=await(a?.({config:this.config}))??{};return this.entrypoint={render:s,onRequest:h,onRouterReady:c,onShellReady:d,onShellError:f,onResponse:p,onError:g,getState:u},this.onServerCreated=l,this.entrypoint}async loadHtml(r){const{isProd:o,root:n,indexFile:i}=this.config.getParams();this.html&&o||(this.html=t.readFileSync(e.resolve(`${n}/${i}`),"utf-8"));let s=this.html;return o||(s=(await this.config.getVite().transformIndexHtml(r.originalUrl,this.html)).replace(/(<script.+)(>[\s\S]+injectIntoGlobalHook.+)/,"$1async$2")),s.split("\x3c!--ssr-outlet--\x3e")}async onAppCreated(){return await this.loadEntrypoint(),await(this.onServerCreated?.(this.config.getApp())),this}}export{r as default};
1
+ import t from"fs";import e from"node:process";import{pathToFileURL as r}from"node:url";import i from"path";import o from"chalk";class n{config;entrypoint;onServerCreated;html;constructor(t){this.config=t}static init(t){return new n(t)}async loadEntrypoint(t=!0){if(this.entrypoint&&this.config.isProd)return this.entrypoint;const{root:n,isProd:s,serverFile:a}=this.config.getParams(),l=i.resolve(`${n}/${a}`);let c;try{c=s?(await import(r(l).toString())).default:(await this.config.getVite().ssrLoadModule(l,{fixStacktrace:!0})).default}catch(t){if(t.message.includes("Cannot find module")&&t.message.includes("/build/"))return this.config.getLogger().error(o.red(`Before starting the server, you need to create a build: ${o.yellow("ssr-boost build")}`)),e.exit(1);throw t}!t&&c.init&&delete c.init;const{render:d,init:h,routes:f,abortDelay:g}=c,{onServerCreated:m,...p}=await(h?.({config:this.config}))??{};return this.entrypoint={render:d,routes:f,abortDelay:g,...p},this.onServerCreated=m,this.entrypoint}async loadHtml(e){const{isProd:r,root:o,indexFile:n}=this.config.getParams();this.html&&r||(this.html=t.readFileSync(i.resolve(`${o}/${n}`),"utf-8"));let s=this.html;return r||(s=(await this.config.getVite().transformIndexHtml(e.originalUrl,this.html)).replace(/(<script.+)(>[\s\S]+injectIntoGlobalHook.+)/,"$1async$2")),s.split("\x3c!--ssr-outlet--\x3e")}async onAppCreated(){return await this.loadEntrypoint(),await(this.onServerCreated?.(this.config.getApp())),this}}export{n as default};
2
2
  //# sourceMappingURL=prepare-server.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"prepare-server.js","sources":["../../src/services/prepare-server.ts"],"sourcesContent":["import fs from 'fs';\nimport path from 'path';\nimport type { Request } from 'express';\nimport type { IEntrypointOptions, IPrepareRenderOut } from '@node/entry';\nimport type { TRender } from '@node/render';\nimport type ServerConfig from '@services/server-config';\n\ninterface IPrepareServerEntrypointLoadOut<TAppProps = Record<string, any>> {\n render: TRender;\n onRequest?: IEntrypointOptions<TAppProps>['onRequest'];\n onRouterReady?: IEntrypointOptions<TAppProps>['onRouterReady'];\n onShellReady?: IEntrypointOptions<TAppProps>['onShellReady'];\n onShellError?: IEntrypointOptions<TAppProps>['onShellError'];\n onResponse?: IEntrypointOptions<TAppProps>['onResponse'];\n onError?: IEntrypointOptions<TAppProps>['onError'];\n getState?: IEntrypointOptions<TAppProps>['getState'];\n}\n\n/**\n * Load server entrypoint and template\n * DEV MODE: refresh entrypoint and template\n */\nclass PrepareServer {\n /**\n * Server configuration\n */\n protected readonly config: ServerConfig;\n\n /**\n * Entrypoint resolved params\n */\n protected entrypoint?: IPrepareServerEntrypointLoadOut;\n\n /**\n * Hook which calls after express server created\n */\n protected onServerCreated?: IEntrypointOptions['onServerCreated'];\n\n /**\n * Html shell\n */\n protected html: string;\n\n /**\n * @constructor\n * @protected\n */\n protected constructor(config: ServerConfig) {\n this.config = config;\n }\n\n /**\n * Init service\n */\n public static init(config: ServerConfig): PrepareServer {\n return new PrepareServer(config);\n }\n\n /**\n * Resolve and return entrypoint params\n */\n public async loadEntrypoint(): Promise<IPrepareServerEntrypointLoadOut> {\n // load server entrypoint each time only in development mode (for fast refresh)\n if (this.entrypoint && this.config.isProd) {\n return this.entrypoint;\n }\n\n const { root, isProd, serverFile } = this.config.getParams();\n const entrypointPath = path.resolve(`${root}/${serverFile}`);\n\n let resolvedEntrypoint: IPrepareRenderOut;\n\n if (!isProd) {\n resolvedEntrypoint = (\n await this.config.getVite()!.ssrLoadModule(entrypointPath, {\n fixStacktrace: true,\n })\n ).default;\n } else {\n resolvedEntrypoint = (await import(entrypointPath)).default;\n }\n\n const { render, init } = resolvedEntrypoint;\n const {\n onServerCreated,\n onRequest,\n onRouterReady,\n onShellReady,\n onResponse,\n onShellError,\n onError,\n getState,\n } =\n (await init?.({\n config: this.config,\n })) ?? {};\n\n this.entrypoint = {\n render,\n onRequest,\n onRouterReady,\n onShellReady,\n onShellError,\n onResponse,\n onError,\n getState,\n };\n this.onServerCreated = onServerCreated;\n\n return this.entrypoint;\n }\n\n /**\n * Load and return html shell\n */\n public async loadHtml(req: Request): Promise<[string, string]> {\n const { isProd, root, indexFile } = this.config.getParams();\n\n if (!this.html || !isProd) {\n this.html = fs.readFileSync(path.resolve(`${root}/${indexFile}`), 'utf-8');\n }\n\n let modifiedHtml = this.html;\n\n if (!isProd) {\n // Apply Vite HTML transforms. This injects the Vite HMR client,\n // and also applies HTML transforms from Vite plugins, e.g. global\n // preambles from @vitejs/plugin-react\n modifiedHtml = (await this.config.getVite()!.transformIndexHtml(req.originalUrl, this.html))\n // Make vite script 'async'\n .replace(/(<script.+)(>[\\s\\S]+injectIntoGlobalHook.+)/, '$1async$2');\n }\n\n return modifiedHtml.split('<!--ssr-outlet-->') as [string, string];\n }\n\n /**\n * Run server created hook\n */\n public async onAppCreated(): Promise<PrepareServer> {\n await this.loadEntrypoint();\n await this.onServerCreated?.(this.config.getApp()!);\n\n return this;\n }\n}\n\nexport default PrepareServer;\n"],"names":["PrepareServer","config","entrypoint","onServerCreated","html","constructor","this","static","async","isProd","root","serverFile","getParams","entrypointPath","path","resolve","resolvedEntrypoint","import","default","getVite","ssrLoadModule","fixStacktrace","render","init","onRequest","onRouterReady","onShellReady","onResponse","onShellError","onError","getState","req","indexFile","fs","readFileSync","modifiedHtml","transformIndexHtml","originalUrl","replace","split","loadEntrypoint","getApp"],"mappings":"sCAsBA,MAAMA,EAIeC,OAKTC,WAKAC,gBAKAC,KAMVC,YAAsBJ,GACpBK,KAAKL,OAASA,CACf,CAKMM,YAAYN,GACjB,OAAO,IAAID,EAAcC,EAC1B,CAKMO,uBAEL,GAAIF,KAAKJ,YAAcI,KAAKL,OAAOQ,OACjC,OAAOH,KAAKJ,WAGd,MAAMQ,KAAEA,EAAID,OAAEA,EAAME,WAAEA,GAAeL,KAAKL,OAAOW,YAC3CC,EAAiBC,EAAKC,QAAQ,GAAGL,KAAQC,KAE/C,IAAIK,EASFA,EAPGP,SAOyBQ,OAAOJ,IAAiBK,eAL5CZ,KAAKL,OAAOkB,UAAWC,cAAcP,EAAgB,CACzDQ,eAAe,KAEjBH,QAKJ,MAAMI,OAAEA,EAAMC,KAAEA,GAASP,GACnBb,gBACJA,EAAeqB,UACfA,EAASC,cACTA,EAAaC,aACbA,EAAYC,WACZA,EAAUC,aACVA,EAAYC,QACZA,EAAOC,SACPA,SAEOP,IAAO,CACZtB,OAAQK,KAAKL,WACR,CAAA,EAcT,OAZAK,KAAKJ,WAAa,CAChBoB,SACAE,YACAC,gBACAC,eACAE,eACAD,aACAE,UACAC,YAEFxB,KAAKH,gBAAkBA,EAEhBG,KAAKJ,UACb,CAKMM,eAAeuB,GACpB,MAAMtB,OAAEA,EAAMC,KAAEA,EAAIsB,UAAEA,GAAc1B,KAAKL,OAAOW,YAE3CN,KAAKF,MAASK,IACjBH,KAAKF,KAAO6B,EAAGC,aAAapB,EAAKC,QAAQ,GAAGL,KAAQsB,KAAc,UAGpE,IAAIG,EAAe7B,KAAKF,KAWxB,OATKK,IAIH0B,SAAsB7B,KAAKL,OAAOkB,UAAWiB,mBAAmBL,EAAIM,YAAa/B,KAAKF,OAEnFkC,QAAQ,8CAA+C,cAGrDH,EAAaI,MAAM,0BAC3B,CAKM/B,qBAIL,aAHMF,KAAKkC,uBACLlC,KAAKH,kBAAkBG,KAAKL,OAAOwC,WAElCnC,IACR"}
1
+ {"version":3,"file":"prepare-server.js","sources":["../../src/services/prepare-server.ts"],"sourcesContent":["import fs from 'fs';\nimport process from 'node:process';\nimport { pathToFileURL } from 'node:url';\nimport path from 'path';\nimport chalk from 'chalk';\nimport type { Request } from 'express';\nimport type { TRouteObject } from '@interfaces/route-object';\nimport type { IEntrypointOptions, IPrepareRenderOut } from '@node/entry';\nimport type { TRender } from '@node/render';\nimport type ServerConfig from '@services/server-config';\n\ninterface IPrepareServerEntrypointLoadOut<TAppProps = Record<string, any>> {\n render: TRender;\n routes: TRouteObject[];\n abortDelay?: number;\n onRequest?: IEntrypointOptions<TAppProps>['onRequest'];\n onRouterReady?: IEntrypointOptions<TAppProps>['onRouterReady'];\n onShellReady?: IEntrypointOptions<TAppProps>['onShellReady'];\n onShellError?: IEntrypointOptions<TAppProps>['onShellError'];\n onResponse?: IEntrypointOptions<TAppProps>['onResponse'];\n onError?: IEntrypointOptions<TAppProps>['onError'];\n getState?: IEntrypointOptions<TAppProps>['getState'];\n}\n\n/**\n * Load server entrypoint and template\n * DEV MODE: refresh entrypoint and template\n */\nclass PrepareServer {\n /**\n * Server configuration\n */\n protected readonly config: ServerConfig;\n\n /**\n * Entrypoint resolved params\n */\n protected entrypoint?: IPrepareServerEntrypointLoadOut;\n\n /**\n * Hook which calls after express server created\n */\n protected onServerCreated?: IEntrypointOptions['onServerCreated'];\n\n /**\n * Html shell\n */\n protected html: string;\n\n /**\n * @constructor\n */\n protected constructor(config: ServerConfig) {\n this.config = config;\n }\n\n /**\n * Init service\n */\n public static init(config: ServerConfig): PrepareServer {\n return new PrepareServer(config);\n }\n\n /**\n * Resolve and return entrypoint params\n */\n public async loadEntrypoint(shouldInit = true): Promise<IPrepareServerEntrypointLoadOut> {\n // load server entrypoint each time only in development mode (for fast refresh)\n if (this.entrypoint && this.config.isProd) {\n return this.entrypoint;\n }\n\n const { root, isProd, serverFile } = this.config.getParams();\n const entrypointPath = path.resolve(`${root}/${serverFile}`);\n\n let resolvedEntrypoint: IPrepareRenderOut;\n\n try {\n if (!isProd) {\n resolvedEntrypoint = (\n await this.config.getVite()!.ssrLoadModule(entrypointPath, {\n fixStacktrace: true,\n })\n ).default;\n } else {\n resolvedEntrypoint = (await import(pathToFileURL(entrypointPath).toString())).default;\n }\n } catch (e) {\n if (e.message.includes('Cannot find module') && e.message.includes('/build/')) {\n this.config\n .getLogger()\n .error(\n chalk.red(\n `Before starting the server, you need to create a build: ${chalk.yellow(\n 'ssr-boost build',\n )}`,\n ),\n );\n\n return process.exit(1);\n }\n\n throw e;\n }\n\n if (!shouldInit && resolvedEntrypoint.init) {\n delete resolvedEntrypoint.init;\n }\n\n const { render, init, routes, abortDelay } = resolvedEntrypoint;\n const { onServerCreated, ...renderParams } =\n (await init?.({\n config: this.config,\n })) ?? {};\n\n this.entrypoint = {\n render,\n routes,\n abortDelay,\n ...renderParams,\n };\n this.onServerCreated = onServerCreated;\n\n return this.entrypoint;\n }\n\n /**\n * Load and return html shell\n */\n public async loadHtml(req: Request): Promise<[string, string]> {\n const { isProd, root, indexFile } = this.config.getParams();\n\n if (!this.html || !isProd) {\n this.html = fs.readFileSync(path.resolve(`${root}/${indexFile}`), 'utf-8');\n }\n\n let modifiedHtml = this.html;\n\n if (!isProd) {\n // Apply Vite HTML transforms. This injects the Vite HMR client,\n // and also applies HTML transforms from Vite plugins, e.g. global\n // preambles from @vitejs/plugin-react\n modifiedHtml = (await this.config.getVite()!.transformIndexHtml(req.originalUrl, this.html))\n // Make vite script 'async'\n .replace(/(<script.+)(>[\\s\\S]+injectIntoGlobalHook.+)/, '$1async$2');\n }\n\n return modifiedHtml.split('<!--ssr-outlet-->') as [string, string];\n }\n\n /**\n * Run server created hook\n */\n public async onAppCreated(): Promise<PrepareServer> {\n await this.loadEntrypoint();\n await this.onServerCreated?.(this.config.getApp()!);\n\n return this;\n }\n}\n\nexport default PrepareServer;\n"],"names":["PrepareServer","config","entrypoint","onServerCreated","html","constructor","this","static","async","shouldInit","isProd","root","serverFile","getParams","entrypointPath","path","resolve","resolvedEntrypoint","import","pathToFileURL","toString","default","getVite","ssrLoadModule","fixStacktrace","e","message","includes","getLogger","error","chalk","red","yellow","process","exit","init","render","routes","abortDelay","renderParams","req","indexFile","fs","readFileSync","modifiedHtml","transformIndexHtml","originalUrl","replace","split","loadEntrypoint","getApp"],"mappings":"gIA4BA,MAAMA,EAIeC,OAKTC,WAKAC,gBAKAC,KAKVC,YAAsBJ,GACpBK,KAAKL,OAASA,CACf,CAKMM,YAAYN,GACjB,OAAO,IAAID,EAAcC,EAC1B,CAKMO,qBAAqBC,GAAa,GAEvC,GAAIH,KAAKJ,YAAcI,KAAKL,OAAOS,OACjC,OAAOJ,KAAKJ,WAGd,MAAMS,KAAEA,EAAID,OAAEA,EAAME,WAAEA,GAAeN,KAAKL,OAAOY,YAC3CC,EAAiBC,EAAKC,QAAQ,GAAGL,KAAQC,KAE/C,IAAIK,EAEJ,IAQIA,EAPGP,SAOyBQ,OAAOC,EAAcL,GAAgBM,aAAaC,eALtEf,KAAKL,OAAOqB,UAAWC,cAAcT,EAAgB,CACzDU,eAAe,KAEjBH,OAIL,CAAC,MAAOI,GACP,GAAIA,EAAEC,QAAQC,SAAS,uBAAyBF,EAAEC,QAAQC,SAAS,WAWjE,OAVArB,KAAKL,OACF2B,YACAC,MACCC,EAAMC,IACJ,2DAA2DD,EAAME,OAC/D,uBAKDC,EAAQC,KAAK,GAGtB,MAAMT,CACP,EAEIhB,GAAcQ,EAAmBkB,aAC7BlB,EAAmBkB,KAG5B,MAAMC,OAAEA,EAAMD,KAAEA,EAAIE,OAAEA,EAAMC,WAAEA,GAAerB,GACvCd,gBAAEA,KAAoBoC,SACnBJ,IAAO,CACZlC,OAAQK,KAAKL,WACR,CAAA,EAUT,OARAK,KAAKJ,WAAa,CAChBkC,SACAC,SACAC,gBACGC,GAELjC,KAAKH,gBAAkBA,EAEhBG,KAAKJ,UACb,CAKMM,eAAegC,GACpB,MAAM9B,OAAEA,EAAMC,KAAEA,EAAI8B,UAAEA,GAAcnC,KAAKL,OAAOY,YAE3CP,KAAKF,MAASM,IACjBJ,KAAKF,KAAOsC,EAAGC,aAAa5B,EAAKC,QAAQ,GAAGL,KAAQ8B,KAAc,UAGpE,IAAIG,EAAetC,KAAKF,KAWxB,OATKM,IAIHkC,SAAsBtC,KAAKL,OAAOqB,UAAWuB,mBAAmBL,EAAIM,YAAaxC,KAAKF,OAEnF2C,QAAQ,8CAA+C,cAGrDH,EAAaI,MAAM,0BAC3B,CAKMxC,qBAIL,aAHMF,KAAK2C,uBACL3C,KAAKH,kBAAkBG,KAAKL,OAAOiD,WAElC5C,IACR"}
@@ -5,7 +5,7 @@ interface IConfigOptions {
5
5
  isProd?: boolean;
6
6
  isHost?: boolean;
7
7
  isOnlyClient?: boolean;
8
- prodParams?: Partial<IConfigParams>;
8
+ isModulePreload?: boolean;
9
9
  mode?: string;
10
10
  }
11
11
  interface IConfigParams {
@@ -16,7 +16,6 @@ interface IConfigParams {
16
16
  isSPA: boolean;
17
17
  indexFile: string;
18
18
  serverFile: string;
19
- abortDelay: number;
20
19
  host: string;
21
20
  port: number;
22
21
  }
@@ -32,6 +31,10 @@ declare class ServerConfig {
32
31
  * Server host mode
33
32
  */
34
33
  readonly isHost: boolean;
34
+ /**
35
+ * Add module preload scripts to server output
36
+ */
37
+ readonly isModulePreload: boolean;
35
38
  /**
36
39
  * SPA mode
37
40
  */
@@ -66,7 +69,7 @@ declare class ServerConfig {
66
69
  /**
67
70
  * @constructor
68
71
  */
69
- protected constructor({ isProd, isHost, isOnlyClient, mode }: IConfigOptions, prodParams: Partial<IConfigParams>);
72
+ protected constructor({ isProd, isHost, isOnlyClient, isModulePreload, mode, }: IConfigOptions, prodParams: Partial<IConfigParams>);
70
73
  /**
71
74
  * Initialize service
72
75
  */
@@ -95,13 +98,6 @@ declare class ServerConfig {
95
98
  * Set express server
96
99
  */
97
100
  setApp(express: Express): void;
98
- /**
99
- * Set custom abort delay
100
- */
101
- /**
102
- * Set custom abort delay
103
- */
104
- setAbortDelay(ms: number): void;
105
101
  /**
106
102
  * Return vite dev server
107
103
  * NOTE: only on development mode
@@ -1,2 +1,2 @@
1
- import r from"node:path";import t from"../helpers/plugin-config.js";import i from"./logger.js";class s{isProd;isHost;isSPA;mode;vite;app;params;prodParams;logger;constructor({isProd:r=!1,isHost:t=!1,isOnlyClient:i=!1,mode:s="production"},e){this.isProd=r,this.isHost=t,this.isSPA=i,this.mode=s,this.prodParams={root:"./build",publicDir:"/client",indexFile:"/client/index.html",serverFile:"/server/server.js",host:"127.0.0.1",port:3e3,abortDelay:1e4,...e},this.makeParams()}static init(r={},t={}){return new s(r,t)}makeParams(){const t=this.getPluginConfig()??{},{config:s}=this.vite??{},e=s?.root??this.prodParams.root??"",o=s?.publicDir??this.prodParams.publicDir,a=new URL(import.meta.url),p=t.pluginPath??r.resolve(`../${r.dirname(a.pathname)}`),h=t.indexFile??this.prodParams.indexFile,l=t.serverFile??this.prodParams.serverFile,n="boolean"==typeof s?.server.host||this.isHost?"0.0.0.0":s?.server.host??this.prodParams.host,m=s?.server.port??(this.isProd?this.prodParams.port:5173),d=t.abortDelay??this.prodParams.abortDelay;this.params={root:e,publicDir:o,pluginPath:p,indexFile:h,serverFile:l,host:n,port:m,abortDelay:d,isSPA:this.isSPA,isProd:this.isProd},this.logger=this.vite?.config.logger??new i}setVite(r){this.vite=r,this.makeParams()}setApp(r){this.app=r}setAbortDelay(r){this.prodParams.abortDelay=r,this.params.abortDelay=r}getVite(){return this.vite}getApp(){return this.app}getPluginConfig(){return this.vite?t(this.vite.config):void 0}getParams(){return this.params}getLogger(){return this.logger}}export{s as default};
1
+ import i from"node:path";import r from"../helpers/plugin-config.js";import s from"./logger.js";class t{isProd;isHost;isModulePreload;isSPA;mode;vite;app;params;prodParams;logger;constructor({isProd:i=!1,isHost:r=!1,isOnlyClient:s=!1,isModulePreload:t=!1,mode:e="production"},o){this.isProd=i,this.isHost=r,this.isSPA=s,this.isModulePreload=t,this.mode=e,this.prodParams={root:"./build",publicDir:"/client",indexFile:"/client/index.html",serverFile:"/server/server.js",host:"127.0.0.1",port:3e3,...o},this.makeParams()}static init(i={},r={}){return new t(i,r)}makeParams(){const r=this.getPluginConfig()??{},{config:t}=this.vite??{},e=t?.root??this.prodParams.root??"",o=t?.publicDir??this.prodParams.publicDir,a=new URL(import.meta.url),h=r.pluginPath??i.resolve(i.dirname(a.pathname),"../"),p=r.indexFile??this.prodParams.indexFile,l=r.serverFile??this.prodParams.serverFile,n="boolean"==typeof t?.server.host||this.isHost?"0.0.0.0":t?.server.host??this.prodParams.host,d=t?.server.port??(this.isProd?this.prodParams.port:5173);this.params={root:e,publicDir:o,pluginPath:h,indexFile:p,serverFile:l,host:n,port:d,isSPA:this.isSPA,isProd:this.isProd},this.logger=this.vite?.config.logger??new s}setVite(i){this.vite=i,this.makeParams()}setApp(i){this.app=i}getVite(){return this.vite}getApp(){return this.app}getPluginConfig(){return this.vite?r(this.vite.config):void 0}getParams(){return this.params}getLogger(){return this.logger}}export{t as default};
2
2
  //# sourceMappingURL=server-config.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"server-config.js","sources":["../../src/services/server-config.ts"],"sourcesContent":["import path from 'node:path';\nimport type { Express } from 'express';\nimport type { Logger, ViteDevServer } from 'vite';\nimport type { IPluginConfig } from '@helpers/plugin-config';\nimport getPluginConfig from '@helpers/plugin-config';\nimport DefaultLogger from '@services/logger';\n\ninterface IConfigOptions {\n isProd?: boolean;\n isHost?: boolean;\n isOnlyClient?: boolean; // SPA mode\n prodParams?: Partial<IConfigParams>;\n mode?: string;\n}\n\ninterface IConfigParams {\n root: string;\n publicDir: string;\n pluginPath: string;\n isProd: boolean;\n isSPA: boolean;\n indexFile: string;\n serverFile: string;\n abortDelay: number;\n host: string;\n port: number;\n}\n\n/**\n * Server config\n */\nclass ServerConfig {\n /**\n * Production build\n */\n public readonly isProd: boolean;\n\n /**\n * Server host mode\n */\n public readonly isHost: boolean;\n\n /**\n * SPA mode\n */\n public readonly isSPA: boolean;\n\n /**\n * Env mode\n */\n public readonly mode: string;\n\n /**\n * Vite config - only for development\n */\n protected vite?: ViteDevServer;\n\n /**\n * Express application\n */\n protected app?: Express;\n\n /**\n * Config params\n */\n protected params: IConfigParams;\n\n /**\n * Default production params\n */\n protected prodParams: Partial<IConfigParams>;\n\n /**\n * Vite logger for dev mode or console for production\n */\n protected logger: Logger;\n\n /**\n * @constructor\n */\n protected constructor(\n { isProd = false, isHost = false, isOnlyClient = false, mode = 'production' }: IConfigOptions,\n prodParams: Partial<IConfigParams>,\n ) {\n this.isProd = isProd;\n this.isHost = isHost;\n this.isSPA = isOnlyClient;\n this.mode = mode;\n this.prodParams = {\n root: './build',\n publicDir: '/client', // default for production,\n indexFile: '/client/index.html',\n serverFile: '/server/server.js',\n host: '127.0.0.1',\n port: 3000,\n abortDelay: 10000,\n ...prodParams,\n };\n\n this.makeParams();\n }\n\n /**\n * Initialize service\n */\n public static init(\n options: IConfigOptions = {},\n prodOptions: Partial<IConfigParams> = {},\n ): ServerConfig {\n return new ServerConfig(options, prodOptions);\n }\n\n /**\n * Make config params\n */\n protected makeParams(): void {\n const pluginConfig = (this.getPluginConfig() ?? {}) as Partial<IPluginConfig>;\n const { config } = this.vite ?? {};\n\n const root = config?.root ?? this.prodParams.root ?? '';\n const publicDir = config?.publicDir ?? this.prodParams.publicDir!;\n const dirInfo = new URL(import.meta.url);\n const pluginPath =\n pluginConfig.pluginPath ?? path.resolve(`../${path.dirname(dirInfo.pathname)}`);\n const indexFile = pluginConfig.indexFile ?? this.prodParams.indexFile!;\n const serverFile = pluginConfig.serverFile ?? this.prodParams.serverFile!;\n const host =\n typeof config?.server.host === 'boolean' || this.isHost\n ? '0.0.0.0'\n : config?.server.host ?? this.prodParams.host!;\n const port = config?.server.port ?? (this.isProd ? this.prodParams.port! : 5173);\n const abortDelay = pluginConfig.abortDelay ?? this.prodParams.abortDelay!;\n\n this.params = {\n root,\n publicDir,\n pluginPath,\n indexFile,\n serverFile,\n host,\n port,\n abortDelay,\n isSPA: this.isSPA,\n isProd: this.isProd,\n };\n this.logger = this.vite?.config.logger ?? new DefaultLogger();\n }\n\n /**\n * Set vite server\n */\n public setVite(vite: ViteDevServer): void {\n this.vite = vite;\n\n this.makeParams();\n }\n\n /**\n * Set express server\n */\n public setApp(express: Express): void {\n this.app = express;\n }\n\n /**\n * Set custom abort delay\n */\n public setAbortDelay(ms: number): void {\n this.prodParams.abortDelay = ms;\n this.params.abortDelay = ms;\n }\n\n /**\n * Return vite dev server\n * NOTE: only on development mode\n */\n public getVite(): ViteDevServer | undefined {\n return this.vite;\n }\n\n /**\n * Return express server\n */\n public getApp(): Express | undefined {\n return this.app;\n }\n\n /**\n * return plugin config\n * NOTE: only on development mode\n */\n public getPluginConfig(): IPluginConfig | undefined {\n return this.vite ? getPluginConfig(this.vite.config) : undefined;\n }\n\n /**\n * Return config params\n */\n public getParams(): IConfigParams {\n return this.params;\n }\n\n /**\n * Get server logger\n */\n public getLogger(): Logger {\n return this.logger;\n }\n}\n\nexport default ServerConfig;\n"],"names":["ServerConfig","isProd","isHost","isSPA","mode","vite","app","params","prodParams","logger","constructor","isOnlyClient","this","root","publicDir","indexFile","serverFile","host","port","abortDelay","makeParams","static","options","prodOptions","pluginConfig","getPluginConfig","config","dirInfo","URL","url","pluginPath","path","resolve","dirname","pathname","server","DefaultLogger","setVite","setApp","express","setAbortDelay","ms","getVite","getApp","undefined","getParams","getLogger"],"mappings":"+FA+BA,MAAMA,EAIYC,OAKAC,OAKAC,MAKAC,KAKNC,KAKAC,IAKAC,OAKAC,WAKAC,OAKVC,aACET,OAAEA,GAAS,EAAKC,OAAEA,GAAS,EAAKS,aAAEA,GAAe,EAAKP,KAAEA,EAAO,cAC/DI,GAEAI,KAAKX,OAASA,EACdW,KAAKV,OAASA,EACdU,KAAKT,MAAQQ,EACbC,KAAKR,KAAOA,EACZQ,KAAKJ,WAAa,CAChBK,KAAM,UACNC,UAAW,UACXC,UAAW,qBACXC,WAAY,oBACZC,KAAM,YACNC,KAAM,IACNC,WAAY,OACTX,GAGLI,KAAKQ,YACN,CAKMC,YACLC,EAA0B,GAC1BC,EAAsC,CAAA,GAEtC,OAAO,IAAIvB,EAAasB,EAASC,EAClC,CAKSH,aACR,MAAMI,EAAgBZ,KAAKa,mBAAqB,CAAE,GAC5CC,OAAEA,GAAWd,KAAKP,MAAQ,CAAA,EAE1BQ,EAAOa,GAAQb,MAAQD,KAAKJ,WAAWK,MAAQ,GAC/CC,EAAYY,GAAQZ,WAAaF,KAAKJ,WAAWM,UACjDa,EAAU,IAAIC,gBAAgBC,KAC9BC,EACJN,EAAaM,YAAcC,EAAKC,QAAQ,MAAMD,EAAKE,QAAQN,EAAQO,aAC/DnB,EAAYS,EAAaT,WAAaH,KAAKJ,WAAWO,UACtDC,EAAaQ,EAAaR,YAAcJ,KAAKJ,WAAWQ,WACxDC,EAC2B,kBAAxBS,GAAQS,OAAOlB,MAAsBL,KAAKV,OAC7C,UACAwB,GAAQS,OAAOlB,MAAQL,KAAKJ,WAAWS,KACvCC,EAAOQ,GAAQS,OAAOjB,OAASN,KAAKX,OAASW,KAAKJ,WAAWU,KAAQ,MACrEC,EAAaK,EAAaL,YAAcP,KAAKJ,WAAWW,WAE9DP,KAAKL,OAAS,CACZM,OACAC,YACAgB,aACAf,YACAC,aACAC,OACAC,OACAC,aACAhB,MAAOS,KAAKT,MACZF,OAAQW,KAAKX,QAEfW,KAAKH,OAASG,KAAKP,MAAMqB,OAAOjB,QAAU,IAAI2B,CAC/C,CAKMC,QAAQhC,GACbO,KAAKP,KAAOA,EAEZO,KAAKQ,YACN,CAKMkB,OAAOC,GACZ3B,KAAKN,IAAMiC,CACZ,CAKMC,cAAcC,GACnB7B,KAAKJ,WAAWW,WAAasB,EAC7B7B,KAAKL,OAAOY,WAAasB,CAC1B,CAMMC,UACL,OAAO9B,KAAKP,IACb,CAKMsC,SACL,OAAO/B,KAAKN,GACb,CAMMmB,kBACL,OAAOb,KAAKP,KAAOoB,EAAgBb,KAAKP,KAAKqB,aAAUkB,CACxD,CAKMC,YACL,OAAOjC,KAAKL,MACb,CAKMuC,YACL,OAAOlC,KAAKH,MACb"}
1
+ {"version":3,"file":"server-config.js","sources":["../../src/services/server-config.ts"],"sourcesContent":["import path from 'node:path';\nimport type { Express } from 'express';\nimport type { Logger, ViteDevServer } from 'vite';\nimport type { IPluginConfig } from '@helpers/plugin-config';\nimport getPluginConfig from '@helpers/plugin-config';\nimport DefaultLogger from '@services/logger';\n\ninterface IConfigOptions {\n isProd?: boolean;\n isHost?: boolean;\n isOnlyClient?: boolean; // SPA mode\n isModulePreload?: boolean;\n mode?: string;\n}\n\ninterface IConfigParams {\n root: string;\n publicDir: string;\n pluginPath: string;\n isProd: boolean;\n isSPA: boolean;\n indexFile: string;\n serverFile: string;\n host: string;\n port: number;\n}\n\n/**\n * Server config\n */\nclass ServerConfig {\n /**\n * Production build\n */\n public readonly isProd: boolean;\n\n /**\n * Server host mode\n */\n public readonly isHost: boolean;\n\n /**\n * Add module preload scripts to server output\n */\n public readonly isModulePreload: boolean;\n\n /**\n * SPA mode\n */\n public readonly isSPA: boolean;\n\n /**\n * Env mode\n */\n public readonly mode: string;\n\n /**\n * Vite config - only for development\n */\n protected vite?: ViteDevServer;\n\n /**\n * Express application\n */\n protected app?: Express;\n\n /**\n * Config params\n */\n protected params: IConfigParams;\n\n /**\n * Default production params\n */\n protected prodParams: Partial<IConfigParams>;\n\n /**\n * Vite logger for dev mode or console for production\n */\n protected logger: Logger;\n\n /**\n * @constructor\n */\n protected constructor(\n {\n isProd = false,\n isHost = false,\n isOnlyClient = false,\n isModulePreload = false,\n mode = 'production',\n }: IConfigOptions,\n prodParams: Partial<IConfigParams>,\n ) {\n this.isProd = isProd;\n this.isHost = isHost;\n this.isSPA = isOnlyClient;\n this.isModulePreload = isModulePreload;\n this.mode = mode;\n this.prodParams = {\n root: './build',\n publicDir: '/client', // default for production,\n indexFile: '/client/index.html',\n serverFile: '/server/server.js',\n host: '127.0.0.1',\n port: 3000,\n ...prodParams,\n };\n\n this.makeParams();\n }\n\n /**\n * Initialize service\n */\n public static init(\n options: IConfigOptions = {},\n prodOptions: Partial<IConfigParams> = {},\n ): ServerConfig {\n return new ServerConfig(options, prodOptions);\n }\n\n /**\n * Make config params\n */\n protected makeParams(): void {\n const pluginConfig = (this.getPluginConfig() ?? {}) as Partial<IPluginConfig>;\n const { config } = this.vite ?? {};\n\n const root = config?.root ?? this.prodParams.root ?? '';\n const publicDir = config?.publicDir ?? this.prodParams.publicDir!;\n const dirInfo = new URL(import.meta.url);\n const pluginPath =\n pluginConfig.pluginPath ?? path.resolve(path.dirname(dirInfo.pathname), '../');\n const indexFile = pluginConfig.indexFile ?? this.prodParams.indexFile!;\n const serverFile = pluginConfig.serverFile ?? this.prodParams.serverFile!;\n const host =\n typeof config?.server.host === 'boolean' || this.isHost\n ? '0.0.0.0'\n : config?.server.host ?? this.prodParams.host!;\n const port = config?.server.port ?? (this.isProd ? this.prodParams.port! : 5173);\n\n this.params = {\n root,\n publicDir,\n pluginPath,\n indexFile,\n serverFile,\n host,\n port,\n isSPA: this.isSPA,\n isProd: this.isProd,\n };\n this.logger = this.vite?.config.logger ?? new DefaultLogger();\n }\n\n /**\n * Set vite server\n */\n public setVite(vite: ViteDevServer): void {\n this.vite = vite;\n\n this.makeParams();\n }\n\n /**\n * Set express server\n */\n public setApp(express: Express): void {\n this.app = express;\n }\n\n /**\n * Return vite dev server\n * NOTE: only on development mode\n */\n public getVite(): ViteDevServer | undefined {\n return this.vite;\n }\n\n /**\n * Return express server\n */\n public getApp(): Express | undefined {\n return this.app;\n }\n\n /**\n * return plugin config\n * NOTE: only on development mode\n */\n public getPluginConfig(): IPluginConfig | undefined {\n return this.vite ? getPluginConfig(this.vite.config) : undefined;\n }\n\n /**\n * Return config params\n */\n public getParams(): IConfigParams {\n return this.params;\n }\n\n /**\n * Get server logger\n */\n public getLogger(): Logger {\n return this.logger;\n }\n}\n\nexport default ServerConfig;\n"],"names":["ServerConfig","isProd","isHost","isModulePreload","isSPA","mode","vite","app","params","prodParams","logger","constructor","isOnlyClient","this","root","publicDir","indexFile","serverFile","host","port","makeParams","static","options","prodOptions","pluginConfig","getPluginConfig","config","dirInfo","URL","url","pluginPath","path","resolve","dirname","pathname","server","DefaultLogger","setVite","setApp","express","getVite","getApp","undefined","getParams","getLogger"],"mappings":"+FA8BA,MAAMA,EAIYC,OAKAC,OAKAC,gBAKAC,MAKAC,KAKNC,KAKAC,IAKAC,OAKAC,WAKAC,OAKVC,aACEV,OACEA,GAAS,EAAKC,OACdA,GAAS,EAAKU,aACdA,GAAe,EAAKT,gBACpBA,GAAkB,EAAKE,KACvBA,EAAO,cAETI,GAEAI,KAAKZ,OAASA,EACdY,KAAKX,OAASA,EACdW,KAAKT,MAAQQ,EACbC,KAAKV,gBAAkBA,EACvBU,KAAKR,KAAOA,EACZQ,KAAKJ,WAAa,CAChBK,KAAM,UACNC,UAAW,UACXC,UAAW,qBACXC,WAAY,oBACZC,KAAM,YACNC,KAAM,OACHV,GAGLI,KAAKO,YACN,CAKMC,YACLC,EAA0B,GAC1BC,EAAsC,CAAA,GAEtC,OAAO,IAAIvB,EAAasB,EAASC,EAClC,CAKSH,aACR,MAAMI,EAAgBX,KAAKY,mBAAqB,CAAE,GAC5CC,OAAEA,GAAWb,KAAKP,MAAQ,CAAA,EAE1BQ,EAAOY,GAAQZ,MAAQD,KAAKJ,WAAWK,MAAQ,GAC/CC,EAAYW,GAAQX,WAAaF,KAAKJ,WAAWM,UACjDY,EAAU,IAAIC,gBAAgBC,KAC9BC,EACJN,EAAaM,YAAcC,EAAKC,QAAQD,EAAKE,QAAQN,EAAQO,UAAW,OACpElB,EAAYQ,EAAaR,WAAaH,KAAKJ,WAAWO,UACtDC,EAAaO,EAAaP,YAAcJ,KAAKJ,WAAWQ,WACxDC,EAC2B,kBAAxBQ,GAAQS,OAAOjB,MAAsBL,KAAKX,OAC7C,UACAwB,GAAQS,OAAOjB,MAAQL,KAAKJ,WAAWS,KACvCC,EAAOO,GAAQS,OAAOhB,OAASN,KAAKZ,OAASY,KAAKJ,WAAWU,KAAQ,MAE3EN,KAAKL,OAAS,CACZM,OACAC,YACAe,aACAd,YACAC,aACAC,OACAC,OACAf,MAAOS,KAAKT,MACZH,OAAQY,KAAKZ,QAEfY,KAAKH,OAASG,KAAKP,MAAMoB,OAAOhB,QAAU,IAAI0B,CAC/C,CAKMC,QAAQ/B,GACbO,KAAKP,KAAOA,EAEZO,KAAKO,YACN,CAKMkB,OAAOC,GACZ1B,KAAKN,IAAMgC,CACZ,CAMMC,UACL,OAAO3B,KAAKP,IACb,CAKMmC,SACL,OAAO5B,KAAKN,GACb,CAMMkB,kBACL,OAAOZ,KAAKP,KAAOmB,EAAgBZ,KAAKP,KAAKoB,aAAUgB,CACxD,CAKMC,YACL,OAAO9B,KAAKL,MACb,CAKMoC,YACL,OAAO/B,KAAKH,MACb"}