@lomray/vite-ssr-boost 1.0.2 → 1.1.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/cli/build.js +1 -1
- package/cli/build.js.map +1 -1
- package/helpers/get-server-state.d.ts +1 -1
- package/helpers/get-server-state.js.map +1 -1
- package/helpers/import-route.d.ts +3 -1
- package/helpers/import-route.js +1 -1
- package/helpers/import-route.js.map +1 -1
- package/helpers/obtain-stream-error.js.map +1 -1
- package/helpers/plugin-config.js +1 -1
- package/helpers/plugin-config.js.map +1 -1
- package/helpers/print-server-info.js.map +1 -1
- package/helpers/process-stop.d.ts +1 -1
- package/helpers/process-stop.js +1 -1
- package/helpers/process-stop.js.map +1 -1
- package/node/create-fetch-request.js +1 -1
- package/node/create-fetch-request.js.map +1 -1
- package/package.json +39 -25
- package/plugin.js +1 -1
- package/plugin.js.map +1 -1
- package/services/build.d.ts +4 -1
- package/services/build.js +1 -1
- package/services/build.js.map +1 -1
- package/services/ssr-manifest.d.ts +1 -1
- package/services/ssr-manifest.js +1 -1
- package/services/ssr-manifest.js.map +1 -1
package/README.md
CHANGED
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
<img src="https://img.shields.io/bundlephobia/minzip/@lomray/vite-ssr-boost" alt="size">
|
|
25
25
|
<img src="https://img.shields.io/npm/l/@lomray/vite-ssr-boost" alt="size">
|
|
26
26
|
<img src="https://img.shields.io/npm/v/@lomray/vite-ssr-boost?label=semantic%20release&logo=semantic-release" alt="semantic version">
|
|
27
|
+
<img src="https://sonarcloud.io/api/project_badges/measure?project=vite-ssr-boost&metric=coverage" alt="code coverage">
|
|
27
28
|
</p>
|
|
28
29
|
|
|
29
30
|
## Table of contents
|
package/cli/build.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import o from"node:child_process";import{performance as e}from"node:perf_hooks";import i from"chalk";import
|
|
1
|
+
import o from"node:child_process";import{performance as e}from"node:perf_hooks";import i from"chalk";import s from"./helpers/vite-reset-cache.js";import t from"../constants/cli-name.js";import{createDevMarker as r}from"../helpers/dev-marker.js";import n from"../helpers/process-stop.js";import l from"../services/build.js";async function a({onFinish:a,mode:c="",clientOptions:p="",serverOptions:d="",isOnlyClient:m=!1,isWatch:f=!1,isUnlockRobots:u=!1,isEject:O=!1,isNoWarnings:v=!1}){const S=e.now(),$=new l({mode:c}),h=["client"],_=new AbortController,b=c?`--mode ${c}`:"";await $.makeConfig(),await s(),$.clearBuildFolder();const g=$.promisifyProcess(o.spawn(`vite build ${p} --emptyOutDir --outDir ${$.outDir}/client ${b}`,{signal:_.signal,stdio:[process.stdin,"pipe","pipe"],shell:!0,env:{...process.env,FORCE_COLOR:"2",SSR_BOOST_IS_SSR:m?"0":"1",SSR_BOOST_ACTION:global.viteBoostAction}}),v);if(!f){const o=await g.promise;n(o,!0)}let w=null;if(!m){if(w=$.promisifyProcess(o.spawn(`vite build ${d} --emptyOutDir --outDir ${$.outDir}/server --ssr ${$.serverFile} ${b}`,{signal:_.signal,stdio:[process.stdin,"pipe","pipe"],shell:!0,env:{...process.env,FORCE_COLOR:"2",SSR_BOOST_IS_SSR:m?"0":"1",SSR_BOOST_ACTION:global.viteBoostAction}}),v),!f){const o=await w.promise;n(o,!0),await $.buildManifest(),O&&$.eject()}h.push("server")}if(f){process.on("exit",(()=>{_.abort()}));let o=m?1:2;const e=i=>{Buffer.from(i).toString().includes("built in")&&(o-=1,o||(g.command.stdout?.removeListener("data",e),w?.command.stdout?.removeListener("data",e),r($.isProd,$.viteConfig),a?.()))};return g.command.stdout?.on("data",e),void w?.command.stdout?.on("data",e)}u&&$.unlockRobots(),r($.isProd,$.viteConfig),a?.();const C=Math.ceil(e.now()-S),R=C>1e3?(C/1e3).toFixed(2):C,B=C>1e3?"s":"ms",j=i.dim(`${i.yellowBright(h.join(","))} built in ${i.reset(i.bold(R))} ${B}`);console.info(`\n ${i.green(`${i.bold(t.toUpperCase())}`)} ${j} ${$.isProd?"":i.redBright(`NODE_ENV=${$.nodeEnv}`)}\n`)}export{a as default};
|
|
2
2
|
//# sourceMappingURL=build.js.map
|
package/cli/build.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build.js","sources":["../../src/cli/build.ts"],"sourcesContent":["import childProcess from 'node:child_process';\nimport { performance } from 'node:perf_hooks';\nimport chalk from 'chalk';\nimport viteResetCache from '@cli/helpers/vite-reset-cache';\nimport cliName from '@constants/cli-name';\nimport { createDevMarker } from '@helpers/dev-marker';\nimport processStop from '@helpers/process-stop';\nimport Build from '@services/build';\n\ninterface IBuildParams {\n onFinish?: () => void;\n mode?: string;\n clientOptions?: string;\n serverOptions?: string;\n isOnlyClient?: boolean;\n isWatch?: boolean;\n isUnlockRobots?: boolean;\n isEject?: boolean;\n isNoWarnings?: boolean;\n}\n\n/**\n * Build production application\n */\nasync function build({\n onFinish,\n mode = '',\n clientOptions = '',\n serverOptions = '',\n isOnlyClient = false,\n isWatch = false,\n isUnlockRobots = false,\n isEject = false,\n isNoWarnings = false,\n}: IBuildParams): Promise<void> {\n const perfStart = performance.now();\n const buildService = new Build({ mode });\n const types = ['client'];\n const controller = new AbortController();\n const modeOpt = mode ? `--mode ${mode}` : '';\n\n await buildService.makeConfig();\n\n // this is required step - build with different env may cause problems\n await viteResetCache();\n buildService.clearBuildFolder();\n\n /**\n * Build client\n */\n const clientProcess = buildService.promisifyProcess(\n childProcess.spawn(\n `vite build ${clientOptions} --emptyOutDir --outDir ${buildService.outDir}/client ${modeOpt}`,\n {\n signal: controller.signal,\n stdio: [process.stdin, 'pipe', 'pipe'],\n shell: true,\n env: {\n ...process.env,\n FORCE_COLOR: '2',\n SSR_BOOST_IS_SSR: isOnlyClient ? '0' : '1',\n SSR_BOOST_ACTION: global.viteBoostAction,\n },\n },\n ),\n isNoWarnings,\n );\n\n if (!isWatch) {\n const exitCode =
|
|
1
|
+
{"version":3,"file":"build.js","sources":["../../src/cli/build.ts"],"sourcesContent":["import childProcess from 'node:child_process';\nimport { performance } from 'node:perf_hooks';\nimport chalk from 'chalk';\nimport viteResetCache from '@cli/helpers/vite-reset-cache';\nimport cliName from '@constants/cli-name';\nimport { createDevMarker } from '@helpers/dev-marker';\nimport processStop from '@helpers/process-stop';\nimport Build from '@services/build';\n\ninterface IBuildParams {\n onFinish?: () => void;\n mode?: string;\n clientOptions?: string;\n serverOptions?: string;\n isOnlyClient?: boolean;\n isWatch?: boolean;\n isUnlockRobots?: boolean;\n isEject?: boolean;\n isNoWarnings?: boolean;\n}\n\n/**\n * Build production application\n */\nasync function build({\n onFinish,\n mode = '',\n clientOptions = '',\n serverOptions = '',\n isOnlyClient = false,\n isWatch = false,\n isUnlockRobots = false,\n isEject = false,\n isNoWarnings = false,\n}: IBuildParams): Promise<void> {\n const perfStart = performance.now();\n const buildService = new Build({ mode });\n const types = ['client'];\n const controller = new AbortController();\n const modeOpt = mode ? `--mode ${mode}` : '';\n\n await buildService.makeConfig();\n\n // this is required step - build with different env may cause problems\n await viteResetCache();\n buildService.clearBuildFolder();\n\n /**\n * Build client\n */\n const clientProcess = buildService.promisifyProcess(\n childProcess.spawn(\n `vite build ${clientOptions} --emptyOutDir --outDir ${buildService.outDir}/client ${modeOpt}`,\n {\n signal: controller.signal,\n stdio: [process.stdin, 'pipe', 'pipe'],\n shell: true,\n env: {\n ...process.env,\n FORCE_COLOR: '2',\n SSR_BOOST_IS_SSR: isOnlyClient ? '0' : '1',\n SSR_BOOST_ACTION: global.viteBoostAction,\n },\n },\n ),\n isNoWarnings,\n );\n\n if (!isWatch) {\n const exitCode = await clientProcess.promise;\n\n processStop(exitCode, true);\n }\n\n let serverProcess: ReturnType<Build['promisifyProcess']> | null = null;\n\n /**\n * Build server\n */\n if (!isOnlyClient) {\n serverProcess = buildService.promisifyProcess(\n childProcess.spawn(\n `vite build ${serverOptions} --emptyOutDir --outDir ${buildService.outDir}/server --ssr ${buildService.serverFile} ${modeOpt}`,\n {\n signal: controller.signal,\n stdio: [process.stdin, 'pipe', 'pipe'],\n shell: true,\n env: {\n ...process.env,\n FORCE_COLOR: '2',\n SSR_BOOST_IS_SSR: isOnlyClient ? '0' : '1',\n SSR_BOOST_ACTION: global.viteBoostAction,\n },\n },\n ),\n isNoWarnings,\n );\n\n if (!isWatch) {\n const exitCode = await serverProcess.promise;\n\n processStop(exitCode, true);\n await buildService.buildManifest();\n\n if (isEject) {\n buildService.eject();\n }\n }\n\n types.push('server');\n }\n\n /**\n * Preview mode\n */\n if (isWatch) {\n process.on('exit', () => {\n controller.abort();\n });\n\n let buildCount = isOnlyClient ? 1 : 2;\n const listener = (buff: Uint8Array): void => {\n const msg = Buffer.from(buff).toString();\n\n if (msg.includes('built in')) {\n buildCount -= 1;\n\n if (!buildCount) {\n clientProcess.command.stdout?.removeListener('data', listener);\n serverProcess?.command.stdout?.removeListener('data', listener);\n createDevMarker(buildService.isProd, buildService.viteConfig);\n onFinish?.();\n }\n }\n };\n\n /**\n * Listen output for call onFinish\n */\n clientProcess.command.stdout?.on('data', listener);\n serverProcess?.command.stdout?.on('data', listener);\n\n return;\n }\n\n if (isUnlockRobots) {\n buildService.unlockRobots();\n }\n\n createDevMarker(buildService.isProd, buildService.viteConfig);\n onFinish?.();\n\n const durationMs = Math.ceil(performance.now() - perfStart);\n const duration = durationMs > 1000 ? (durationMs / 1000).toFixed(2) : durationMs;\n const units = durationMs > 1000 ? 's' : 'ms';\n\n const buildDurationString = chalk.dim(\n `${chalk.yellowBright(types.join(','))} built in ${chalk.reset(chalk.bold(duration))} ${units}`,\n );\n\n console.info(\n `\\n ${chalk.green(`${chalk.bold(cliName.toUpperCase())}`)} ${buildDurationString} ${\n buildService.isProd ? '' : chalk.redBright(`NODE_ENV=${buildService.nodeEnv}`)\n }\\n`,\n );\n}\n\nexport default build;\n"],"names":["async","build","onFinish","mode","clientOptions","serverOptions","isOnlyClient","isWatch","isUnlockRobots","isEject","isNoWarnings","perfStart","performance","now","buildService","Build","types","controller","AbortController","modeOpt","makeConfig","viteResetCache","clearBuildFolder","clientProcess","promisifyProcess","childProcess","spawn","outDir","signal","stdio","process","stdin","shell","env","FORCE_COLOR","SSR_BOOST_IS_SSR","SSR_BOOST_ACTION","global","viteBoostAction","exitCode","promise","processStop","serverProcess","serverFile","buildManifest","eject","push","on","abort","buildCount","listener","buff","Buffer","from","toString","includes","command","stdout","removeListener","createDevMarker","isProd","viteConfig","unlockRobots","durationMs","Math","ceil","duration","toFixed","units","buildDurationString","chalk","dim","yellowBright","join","reset","bold","console","info","green","cliName","toUpperCase","redBright","nodeEnv"],"mappings":"mUAwBAA,eAAeC,GAAMC,SACnBA,EAAQC,KACRA,EAAO,GAAEC,cACTA,EAAgB,GAAEC,cAClBA,EAAgB,GAAEC,aAClBA,GAAe,EAAKC,QACpBA,GAAU,EAAKC,eACfA,GAAiB,EAAKC,QACtBA,GAAU,EAAKC,aACfA,GAAe,IAEf,MAAMC,EAAYC,EAAYC,MACxBC,EAAe,IAAIC,EAAM,CAAEZ,SAC3Ba,EAAQ,CAAC,UACTC,EAAa,IAAIC,gBACjBC,EAAUhB,EAAO,UAAUA,IAAS,SAEpCW,EAAaM,mBAGbC,IACNP,EAAaQ,mBAKb,MAAMC,EAAgBT,EAAaU,iBACjCC,EAAaC,MACX,cAActB,4BAAwCU,EAAaa,iBAAiBR,IACpF,CACES,OAAQX,EAAWW,OACnBC,MAAO,CAACC,QAAQC,MAAO,OAAQ,QAC/BC,OAAO,EACPC,IAAK,IACAH,QAAQG,IACXC,YAAa,IACbC,iBAAkB7B,EAAe,IAAM,IACvC8B,iBAAkBC,OAAOC,mBAI/B5B,GAGF,IAAKH,EAAS,CACZ,MAAMgC,QAAiBhB,EAAciB,QAErCC,EAAYF,GAAU,EACvB,CAED,IAAIG,EAA8D,KAKlE,IAAKpC,EAAc,CAmBjB,GAlBAoC,EAAgB5B,EAAaU,iBAC3BC,EAAaC,MACX,cAAcrB,4BAAwCS,EAAaa,uBAAuBb,EAAa6B,cAAcxB,IACrH,CACES,OAAQX,EAAWW,OACnBC,MAAO,CAACC,QAAQC,MAAO,OAAQ,QAC/BC,OAAO,EACPC,IAAK,IACAH,QAAQG,IACXC,YAAa,IACbC,iBAAkB7B,EAAe,IAAM,IACvC8B,iBAAkBC,OAAOC,mBAI/B5B,IAGGH,EAAS,CACZ,MAAMgC,QAAiBG,EAAcF,QAErCC,EAAYF,GAAU,SAChBzB,EAAa8B,gBAEfnC,GACFK,EAAa+B,OAEhB,CAED7B,EAAM8B,KAAK,SACZ,CAKD,GAAIvC,EAAS,CACXuB,QAAQiB,GAAG,QAAQ,KACjB9B,EAAW+B,OAAO,IAGpB,IAAIC,EAAa3C,EAAe,EAAI,EACpC,MAAM4C,EAAYC,IACJC,OAAOC,KAAKF,GAAMG,WAEtBC,SAAS,cACfN,GAAc,EAETA,IACH1B,EAAciC,QAAQC,QAAQC,eAAe,OAAQR,GACrDR,GAAec,QAAQC,QAAQC,eAAe,OAAQR,GACtDS,EAAgB7C,EAAa8C,OAAQ9C,EAAa+C,YAClD3D,OAEH,EASH,OAHAqB,EAAciC,QAAQC,QAAQV,GAAG,OAAQG,QACzCR,GAAec,QAAQC,QAAQV,GAAG,OAAQG,EAG3C,CAEG1C,GACFM,EAAagD,eAGfH,EAAgB7C,EAAa8C,OAAQ9C,EAAa+C,YAClD3D,MAEA,MAAM6D,EAAaC,KAAKC,KAAKrD,EAAYC,MAAQF,GAC3CuD,EAAWH,EAAa,KAAQA,EAAa,KAAMI,QAAQ,GAAKJ,EAChEK,EAAQL,EAAa,IAAO,IAAM,KAElCM,EAAsBC,EAAMC,IAChC,GAAGD,EAAME,aAAaxD,EAAMyD,KAAK,kBAAkBH,EAAMI,MAAMJ,EAAMK,KAAKT,OAAcE,KAG1FQ,QAAQC,KACN,OAAOP,EAAMQ,MAAM,GAAGR,EAAMK,KAAKI,EAAQC,sBAAsBX,KAC7DvD,EAAa8C,OAAS,GAAKU,EAAMW,UAAU,YAAYnE,EAAaoE,eAG1E"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Get server state on the client side
|
|
3
3
|
*/
|
|
4
|
-
declare const getServerState: (name: string, shouldRemove?: boolean) =>
|
|
4
|
+
declare const getServerState: <TP = Record<string, any>>(name: string, shouldRemove?: boolean) => TP;
|
|
5
5
|
export { getServerState as default };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get-server-state.js","sources":["../../src/helpers/get-server-state.ts"],"sourcesContent":["/**\n * Get server state on the client side\n */\nconst getServerState = (name: string, shouldRemove = true):
|
|
1
|
+
{"version":3,"file":"get-server-state.js","sources":["../../src/helpers/get-server-state.ts"],"sourcesContent":["/**\n * Get server state on the client side\n */\nconst getServerState = <TP = Record<string, any>>(name: string, shouldRemove = true): TP => {\n const data = (window as Record<any, any>)[name] as TP;\n\n if (shouldRemove && data) {\n delete (window as Record<any, any>)[name];\n }\n\n return (data ?? {}) as TP;\n};\n\nexport default getServerState;\n"],"names":["getServerState","name","shouldRemove","data","window"],"mappings":"AAGM,MAAAA,EAAiB,CAA2BC,EAAcC,GAAe,KAC7E,MAAMC,EAAQC,OAA4BH,GAM1C,OAJIC,GAAgBC,UACVC,OAA4BH,GAG9BE,GAAQ,CAAA,CAAU"}
|
|
@@ -244,7 +244,9 @@ declare const redirect: RedirectFunction;
|
|
|
244
244
|
type IDynamicRoute = () => Promise<{
|
|
245
245
|
default: FCRoute | FCCRoute<any>;
|
|
246
246
|
}>;
|
|
247
|
-
type IAsyncRoute =
|
|
247
|
+
type IAsyncRoute = {
|
|
248
|
+
pathId?: string;
|
|
249
|
+
} & (Omit<IndexRouteObject, ImmutableRouteKey> | Omit<NonIndexRouteObject, ImmutableRouteKey>);
|
|
248
250
|
/**
|
|
249
251
|
* Import dynamic route
|
|
250
252
|
*/
|
package/helpers/import-route.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import t from"../components/with-suspense.js";import{keys as
|
|
1
|
+
import t from"../components/with-suspense.js";import{keys as n}from"../interfaces/fc-route.js";const e=async(e,o)=>{const s=await e();if("Component"in s)return{...s,pathId:o};const p=s.default,r={Component:p,pathId:o};return n.forEach((t=>{p[t]&&(r[t]=p[t])})),p.Suspense&&(r.Component=t(p,p.Suspense)),r};export{e as default};
|
|
2
2
|
//# sourceMappingURL=import-route.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"import-route.js","sources":["../../src/helpers/import-route.ts"],"sourcesContent":["import type { ImmutableRouteKey } from '@remix-run/router/utils';\nimport type { IndexRouteObject, NonIndexRouteObject } from 'react-router-dom';\nimport withSuspense from '@components/with-suspense';\nimport type { FCCRoute, FCRoute } from '@interfaces/fc-route';\nimport { keys } from '@interfaces/fc-route';\n\nexport type IDynamicRoute = () => Promise<{ default: FCRoute | FCCRoute<any> }>;\n\nexport type IAsyncRoute
|
|
1
|
+
{"version":3,"file":"import-route.js","sources":["../../src/helpers/import-route.ts"],"sourcesContent":["import type { ImmutableRouteKey } from '@remix-run/router/utils';\nimport type { IndexRouteObject, NonIndexRouteObject } from 'react-router-dom';\nimport withSuspense from '@components/with-suspense';\nimport type { FCCRoute, FCRoute } from '@interfaces/fc-route';\nimport { keys } from '@interfaces/fc-route';\n\nexport type IDynamicRoute = () => Promise<{ default: FCRoute | FCCRoute<any> }>;\n\nexport type IAsyncRoute = { pathId?: string } & (\n | Omit<IndexRouteObject, ImmutableRouteKey>\n | Omit<NonIndexRouteObject, ImmutableRouteKey>\n);\n\n/**\n * Import dynamic route\n */\nconst importRoute = async (route: IDynamicRoute, id?: string): Promise<IAsyncRoute> => {\n const resolved = await route();\n\n // fallback to react router export style\n if ('Component' in resolved) {\n return { ...resolved, pathId: id } as IAsyncRoute;\n }\n\n const Component = resolved.default;\n const result: IAsyncRoute = { Component, pathId: id };\n\n keys.forEach((key) => {\n if (Component[key]) {\n result[key] = Component[key] as any;\n }\n });\n\n if (Component.Suspense) {\n result.Component = withSuspense(Component, Component.Suspense);\n }\n\n return result;\n};\n\nexport default importRoute;\n"],"names":["importRoute","async","route","id","resolved","pathId","Component","default","result","keys","forEach","key","Suspense","withSuspense"],"mappings":"+FAgBM,MAAAA,EAAcC,MAAOC,EAAsBC,KAC/C,MAAMC,QAAiBF,IAGvB,GAAI,cAAeE,EACjB,MAAO,IAAKA,EAAUC,OAAQF,GAGhC,MAAMG,EAAYF,EAASG,QACrBC,EAAsB,CAAEF,YAAWD,OAAQF,GAYjD,OAVAM,EAAKC,SAASC,IACRL,EAAUK,KACZH,EAAOG,GAAOL,EAAUK,GACzB,IAGCL,EAAUM,WACZJ,EAAOF,UAAYO,EAAaP,EAAWA,EAAUM,WAGhDJ,CAAM"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"obtain-stream-error.js","sources":["../../src/helpers/obtain-stream-error.ts"],"sourcesContent":["import StreamError from '@constants/stream-error';\n\nexport interface IObtainStreamErrorOut {\n code: StreamError;\n message: string;\n original: unknown;\n}\n\n/**\n * Get react stream error\n */\nconst obtainStreamError = (err: unknown): IObtainStreamErrorOut => {\n const message = (err?.
|
|
1
|
+
{"version":3,"file":"obtain-stream-error.js","sources":["../../src/helpers/obtain-stream-error.ts"],"sourcesContent":["import StreamError from '@constants/stream-error';\n\nexport interface IObtainStreamErrorOut {\n code: StreamError;\n message: string;\n original: unknown;\n}\n\n/**\n * Get react stream error\n */\nconst obtainStreamError = (err: unknown): IObtainStreamErrorOut => {\n const message = ((err as Record<string, any>)?.message ?? 'Unknown.').replace('Error: ', '');\n\n if (message === 'The render was aborted by the server without a reason.') {\n return {\n code: StreamError.RenderAborted,\n message,\n original: err,\n };\n }\n\n return {\n code: StreamError.Unknown,\n message: message || 'Unknown error',\n original: err,\n };\n};\n\nexport default obtainStreamError;\n"],"names":["obtainStreamError","err","message","replace","code","StreamError","RenderAborted","original","Unknown"],"mappings":"4CAWA,MAAMA,EAAqBC,IACzB,MAAMC,GAAYD,GAA6BC,SAAW,YAAYC,QAAQ,UAAW,IAEzF,MAAgB,2DAAZD,EACK,CACLE,KAAMC,EAAYC,cAClBJ,UACAK,SAAUN,GAIP,CACLG,KAAMC,EAAYG,QAClBN,QAASA,GAAW,gBACpBK,SAAUN,EACX"}
|
package/helpers/plugin-config.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import n from"../constants/plugin-name.js";function t(t){const o=t.plugins.find((t=>t.name===n))?.pluginOptions;if(!
|
|
1
|
+
import n from"../constants/plugin-name.js";function t(t){const o=t.plugins.find((t=>t.name===n)),i=o?.pluginOptions;if(!i)throw new Error(`Failed to get to plugin config. Make sure you add the plugin '${n}' to the VITE config.`);return i}export{t as default};
|
|
2
2
|
//# sourceMappingURL=plugin-config.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin-config.js","sources":["../../src/helpers/plugin-config.ts"],"sourcesContent":["import type { ResolvedConfig } from 'vite';\nimport type CliActions from '@constants/cli-actions';\nimport PLUGIN_NAME from '@constants/plugin-name';\nimport type { IPluginOptions } from '../plugin';\n\nexport interface IPluginConfig extends Required<IPluginOptions> {\n pluginPath: string;\n action: CliActions;\n isDev: boolean;\n}\n\n/**\n * Get plugin config from vite config\n */\nfunction getPluginConfig(viteConfig: ResolvedConfig): IPluginConfig {\n const
|
|
1
|
+
{"version":3,"file":"plugin-config.js","sources":["../../src/helpers/plugin-config.ts"],"sourcesContent":["import type { ResolvedConfig } from 'vite';\nimport type CliActions from '@constants/cli-actions';\nimport PLUGIN_NAME from '@constants/plugin-name';\nimport type { IPluginOptions } from '../plugin';\n\nexport interface IPluginConfig extends Required<IPluginOptions> {\n pluginPath: string;\n action: CliActions;\n isDev: boolean;\n}\n\n/**\n * Get plugin config from vite config\n */\nfunction getPluginConfig(viteConfig: ResolvedConfig): IPluginConfig {\n const pluginConfig = viteConfig.plugins.find(\n (plugin) => plugin.name === PLUGIN_NAME,\n ) as ResolvedConfig['plugins'][number] & { pluginOptions?: IPluginConfig };\n const pluginOptions = pluginConfig?.pluginOptions;\n\n if (!pluginOptions) {\n throw new Error(\n `Failed to get to plugin config. Make sure you add the plugin '${PLUGIN_NAME}' to the VITE config.`,\n );\n }\n\n return pluginOptions;\n}\n\nexport default getPluginConfig;\n"],"names":["getPluginConfig","viteConfig","pluginConfig","plugins","find","plugin","name","PLUGIN_NAME","pluginOptions","Error"],"mappings":"2CAcA,SAASA,EAAgBC,GACvB,MAAMC,EAAeD,EAAWE,QAAQC,MACrCC,GAAWA,EAAOC,OAASC,IAExBC,EAAgBN,GAAcM,cAEpC,IAAKA,EACH,MAAM,IAAIC,MACR,iEAAiEF,0BAIrE,OAAOC,CACT"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"print-server-info.js","sources":["../../src/helpers/print-server-info.ts"],"sourcesContent":["import fs from 'node:fs';\nimport type { Server } from 'node:net';\nimport { performance } from 'node:perf_hooks';\nimport chalk from 'chalk';\nimport CliActions from '@constants/cli-actions';\nimport cliName from '@constants/cli-name';\nimport { getMarkerFile } from '@helpers/dev-marker';\nimport printServerUrls from '@helpers/print-server-urls';\nimport resolveServerUrls from '@helpers/resolve-server-urls';\nimport type ServerConfig from '@services/server-config';\n\ninterface IPrintServerInfoParams {\n version?: string;\n}\n\n/**\n * Print server info\n */\nasync function printServerInfo(\n server: Server,\n config: ServerConfig,\n { version = 'unknown' }: IPrintServerInfoParams,\n): Promise<void> {\n const { action } = config.getPluginConfig() ?? {};\n const { isProd, host, root } = config.getParams();\n const devMarker = getMarkerFile(root);\n\n const Logger = config.getLogger();\n const perfStart = global.viteBoostStartTime ?? performance.now();\n const startupDurationString = chalk.dim(\n `ready in ${chalk.reset(chalk.bold(Math.ceil(performance.now() - perfStart)))} ms`,\n );\n\n Logger.info(\n `\\n ${chalk.green(\n `${chalk.bold(cliName.toUpperCase())} v${version}`,\n )} ${startupDurationString}\\n`,\n { clear: !Logger.hasWarned },\n );\n\n const viteConfig = config.getVite()?.config;\n const isProdBuild = !viteConfig?.mode && !fs.existsSync(devMarker);\n const resolvedUrls = await resolveServerUrls(server, {\n host,\n isHttps: typeof viteConfig?.server.https === 'boolean' ? viteConfig?.server.https : false,\n rawBase: viteConfig?.
|
|
1
|
+
{"version":3,"file":"print-server-info.js","sources":["../../src/helpers/print-server-info.ts"],"sourcesContent":["import fs from 'node:fs';\nimport type { Server } from 'node:net';\nimport { performance } from 'node:perf_hooks';\nimport chalk from 'chalk';\nimport type { ResolvedConfig } from 'vite';\nimport CliActions from '@constants/cli-actions';\nimport cliName from '@constants/cli-name';\nimport { getMarkerFile } from '@helpers/dev-marker';\nimport printServerUrls from '@helpers/print-server-urls';\nimport resolveServerUrls from '@helpers/resolve-server-urls';\nimport type ServerConfig from '@services/server-config';\n\ninterface IPrintServerInfoParams {\n version?: string;\n}\n\n/**\n * Print server info\n */\nasync function printServerInfo(\n server: Server,\n config: ServerConfig,\n { version = 'unknown' }: IPrintServerInfoParams,\n): Promise<void> {\n const { action } = config.getPluginConfig() ?? {};\n const { isProd, host, root } = config.getParams();\n const devMarker = getMarkerFile(root);\n\n const Logger = config.getLogger();\n const perfStart = global.viteBoostStartTime ?? performance.now();\n const startupDurationString = chalk.dim(\n `ready in ${chalk.reset(chalk.bold(Math.ceil(performance.now() - perfStart)))} ms`,\n );\n\n Logger.info(\n `\\n ${chalk.green(\n `${chalk.bold(cliName.toUpperCase())} v${version}`,\n )} ${startupDurationString}\\n`,\n { clear: !Logger.hasWarned },\n );\n\n const viteConfig = config.getVite()?.config as\n | (ResolvedConfig & { rawBase?: string })\n | undefined;\n const isProdBuild = !viteConfig?.mode && !fs.existsSync(devMarker);\n const resolvedUrls = await resolveServerUrls(server, {\n host,\n isHttps: typeof viteConfig?.server.https === 'boolean' ? viteConfig?.server.https : false,\n rawBase: viteConfig?.rawBase,\n });\n const mode =\n viteConfig?.mode || isProdBuild\n ? config.mode\n : `production ${chalk.red('NODE_ENV=development')}`;\n\n Logger.info(chalk.dim(chalk.green(' ➜')) + chalk.dim(' Mode: ') + chalk.blue(mode));\n\n if (!isProd) {\n const vite = config.getVite()!;\n\n vite.resolvedUrls = resolvedUrls;\n vite.printUrls();\n } else {\n printServerUrls(resolvedUrls, (msg) => Logger.info(msg));\n }\n\n if (action === CliActions.dev) {\n Logger.info(\n chalk.dim(chalk.green(' ➜')) +\n chalk.dim(' press ') +\n chalk.bold('h') +\n chalk.dim(' to show help'),\n );\n }\n}\n\nexport default printServerInfo;\n"],"names":["async","printServerInfo","server","config","version","action","getPluginConfig","isProd","host","root","getParams","devMarker","getMarkerFile","Logger","getLogger","perfStart","global","viteBoostStartTime","performance","now","startupDurationString","chalk","dim","reset","bold","Math","ceil","info","green","cliName","toUpperCase","clear","hasWarned","viteConfig","getVite","isProdBuild","mode","fs","existsSync","resolvedUrls","resolveServerUrls","isHttps","https","rawBase","red","blue","printServerUrls","msg","vite","printUrls","CliActions","dev"],"mappings":"2SAmBAA,eAAeC,EACbC,EACAC,GACAC,QAAEA,EAAU,YAEZ,MAAMC,OAAEA,GAAWF,EAAOG,mBAAqB,CAAA,GACzCC,OAAEA,EAAMC,KAAEA,EAAIC,KAAEA,GAASN,EAAOO,YAChCC,EAAYC,EAAcH,GAE1BI,EAASV,EAAOW,YAChBC,EAAYC,OAAOC,oBAAsBC,EAAYC,MACrDC,EAAwBC,EAAMC,IAClC,YAAYD,EAAME,MAAMF,EAAMG,KAAKC,KAAKC,KAAKR,EAAYC,MAAQJ,WAGnEF,EAAOc,KACL,OAAON,EAAMO,MACX,GAAGP,EAAMG,KAAKK,EAAQC,mBAAmB1B,SACrCgB,MACN,CAAEW,OAAQlB,EAAOmB,YAGnB,MAAMC,EAAa9B,EAAO+B,WAAW/B,OAG/BgC,GAAeF,GAAYG,OAASC,EAAGC,WAAW3B,GAClD4B,QAAqBC,EAAkBtC,EAAQ,CACnDM,OACAiC,QAA6C,kBAA7BR,GAAY/B,OAAOwC,OAAsBT,GAAY/B,OAAOwC,MAC5EC,QAASV,GAAYU,UAEjBP,EACJH,GAAYG,MAAQD,EAChBhC,EAAOiC,KACP,cAAcf,EAAMuB,IAAI,0BAI9B,GAFA/B,EAAOc,KAAKN,EAAMC,IAAID,EAAMO,MAAM,QAAUP,EAAMC,IAAI,eAAiBD,EAAMwB,KAAKT,IAE7E7B,EAMHuC,EAAgBP,GAAeQ,GAAQlC,EAAOc,KAAKoB,SANxC,CACX,MAAMC,EAAO7C,EAAO+B,UAEpBc,EAAKT,aAAeA,EACpBS,EAAKC,WACN,CAIG5C,IAAW6C,EAAWC,KACxBtC,EAAOc,KACLN,EAAMC,IAAID,EAAMO,MAAM,QACpBP,EAAMC,IAAI,YACVD,EAAMG,KAAK,KACXH,EAAMC,IAAI,iBAGlB"}
|
package/helpers/process-stop.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import o from"node:process";const e=(e=0,
|
|
1
|
+
import o from"node:process";const e=(e=0,r=!1)=>{if(!r||0!==e&&null!==e)return"string"==typeof e?(console.error(e),o.exit(1)):void o.exit(null===e?0:e)};export{e as default};
|
|
2
2
|
//# sourceMappingURL=process-stop.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"process-stop.js","sources":["../../src/helpers/process-stop.ts"],"sourcesContent":["import process from 'node:process';\n\n/**\n * Stop node process\n */\nconst processStop = (code = 0, isOnlyError = false) => {\n if (isOnlyError && code === 0) {\n return;\n }\n\n process.exit(code);\n};\n\nexport default processStop;\n"],"names":["processStop","code","isOnlyError","process","exit"],"mappings":"4BAKM,MAAAA,EAAc,CAACC,
|
|
1
|
+
{"version":3,"file":"process-stop.js","sources":["../../src/helpers/process-stop.ts"],"sourcesContent":["import process from 'node:process';\n\n/**\n * Stop node process\n */\nconst processStop = (code: number | string | null = 0, isOnlyError = false): void => {\n if (isOnlyError && (code === 0 || code === null)) {\n return;\n }\n\n if (typeof code === 'string') {\n console.error(code);\n\n return process.exit(1);\n }\n\n process.exit(code === null ? 0 : code);\n};\n\nexport default processStop;\n"],"names":["processStop","code","isOnlyError","console","error","process","exit"],"mappings":"4BAKM,MAAAA,EAAc,CAACC,EAA+B,EAAGC,GAAc,KACnE,IAAIA,GAAyB,IAATD,GAAuB,OAATA,EAIlC,MAAoB,iBAATA,GACTE,QAAQC,MAAMH,GAEPI,EAAQC,KAAK,SAGtBD,EAAQC,KAAc,OAATL,EAAgB,EAAIA,EAAK"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
function e(e){const o=`${e.protocol}://${e.get("host")}`,t=new URL(e.originalUrl||e.url,o),r=new AbortController;e.on("close",(()=>r.abort()));const n=new Headers;for(const[o,t]of Object.entries(e.headers))if(t)if(Array.isArray(t))for(const e of t)n.append(o,e);else n.set(o,t);const s={method:e.method,headers:n,signal:r.signal};return"GET"!==e.method&&"HEAD"!==e.method&&(s.body=e.body),new Request(t.href,s)}export{e as default};
|
|
1
|
+
function e(e){const o=`${e.protocol}://${e.get("host")}`,t=new URL(e.originalUrl||e.url,o),r=new AbortController;e.on("close",(()=>r.abort()));const n=new Headers;for(const[o,t]of Object.entries(e.headers))if(t)if(Array.isArray(t))for(const e of t)n.append(o,e);else n.set(o,t);const s={method:e.method,headers:n,signal:r.signal,body:void 0};return"GET"!==e.method&&"HEAD"!==e.method&&(s.body=e.body),new Request(t.href,s)}export{e as default};
|
|
2
2
|
//# sourceMappingURL=create-fetch-request.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-fetch-request.js","sources":["../../src/node/create-fetch-request.ts"],"sourcesContent":["import type { Request as ExpressRequest } from 'express';\n\n/**\n * Convert the incoming Express request into a Fetch request, which is what the static handler methods operate on.\n * @see https://reactrouter.com/en/main/guides/ssr\n */\nfunction createFetchRequest(req: ExpressRequest): Request {\n const origin = `${req.protocol}://${req.get('host') as string}`;\n // Note: This had to take originalUrl into account for presumably vite's proxying\n const url = new URL(req.originalUrl || req.url, origin);\n const controller = new AbortController();\n\n req.on('close', () => controller.abort());\n\n const headers = new Headers();\n\n for (const [key, values] of Object.entries(req.headers)) {\n if (values) {\n if (Array.isArray(values)) {\n for (const value of values) {\n headers.append(key, value);\n }\n } else {\n headers.set(key, values);\n }\n }\n }\n\n const init = {\n method: req.method,\n headers,\n signal: controller.signal,\n };\n\n if (req.method !== 'GET' && req.method !== 'HEAD') {\n init
|
|
1
|
+
{"version":3,"file":"create-fetch-request.js","sources":["../../src/node/create-fetch-request.ts"],"sourcesContent":["import type { Request as ExpressRequest } from 'express';\n\n/**\n * Convert the incoming Express request into a Fetch request, which is what the static handler methods operate on.\n * @see https://reactrouter.com/en/main/guides/ssr\n */\nfunction createFetchRequest(req: ExpressRequest): Request {\n const origin = `${req.protocol}://${req.get('host') as string}`;\n // Note: This had to take originalUrl into account for presumably vite's proxying\n const url = new URL(req.originalUrl || req.url, origin);\n const controller = new AbortController();\n\n req.on('close', () => controller.abort());\n\n const headers = new Headers();\n\n for (const [key, values] of Object.entries(req.headers)) {\n if (values) {\n if (Array.isArray(values)) {\n for (const value of values) {\n headers.append(key, value);\n }\n } else {\n headers.set(key, values);\n }\n }\n }\n\n const init = {\n method: req.method,\n headers,\n signal: controller.signal,\n body: undefined,\n };\n\n if (req.method !== 'GET' && req.method !== 'HEAD') {\n init.body = req.body;\n }\n\n return new Request(url.href, init);\n}\n\nexport default createFetchRequest;\n"],"names":["createFetchRequest","req","origin","protocol","get","url","URL","originalUrl","controller","AbortController","on","abort","headers","Headers","key","values","Object","entries","Array","isArray","value","append","set","init","method","signal","body","undefined","Request","href"],"mappings":"AAMA,SAASA,EAAmBC,GAC1B,MAAMC,EAAS,GAAGD,EAAIE,cAAcF,EAAIG,IAAI,UAEtCC,EAAM,IAAIC,IAAIL,EAAIM,aAAeN,EAAII,IAAKH,GAC1CM,EAAa,IAAIC,gBAEvBR,EAAIS,GAAG,SAAS,IAAMF,EAAWG,UAEjC,MAAMC,EAAU,IAAIC,QAEpB,IAAK,MAAOC,EAAKC,KAAWC,OAAOC,QAAQhB,EAAIW,SAC7C,GAAIG,EACF,GAAIG,MAAMC,QAAQJ,GAChB,IAAK,MAAMK,KAASL,EAClBH,EAAQS,OAAOP,EAAKM,QAGtBR,EAAQU,IAAIR,EAAKC,GAKvB,MAAMQ,EAAO,CACXC,OAAQvB,EAAIuB,OACZZ,UACAa,OAAQjB,EAAWiB,OACnBC,UAAMC,GAOR,MAJmB,QAAf1B,EAAIuB,QAAmC,SAAfvB,EAAIuB,SAC9BD,EAAKG,KAAOzB,EAAIyB,MAGX,IAAIE,QAAQvB,EAAIwB,KAAMN,EAC/B"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lomray/vite-ssr-boost",
|
|
3
|
-
"version": "1.0.2",
|
|
3
|
+
"version": "1.1.0-beta.2",
|
|
4
4
|
"description": "Vite plugin for create awesome SSR or SPA applications on React.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"keywords": [
|
|
@@ -29,50 +29,64 @@
|
|
|
29
29
|
"release": "npm run build && cd lib && npm publish",
|
|
30
30
|
"lint:check": "eslint --ext \".ts,.tsx\" \"src/**/*.{ts,tsx,*.ts,*tsx}\"",
|
|
31
31
|
"lint:format": "eslint --fix --ext \".ts,.tsx\" \"src/**/*.{ts,tsx,*.ts,*tsx}\"",
|
|
32
|
-
"ts:check": "tsc --project ./tsconfig.json --skipLibCheck --noemit"
|
|
32
|
+
"ts:check": "tsc --project ./tsconfig.json --skipLibCheck --noemit",
|
|
33
|
+
"test": "mocha --no-warnings __tests__ --recursive --unhandled-rejections=strict --exit",
|
|
34
|
+
"test:watch": "mocha --no-warnings __tests__ --recursive --unhandled-rejections=strict"
|
|
33
35
|
},
|
|
34
36
|
"dependencies": {
|
|
35
|
-
"chalk": "^5.
|
|
36
|
-
"commander": "^
|
|
37
|
+
"chalk": "^5.3.0",
|
|
38
|
+
"commander": "^11.1.0",
|
|
37
39
|
"compression": "^1.7.4",
|
|
38
40
|
"express": "^4.18.2",
|
|
39
41
|
"hjson": "^3.2.2",
|
|
40
42
|
"hoist-non-react-statics": "^3.3.2"
|
|
41
43
|
},
|
|
42
44
|
"devDependencies": {
|
|
43
|
-
"@commitlint/cli": "^
|
|
44
|
-
"@commitlint/config-conventional": "^
|
|
45
|
-
"@lomray/eslint-config": "^
|
|
45
|
+
"@commitlint/cli": "^18.4.3",
|
|
46
|
+
"@commitlint/config-conventional": "^18.4.3",
|
|
47
|
+
"@lomray/eslint-config": "^4.0.1",
|
|
46
48
|
"@lomray/prettier-config": "^1.2.0",
|
|
47
|
-
"@rollup/plugin-terser": "^0.4.
|
|
48
|
-
"@types/
|
|
49
|
-
"@types/
|
|
50
|
-
"@types/
|
|
49
|
+
"@rollup/plugin-terser": "^0.4.4",
|
|
50
|
+
"@types/chai": "^4.3.11",
|
|
51
|
+
"@types/compression": "^1.7.5",
|
|
52
|
+
"@types/hjson": "^2.4.6",
|
|
53
|
+
"@types/hoist-non-react-statics": "^3.3.5",
|
|
54
|
+
"@types/mocha": "^10.0.6",
|
|
51
55
|
"@types/react-dom": "^18.2.5",
|
|
52
|
-
"@
|
|
56
|
+
"@types/sinon": "^17.0.2",
|
|
57
|
+
"@types/sinon-chai": "^3.2.12",
|
|
58
|
+
"@typescript-eslint/eslint-plugin": "^6.12.0",
|
|
53
59
|
"@zerollup/ts-transform-paths": "^1.7.18",
|
|
54
|
-
"
|
|
55
|
-
"
|
|
56
|
-
"eslint
|
|
57
|
-
"eslint-
|
|
58
|
-
"eslint-plugin-
|
|
60
|
+
"c8": "^8.0.1",
|
|
61
|
+
"chai": "^4.3.10",
|
|
62
|
+
"eslint": "^8.54.0",
|
|
63
|
+
"eslint-config-prettier": "^9.0.0",
|
|
64
|
+
"eslint-plugin-import": "^2.29.0",
|
|
65
|
+
"eslint-plugin-jsx-a11y": "^6.8.0",
|
|
66
|
+
"eslint-plugin-prettier": "^5.0.1",
|
|
59
67
|
"husky": "^8.0.3",
|
|
60
|
-
"lint-staged": "^
|
|
61
|
-
"
|
|
68
|
+
"lint-staged": "^15.1.0",
|
|
69
|
+
"mocha": "^10.2.0",
|
|
70
|
+
"nodemon": "^3.0.1",
|
|
71
|
+
"prettier": "^3.1.0",
|
|
62
72
|
"rollup": "^3.25.1",
|
|
63
|
-
"rollup-plugin-copy": "^3.
|
|
73
|
+
"rollup-plugin-copy": "^3.5.0",
|
|
64
74
|
"rollup-plugin-folder-input": "^1.0.1",
|
|
65
75
|
"rollup-plugin-peer-deps-external": "^2.2.4",
|
|
66
76
|
"rollup-plugin-preserve-shebangs": "^0.2.0",
|
|
67
|
-
"rollup-plugin-ts": "^3.
|
|
68
|
-
"semantic-release": "^21.
|
|
69
|
-
"
|
|
77
|
+
"rollup-plugin-ts": "^3.4.5",
|
|
78
|
+
"semantic-release": "^21.1.2",
|
|
79
|
+
"sinon": "^17.0.1",
|
|
80
|
+
"sinon-chai": "^3.7.0",
|
|
81
|
+
"ts-node": "^10.9.1",
|
|
82
|
+
"tsconfig-paths": "^4.2.0",
|
|
83
|
+
"typescript": "^5.3.2"
|
|
70
84
|
},
|
|
71
85
|
"peerDependencies": {
|
|
72
|
-
"@types/express": "^4.17.
|
|
86
|
+
"@types/express": "^4.17.21",
|
|
73
87
|
"react-dom": ">=18.2.0",
|
|
74
88
|
"react-router-dom": ">=6.12.1",
|
|
75
|
-
"vite": "^4.
|
|
89
|
+
"vite": "^4.5.0"
|
|
76
90
|
},
|
|
77
91
|
"bin": {
|
|
78
92
|
"ssr-boost": "cli.js"
|
package/plugin.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
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||
|
|
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||p===i.dev,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 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 ===
|
|
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 === CliActions.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","CliActions","dev","isBuild","build","plugins","name","PLUGIN_NAME","enforce","pluginOptions","pluginPath","path","dirname","pathname","isDev","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,kBAA4BR,IAAWS,EAAWC,IACtEC,EAAUX,IAAWS,EAAWG,MAEhCC,EAAoB,CACxB,CACEC,KAAMC,EACNC,QAAS,MAETC,cAAe,IACVX,EACHY,WAAYC,EAAKC,QAAQvB,EAAQwB,UACjCrB,SACAsB,MAAOtB,IAAWS,EAAWC,KAG/Ba,OAAM,CAACA,GAAQC,SAAEA,MACfD,EAAOE,OAAS,IACVF,EAAOE,QAAU,GACrBC,WAAYnB,GAGdgB,EAAOX,MAAQ,IACTW,EAAOX,OAAS,IAIjBY,EAQE,IACFD,KACCZ,EAAU,CAAEgB,QAAS,UAAa,CAAA,EACtCC,WAAW,IAVPrB,GAASI,IACXY,EAAOX,MAAOiB,UAAW,GAGpBN,OAYT7B,gBAAEA,GAAoBY,EAU5B,OARIZ,GACFmB,EAAQiB,KACNC,EAAiD,kBAApBrC,OAAgCsC,EAAYtC,IAI7EmB,EAAQiB,KAAKG,EAA0B,CAAE1B,WAElCM,CACT"}
|
package/services/build.d.ts
CHANGED
|
@@ -68,7 +68,10 @@ declare class Build {
|
|
|
68
68
|
/**
|
|
69
69
|
* Promisify spawn process
|
|
70
70
|
*/
|
|
71
|
-
promisifyProcess(command: childProcess.ChildProcess, isRejectWarnings?: boolean):
|
|
71
|
+
promisifyProcess(command: childProcess.ChildProcess, isRejectWarnings?: boolean): {
|
|
72
|
+
promise: Promise<number | null | string>;
|
|
73
|
+
command: childProcess.ChildProcess;
|
|
74
|
+
};
|
|
72
75
|
/**
|
|
73
76
|
* Build assets manifest file
|
|
74
77
|
*/
|
package/services/build.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import i from"node:fs";import o from"node:path";import t from"chalk";import{resolveConfig as s}from"vite";import
|
|
1
|
+
import i from"node:fs";import o from"node:path";import t from"chalk";import{resolveConfig as s}from"vite";import r from"../helpers/plugin-config.js";import n from"./server-config.js";import e 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"),this.pluginConfig=r(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||"production",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),{promise:t,command:i}}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 e.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
2
|
//# sourceMappingURL=build.js.map
|
package/services/build.js.map
CHANGED
|
@@ -1 +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({}, 'build', mode, 'production');\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 || 'production';\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<
|
|
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({}, 'build', mode, 'production');\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 || 'production';\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: Promise<number | null | string>; command: childProcess.ChildProcess } {\n const promise = new Promise<number | null | string>((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 return { promise, command };\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,EAAc,CAAE,EAAE,QAASD,EAAM,cACzDF,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,aACvCX,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,SAAgC,CAACf,EAASgB,KAC5DJ,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,IAMH,OAHAY,EAAQe,QAAQC,KAAKzB,QAAQwB,QAC7Bf,EAAQQ,QAAQQ,KAAKzB,QAAQiB,QAEtB,CAAEN,UAASF,UACnB,CAKMjB,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"}
|
|
@@ -109,7 +109,7 @@ declare class SsrManifest {
|
|
|
109
109
|
/**
|
|
110
110
|
* Recursive walk routes and return id's with route import path
|
|
111
111
|
*/
|
|
112
|
-
protected getRoutesIds(routes: RouteObject[], index?: string): Promise<Record<string, string>>;
|
|
112
|
+
protected getRoutesIds(routes: RouteObject[], index?: string): Promise<Record<string, string | undefined>>;
|
|
113
113
|
/**
|
|
114
114
|
* Sort assets
|
|
115
115
|
*/
|
package/services/ssr-manifest.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import t from"node:fs";import e from"node:path";import s from"chalk";import i from"./prepare-server.js";import r from"./server-config.js";var o;!function(t){t.style="style",t.script="script",t.image="image",t.font="font"}(o||(o={}));const n="\r\n";class a{static instance=null;config;root;buildDir;manifestName="manifest.json";assetsManifest="assets-manifest.json";viteAliases;routesAssets=null;constructor(t,{buildDir:e,viteAliases:s}={}){this.config=t,this.root=t.getParams().root,this.buildDir=e,this.viteAliases=s??t.getVite()?.config?.resolve.alias}static get(t,e={}){return null===a.instance&&(a.instance=new a(t,e)),a.instance}getAssetsManifestFile(){return`${e.resolve(this.root,this.buildDir||"")}/server/${this.assetsManifest}`}loadClientManifest(){const s=e.resolve(this.root,`${this.buildDir||""}/client/${this.manifestName}`);if(!t.existsSync(s))return{};const i=JSON.parse(t.readFileSync(s,{encoding:"utf-8"}));return t.rmSync(s),i}loadAssetsManifest(){if(null!==this.routesAssets)return this.routesAssets;const e=this.getAssetsManifestFile();return t.existsSync(e)?(this.routesAssets=JSON.parse(t.readFileSync(e,{encoding:"utf-8"})),this.routesAssets):{}}async getRoutesIds(t,e){const i={};for(const r in t){const o=t[r],n=[e,r].filter(Boolean).join("-");if(o.lazy)try{const t=await o.lazy();i[n]=this.normalizeRoutePath(t?.pathId)}catch(t){console.error(s.red("Failed to load route:"),o.path,t)}else o.children&&Object.assign(i,await this.getRoutesIds(o.children,n))}return i}sortAssets(t){return t.sort(((t,e)=>t.weight===e.weight?Number(t.isNested)-Number(e.isNested):t.weight-e.weight))}getRouteAssets(t,e,s=!1){const i=[...e?.assets??[],...e?.css??[],e?.file].reduce(((t,i)=>{if(i){const r=this.getAssetType(i),o=e.isEntry&&e.file===i;r&&(t[i]={url:`/${i}`,weight:o?1.9:this.getAssetWeight(i),type:r,isNested:s,isPreload:!o})}return t}),{});return e?.imports?.length&&e.imports.forEach((e=>{const s=t[e];s&&Object.assign(i,this.getRouteAssets(t,s,!0))})),i}async buildRoutesManifest(){const e=i.init(r.init({isProd:!0})),s=this.loadClientManifest(),{routes:o}=await e.loadEntrypoint(!1),n=await this.getRoutesIds(o),a=this.getRouteImportPostfix(),l={};Object.entries(n).forEach((([t,e])=>{const i=a.find((t=>void 0!==s[`${e}${t}`])),r=s[`${e}${i||""}`];l[t]=this.sortAssets(Object.values(this.getRouteAssets(s,r)))})),t.writeFileSync(this.getAssetsManifestFile(),JSON.stringify(l,null,2),{encoding:"utf-8"})}getAliases(){const t={};return this.viteAliases?.forEach((({find:e,replacement:s})=>{"string"==typeof e&&(t[e]=s)})),t}getRouteImportPostfix(){return["","/index"].map((t=>["",".js",".ts",".tsx"].map((e=>`${t}${e}`)))).flat()}normalizeRoutePath(t,s=!1){if(!t)return;let i="";if(t.startsWith("./")||t.startsWith("../"))i=e.resolve(this.root,t);else{const e=this.getAliases(),[s]=t.split("/");e[s]&&(i=t.replace(s,e[s]))}return i=i.split(e.win32.sep).join(e.posix.sep),s?i:i.replace(this.root,"").replace(/^\/|\/$/g,"")}getAssets(t){if(this.config.getVite())return this.getAssetsDev(t);const e=t?.map((({route:t})=>t.id)).filter(Boolean)??[];if(!e.length)return[];const s=this.loadAssetsManifest();return this.sortAssets(e.map((t=>s[t])).flat().filter(Boolean))}getAssetsDev(t){const e=t?.map((({route:t})=>this.normalizeRoutePath(t?.pathId,!0))).filter(Boolean)??[];if(!e.length)return[];let s={};const i=this.getRouteImportPostfix();return[`${this.root}/${this.config.getPluginConfig()?.clientFile??"client.ts"}`,...e].forEach((t=>{for(const e of i){const i=this.config.getVite()?.moduleGraph.getModuleById(`${t}${e}`);if(i){s={...s,...this.getModuleAssets(i)};break}}})),Object.values(s)}getModuleAssets(t,e=!1){if(!t?.clientImportedModules.size)return{};let i={};return t.clientImportedModules.forEach((t=>{const{file:r,clientImportedModules:n,transformResult:a}=t,l=r?.split(".").at(-1);if(r&&l&&["css","scss"].includes(l)){const t=a?.code.match(/__vite__css\s+=\s+"(?<css>.+)"/)?.groups?.css;if(t)try{i[r]={type:o.style,url:r,weight:this.getAssetWeight(r),content:JSON.parse(`{"style": "${t}"}`).style,isNested:e,isPreload:!1}}catch(t){console.warn(s.yellowBright("Failed to parse style: ",r))}}else n.size&&(i={...i,...this.getModuleAssets(t,!0)})})),i}getAssetWeight(t){switch(this.getAssetType(t)){case
|
|
1
|
+
import t from"node:fs";import e from"node:path";import s from"chalk";import i from"./prepare-server.js";import r from"./server-config.js";var o;!function(t){t.style="style",t.script="script",t.image="image",t.font="font"}(o||(o={}));const n="\r\n";class a{static instance=null;config;root;buildDir;manifestName="manifest.json";assetsManifest="assets-manifest.json";viteAliases;routesAssets=null;constructor(t,{buildDir:e,viteAliases:s}={}){this.config=t,this.root=t.getParams().root,this.buildDir=e,this.viteAliases=s??t.getVite()?.config?.resolve.alias}static get(t,e={}){return null===a.instance&&(a.instance=new a(t,e)),a.instance}getAssetsManifestFile(){return`${e.resolve(this.root,this.buildDir||"")}/server/${this.assetsManifest}`}loadClientManifest(){const s=e.resolve(this.root,`${this.buildDir||""}/client/${this.manifestName}`);if(!t.existsSync(s))return{};const i=JSON.parse(t.readFileSync(s,{encoding:"utf-8"}));return t.rmSync(s),i}loadAssetsManifest(){if(null!==this.routesAssets)return this.routesAssets;const e=this.getAssetsManifestFile();return t.existsSync(e)?(this.routesAssets=JSON.parse(t.readFileSync(e,{encoding:"utf-8"})),this.routesAssets):{}}async getRoutesIds(t,e){const i={};for(const r in t){const o=t[r],n=[e,r].filter(Boolean).join("-");if(o.lazy)try{const t=await o.lazy();i[n]=this.normalizeRoutePath(t?.pathId)}catch(t){console.error(s.red("Failed to load route:"),o.path,t)}else o.children&&Object.assign(i,await this.getRoutesIds(o.children,n))}return i}sortAssets(t){return t.sort(((t,e)=>t.weight===e.weight?Number(t.isNested)-Number(e.isNested):t.weight-e.weight))}getRouteAssets(t,e,s=!1){const i=[...e?.assets??[],...e?.css??[],e?.file].reduce(((t,i)=>{if(i){const r=this.getAssetType(i),o=e.isEntry&&e.file===i;r&&(t[i]={url:`/${i}`,weight:o?1.9:this.getAssetWeight(i),type:r,isNested:s,isPreload:!o})}return t}),{});return e?.imports?.length&&e.imports.forEach((e=>{const s=t[e];s&&Object.assign(i,this.getRouteAssets(t,s,!0))})),i}async buildRoutesManifest(){const e=i.init(r.init({isProd:!0})),s=this.loadClientManifest(),{routes:o}=await e.loadEntrypoint(!1),n=await this.getRoutesIds(o),a=this.getRouteImportPostfix(),l={};Object.entries(n).forEach((([t,e])=>{const i=a.find((t=>void 0!==s[`${e}${t}`])),r=s[`${e}${i||""}`];l[t]=this.sortAssets(Object.values(this.getRouteAssets(s,r)))})),t.writeFileSync(this.getAssetsManifestFile(),JSON.stringify(l,null,2),{encoding:"utf-8"})}getAliases(){const t={};return this.viteAliases?.forEach((({find:e,replacement:s})=>{"string"==typeof e&&(t[e]=s)})),t}getRouteImportPostfix(){return["","/index"].map((t=>["",".js",".ts",".tsx"].map((e=>`${t}${e}`)))).flat()}normalizeRoutePath(t,s=!1){if(!t)return;let i="";if(t.startsWith("./")||t.startsWith("../"))i=e.resolve(this.root,t);else{const e=this.getAliases(),[s]=t.split("/");e[s]&&(i=t.replace(s,e[s]))}return i=i.split(e.win32.sep).join(e.posix.sep),s?i:i.replace(this.root,"").replace(/^\/|\/$/g,"")}getAssets(t){if(this.config.getVite())return this.getAssetsDev(t);const e=t?.map((({route:t})=>t.id)).filter(Boolean)??[];if(!e.length)return[];const s=this.loadAssetsManifest();return this.sortAssets(e.map((t=>s[t])).flat().filter(Boolean))}getAssetsDev(t){const e=t?.map((({route:t})=>this.normalizeRoutePath(t?.pathId,!0))).filter(Boolean)??[];if(!e.length)return[];let s={};const i=this.getRouteImportPostfix();return[`${this.root}/${this.config.getPluginConfig()?.clientFile??"client.ts"}`,...e].forEach((t=>{for(const e of i){const i=this.config.getVite()?.moduleGraph.getModuleById(`${t}${e}`);if(i){s={...s,...this.getModuleAssets(i)};break}}})),Object.values(s)}getModuleAssets(t,e=!1){if(!t?.clientImportedModules.size)return{};let i={};return t.clientImportedModules.forEach((t=>{const{file:r,clientImportedModules:n,transformResult:a}=t,l=r?.split(".").at(-1);if(r&&l&&["css","scss"].includes(l)){const t=a?.code.match(/__vite__css\s+=\s+"(?<css>.+)"/)?.groups?.css;if(t)try{i[r]={type:o.style,url:r,weight:this.getAssetWeight(r),content:JSON.parse(`{"style": "${t}"}`).style,isNested:e,isPreload:!1}}catch(t){console.warn(s.yellowBright("Failed to parse style: ",r))}}else n.size&&(i={...i,...this.getModuleAssets(t,!0)})})),i}getAssetWeight(t){switch(this.getAssetType(t)){case o.style:return 1;case o.script:return 2;default:return 3}}getAssetType(t){const e=t.split(".").at(-1)?.toLowerCase();switch(e){case"css":case"scss":return o.style;case"js":return o.script;case"svg":case"jpg":case"jpeg":case"png":case"webp":case"gif":case"ico":return o.image;case"ttf":case"otf":case"woff":case"woff2":return o.font;default:return null}}writeEarlyHits(t,e){e.write(`HTTP/1.1 103 Early Hints${n}`),t.forEach((({type:t,url:s})=>{t&&["style","script"].includes(t)&&e.write(`Link: <${s}>; rel=preload; as=${t}${n}`)})),e.write(n)}injectAssets({routerContext:t,html:e,res:s,hasEarlyHints:i=!1}){const r=this.getAssets(t?.matches),n=r.map((({type:t,url:e,isPreload:s,content:i=""})=>{switch(t){case o.style:return this.config.getVite()?`<style data-vite-dev-id="${e}">${i}</style>`:`<link rel="stylesheet" href="${e}">`;case o.script:return s?this.config.isModulePreload?`<link rel="modulepreload" as="script" crossorigin href="${e}">`:null:`<script async type="module" crossorigin src="${e}"><\/script>`}return null})).filter(Boolean);e.header=e.header.replace("</head>",`${n.join("\n")}</head>`),i&&n.length&&s.socket&&this.writeEarlyHits(r,s.socket)}}export{a as default};
|
|
2
2
|
//# sourceMappingURL=ssr-manifest.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ssr-manifest.js","sources":["../../src/services/ssr-manifest.ts"],"sourcesContent":["import fs from 'node:fs';\nimport type { Socket } from 'node:net';\nimport path from 'node:path';\nimport type { AgnosticDataRouteMatch } from '@remix-run/router/dist/utils';\nimport chalk from 'chalk';\nimport type { RouteObject } from 'react-router-dom';\nimport type { Alias, ModuleNode } from 'vite';\nimport type { IRequestContext } from '@node/render';\nimport PrepareServer from '@services/prepare-server';\nimport ServerConfig from '@services/server-config';\n\ninterface ISsrManifestParams {\n buildDir?: string;\n viteAliases?: Alias[];\n}\n\ninterface IManifest {\n [path: string]: {\n assets: string[];\n css: string[];\n file: string;\n isEntry?: boolean;\n imports: string[];\n };\n}\n\nenum AssetType {\n style = 'style',\n script = 'script',\n image = 'image',\n font = 'font',\n}\n\ninterface IAsset {\n type: AssetType;\n url: string;\n weight: number;\n isNested: boolean;\n isPreload: boolean;\n content?: string;\n}\n\nconst CRLF = '\\r\\n';\n\n/**\n * Working with SSR Manifest file\n */\nclass SsrManifest {\n /**\n * Singleton\n */\n protected static instance: SsrManifest | null = null;\n\n /**\n * Server config\n */\n protected readonly config: ServerConfig;\n\n /**\n * Project root path\n */\n protected readonly root: string;\n\n /**\n * Build dir\n */\n protected readonly buildDir?: string;\n\n /**\n * Client manifest file name\n */\n protected readonly manifestName = 'manifest.json';\n\n /**\n * Assets manifest file name\n */\n protected readonly assetsManifest = 'assets-manifest.json';\n\n /**\n * Vite resolve aliases\n */\n protected readonly viteAliases?: Alias[];\n\n /**\n * Loaded assets manifest file\n */\n protected routesAssets: Record<string, IAsset[]> | null = null;\n\n /**\n * @constructor\n */\n protected constructor(config: ServerConfig, { buildDir, viteAliases }: ISsrManifestParams = {}) {\n this.config = config;\n this.root = config.getParams().root;\n this.buildDir = buildDir;\n this.viteAliases = viteAliases ?? config.getVite()?.config?.resolve.alias;\n }\n\n /**\n * Get singleton instance\n */\n public static get(config: ServerConfig, params: ISsrManifestParams = {}): SsrManifest {\n if (SsrManifest.instance === null) {\n SsrManifest.instance = new SsrManifest(config, params);\n }\n\n return SsrManifest.instance;\n }\n\n /**\n * Get assets manifest file name\n */\n protected getAssetsManifestFile(): string {\n const outDir = path.resolve(this.root, this.buildDir || '');\n\n return `${outDir}/server/${this.assetsManifest}`;\n }\n\n /**\n * Load client ssr manifest\n */\n protected loadClientManifest(): IManifest {\n const clientSsrManifest = path.resolve(\n this.root,\n `${this.buildDir || ''}/client/${this.manifestName}`,\n );\n\n if (!fs.existsSync(clientSsrManifest)) {\n return {};\n }\n\n const result = JSON.parse(\n fs.readFileSync(clientSsrManifest, { encoding: 'utf-8' }),\n ) as IManifest;\n\n fs.rmSync(clientSsrManifest);\n\n return result;\n }\n\n /**\n * Load assets manifest\n */\n protected loadAssetsManifest(): Record<string, IAsset[]> {\n if (this.routesAssets !== null) {\n return this.routesAssets;\n }\n\n const manifestFile = this.getAssetsManifestFile();\n\n if (!fs.existsSync(manifestFile)) {\n return {};\n }\n\n this.routesAssets = JSON.parse(fs.readFileSync(manifestFile, { encoding: 'utf-8' })) as Record<\n string,\n IAsset[]\n >;\n\n return this.routesAssets;\n }\n\n /**\n * Recursive walk routes and return id's with route import path\n */\n protected async getRoutesIds(\n routes: RouteObject[],\n index?: string,\n ): Promise<Record<string, string>> {\n const result = {};\n\n for (const routeIndex in routes) {\n const route = routes[routeIndex];\n const routeId = [index, routeIndex].filter(Boolean).join('-');\n\n if (route.lazy) {\n try {\n const resolvedRoute = await route.lazy();\n\n result[routeId] = this.normalizeRoutePath(resolvedRoute?.['pathId'] as string);\n } catch (e) {\n console.error(chalk.red('Failed to load route:'), route.path, e);\n }\n } else if (route.children) {\n Object.assign(result, await this.getRoutesIds(route.children, routeId));\n }\n }\n\n return result;\n }\n\n /**\n * Sort assets\n */\n protected sortAssets(assets: IAsset[]): IAsset[] {\n return assets.sort((a, b) =>\n a.weight === b.weight ? Number(a.isNested) - Number(b.isNested) : a.weight - b.weight,\n );\n }\n\n /**\n * Get recursive module assets\n */\n protected getRouteAssets(\n manifest: IManifest,\n module: IManifest[string],\n isNested = false,\n ): Record<string, IAsset> {\n const rootAssets = [...(module?.assets ?? []), ...(module?.css ?? []), module?.file];\n\n const assets = rootAssets.reduce((res, asset) => {\n if (asset) {\n const type = this.getAssetType(asset);\n const isEntry = module.isEntry && module.file === asset;\n\n // keep only js,css,image,fonts files\n if (type) {\n res[asset] = {\n url: `/${asset}`,\n weight: isEntry ? 1.9 : this.getAssetWeight(asset),\n type,\n isNested,\n isPreload: !isEntry,\n };\n }\n }\n\n return res;\n }, {} as Record<string, IAsset>);\n\n // nested assets\n if (module?.imports?.length) {\n module.imports.forEach((nestedAsset) => {\n const nestedModule = manifest[nestedAsset];\n\n if (nestedModule) {\n Object.assign(assets, this.getRouteAssets(manifest, nestedModule, true));\n }\n });\n }\n\n return assets;\n }\n\n /**\n * Build routes manifest file\n */\n public async buildRoutesManifest(): Promise<void> {\n const prepareServer = PrepareServer.init(ServerConfig.init({ isProd: true }));\n const manifest = this.loadClientManifest();\n const { routes } = await prepareServer.loadEntrypoint(false);\n const routesPaths = await this.getRoutesIds(routes as RouteObject[]);\n const postfixes = this.getRouteImportPostfix();\n\n const result = {};\n\n // find route assets\n Object.entries(routesPaths).forEach(([routeId, routePath]) => {\n const routePostfix = postfixes.find((postfix) => {\n const filePath = `${routePath}${postfix}`;\n\n return manifest[filePath] !== undefined;\n });\n const routeFile = `${routePath}${routePostfix || ''}`;\n const routeMeta = manifest[routeFile];\n\n result[routeId] = this.sortAssets(Object.values(this.getRouteAssets(manifest, routeMeta)));\n });\n\n fs.writeFileSync(this.getAssetsManifestFile(), JSON.stringify(result, null, 2), {\n encoding: 'utf-8',\n });\n }\n\n /**\n * Get vite aliases\n */\n protected getAliases(): Record<string, string> {\n const aliases = {};\n\n this.viteAliases?.forEach(({ find, replacement }) => {\n if (typeof find !== 'string') {\n return;\n }\n\n aliases[find] = replacement;\n });\n\n return aliases;\n }\n\n /**\n * Return route postfix\n */\n protected getRouteImportPostfix(): string[] {\n return ['', '/index']\n .map((prefix) => ['', '.js', '.ts', '.tsx'].map((ext) => `${prefix}${ext}`))\n .flat();\n }\n\n /**\n * Normalized route path\n */\n protected normalizeRoutePath(routePath?: string, withRoot = false): string | undefined {\n if (!routePath) {\n return;\n }\n\n let fullPath = '';\n\n // relative import\n if (routePath.startsWith('./') || routePath.startsWith('../')) {\n fullPath = path.resolve(this.root, routePath);\n } else {\n // alias import\n const aliases = this.getAliases();\n // get alias\n const [routeAlias] = routePath.split('/');\n\n if (aliases[routeAlias]) {\n fullPath = routePath.replace(routeAlias, aliases[routeAlias]);\n }\n }\n\n // normalize slashes\n fullPath = fullPath.split(path.win32.sep).join(path.posix.sep);\n\n if (withRoot) {\n return fullPath;\n }\n\n return fullPath.replace(this.root, '').replace(/^\\/|\\/$/g, '');\n }\n\n /**\n * Get route assets\n */\n protected getAssets(routes?: AgnosticDataRouteMatch[]): IAsset[] {\n if (this.config.getVite()) {\n return this.getAssetsDev(routes);\n }\n\n const routeIds = routes?.map(({ route }) => route.id).filter(Boolean) ?? [];\n\n if (!routeIds.length) {\n return [];\n }\n\n const routesAssets = this.loadAssetsManifest();\n\n return this.sortAssets(\n routeIds\n .map((routeId) => routesAssets[routeId])\n .flat()\n .filter(Boolean),\n );\n }\n\n /**\n * Get development route assets\n */\n protected getAssetsDev(routes?: AgnosticDataRouteMatch[]): IAsset[] {\n const routeIds =\n (routes\n ?.map(({ route }) => this.normalizeRoutePath(route?.['pathId'] as string, true))\n .filter(Boolean) as string[]) ?? [];\n\n if (!routeIds.length) {\n return [];\n }\n\n let assets: { [id: string]: IAsset } = {};\n const postfixes = this.getRouteImportPostfix();\n const rootId = `${this.root}/${this.config.getPluginConfig()?.clientFile ?? 'client.ts'}`;\n\n [rootId, ...routeIds].forEach((moduleId) => {\n for (const ext of postfixes) {\n const module = this.config.getVite()?.moduleGraph.getModuleById(`${moduleId}${ext}`);\n\n if (module) {\n assets = { ...assets, ...this.getModuleAssets(module) };\n break;\n }\n }\n });\n\n return Object.values(assets);\n }\n\n /**\n * Get module assets\n */\n protected getModuleAssets(module?: ModuleNode, isNested = false): { [id: string]: IAsset } {\n if (!module?.clientImportedModules.size) {\n return {};\n }\n\n let assets: { [id: string]: IAsset } = {};\n\n module.clientImportedModules.forEach((subModule) => {\n const { file, clientImportedModules, transformResult } = subModule;\n const ext = file?.split('.').at(-1);\n\n if (file && ext && ['css', 'scss'].includes(ext)) {\n // @TODO investigate better method?\n const code = transformResult?.code.match(/__vite__css\\s+=\\s+\"(?<css>.+)\"/)?.groups?.css;\n\n if (code) {\n try {\n assets[file] = {\n type: AssetType.style,\n url: file,\n weight: this.getAssetWeight(file),\n content: JSON.parse(`{\"style\": \"${code}\"}`).style,\n isNested,\n isPreload: false,\n };\n } catch (e) {\n console.warn(chalk.yellowBright('Failed to parse style: ', file));\n }\n }\n } else if (clientImportedModules.size) {\n assets = {\n ...assets,\n ...this.getModuleAssets(subModule, true),\n };\n }\n });\n\n return assets;\n }\n\n /**\n * Get asset weight\n */\n protected getAssetWeight(asset: string): number {\n const type = this.getAssetType(asset);\n\n switch (type) {\n case 'style':\n return 1;\n\n case 'script':\n return 2;\n\n default:\n return 3;\n }\n }\n\n /**\n * Get asset type\n */\n protected getAssetType(asset: string): AssetType | null {\n const ext = asset.split('.').at(-1)?.toLowerCase();\n\n switch (ext) {\n case 'css':\n case 'scss':\n return AssetType.style;\n\n case 'js':\n return AssetType.script;\n\n case 'svg':\n case 'jpg':\n case 'jpeg':\n case 'png':\n case 'webp':\n case 'gif':\n case 'ico':\n return AssetType.image;\n\n case 'ttf':\n case 'otf':\n case 'woff':\n case 'woff2':\n return AssetType.font;\n\n default:\n return null;\n }\n }\n\n /**\n * Write 103 Early Hits header\n */\n public writeEarlyHits(assets: IAsset[], socket: Socket): void {\n socket.write(`HTTP/1.1 103 Early Hints${CRLF}`);\n assets.forEach(({ type, url }) => {\n if (!type || !['style', 'script'].includes(type)) {\n return;\n }\n\n socket.write(`Link: <${url}>; rel=preload; as=${type}${CRLF}`);\n });\n socket.write(CRLF);\n }\n\n /**\n * Inject route assets to head html\n */\n public injectAssets({ routerContext, html, res, hasEarlyHints = false }: IRequestContext): void {\n const assets = this.getAssets(routerContext?.matches);\n const htmlAssets = assets\n .map(({ type, url, isPreload, content = '' }) => {\n switch (type) {\n case 'style':\n return this.config.getVite()\n ? `<style data-vite-dev-id=\"${url}\">${content}</style>`\n : `<link rel=\"stylesheet\" href=\"${url}\">`;\n\n case 'script':\n return isPreload\n ? this.config.isModulePreload\n ? // can reduce lighthouse performance\n `<link rel=\"modulepreload\" as=\"script\" crossorigin href=\"${url}\">`\n : null\n : `<script async type=\"module\" crossorigin src=\"${url}\"></script>`;\n }\n\n return null;\n })\n .filter(Boolean);\n\n html.header = html.header.replace('</head>', `${htmlAssets.join('\\n')}</head>`);\n\n if (hasEarlyHints && htmlAssets.length && res.socket) {\n this.writeEarlyHits(assets, res.socket);\n }\n }\n}\n\nexport default SsrManifest;\n"],"names":["AssetType","CRLF","SsrManifest","static","config","root","buildDir","manifestName","assetsManifest","viteAliases","routesAssets","constructor","this","getParams","getVite","resolve","alias","params","instance","getAssetsManifestFile","path","loadClientManifest","clientSsrManifest","fs","existsSync","result","JSON","parse","readFileSync","encoding","rmSync","loadAssetsManifest","manifestFile","async","routes","index","routeIndex","route","routeId","filter","Boolean","join","lazy","resolvedRoute","normalizeRoutePath","e","console","error","chalk","red","children","Object","assign","getRoutesIds","sortAssets","assets","sort","a","b","weight","Number","isNested","getRouteAssets","manifest","module","css","file","reduce","res","asset","type","getAssetType","isEntry","url","getAssetWeight","isPreload","imports","length","forEach","nestedAsset","nestedModule","prepareServer","PrepareServer","init","ServerConfig","isProd","loadEntrypoint","routesPaths","postfixes","getRouteImportPostfix","entries","routePath","routePostfix","find","postfix","undefined","routeMeta","values","writeFileSync","stringify","getAliases","aliases","replacement","map","prefix","ext","flat","withRoot","fullPath","startsWith","routeAlias","split","replace","win32","sep","posix","getAssets","getAssetsDev","routeIds","id","getPluginConfig","clientFile","moduleId","moduleGraph","getModuleById","getModuleAssets","clientImportedModules","size","subModule","transformResult","at","includes","code","match","groups","style","content","warn","yellowBright","toLowerCase","script","image","font","writeEarlyHits","socket","write","injectAssets","routerContext","html","hasEarlyHints","matches","htmlAssets","isModulePreload","header"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ssr-manifest.js","sources":["../../src/services/ssr-manifest.ts"],"sourcesContent":["import fs from 'node:fs';\nimport type { Socket } from 'node:net';\nimport path from 'node:path';\nimport type { AgnosticDataRouteMatch } from '@remix-run/router/dist/utils';\nimport chalk from 'chalk';\nimport type { RouteObject } from 'react-router-dom';\nimport type { Alias, ModuleNode } from 'vite';\nimport type { IAsyncRoute } from '@helpers/import-route';\nimport type { IRequestContext } from '@node/render';\nimport PrepareServer from '@services/prepare-server';\nimport ServerConfig from '@services/server-config';\n\ninterface ISsrManifestParams {\n buildDir?: string;\n viteAliases?: Alias[];\n}\n\ninterface IManifest {\n [path: string]: {\n assets: string[];\n css: string[];\n file: string;\n isEntry?: boolean;\n imports: string[];\n };\n}\n\nenum AssetType {\n style = 'style',\n script = 'script',\n image = 'image',\n font = 'font',\n}\n\ninterface IAsset {\n type: AssetType;\n url: string;\n weight: number;\n isNested: boolean;\n isPreload: boolean;\n content?: string;\n}\n\nconst CRLF = '\\r\\n';\n\n/**\n * Working with SSR Manifest file\n */\nclass SsrManifest {\n /**\n * Singleton\n */\n protected static instance: SsrManifest | null = null;\n\n /**\n * Server config\n */\n protected readonly config: ServerConfig;\n\n /**\n * Project root path\n */\n protected readonly root: string;\n\n /**\n * Build dir\n */\n protected readonly buildDir?: string;\n\n /**\n * Client manifest file name\n */\n protected readonly manifestName = 'manifest.json';\n\n /**\n * Assets manifest file name\n */\n protected readonly assetsManifest = 'assets-manifest.json';\n\n /**\n * Vite resolve aliases\n */\n protected readonly viteAliases?: Alias[];\n\n /**\n * Loaded assets manifest file\n */\n protected routesAssets: Record<string, IAsset[]> | null = null;\n\n /**\n * @constructor\n */\n protected constructor(config: ServerConfig, { buildDir, viteAliases }: ISsrManifestParams = {}) {\n this.config = config;\n this.root = config.getParams().root;\n this.buildDir = buildDir;\n this.viteAliases = viteAliases ?? config.getVite()?.config?.resolve.alias;\n }\n\n /**\n * Get singleton instance\n */\n public static get(config: ServerConfig, params: ISsrManifestParams = {}): SsrManifest {\n if (SsrManifest.instance === null) {\n SsrManifest.instance = new SsrManifest(config, params);\n }\n\n return SsrManifest.instance;\n }\n\n /**\n * Get assets manifest file name\n */\n protected getAssetsManifestFile(): string {\n const outDir = path.resolve(this.root, this.buildDir || '');\n\n return `${outDir}/server/${this.assetsManifest}`;\n }\n\n /**\n * Load client ssr manifest\n */\n protected loadClientManifest(): IManifest {\n const clientSsrManifest = path.resolve(\n this.root,\n `${this.buildDir || ''}/client/${this.manifestName}`,\n );\n\n if (!fs.existsSync(clientSsrManifest)) {\n return {};\n }\n\n const result = JSON.parse(\n fs.readFileSync(clientSsrManifest, { encoding: 'utf-8' }),\n ) as IManifest;\n\n fs.rmSync(clientSsrManifest);\n\n return result;\n }\n\n /**\n * Load assets manifest\n */\n protected loadAssetsManifest(): Record<string, IAsset[]> {\n if (this.routesAssets !== null) {\n return this.routesAssets;\n }\n\n const manifestFile = this.getAssetsManifestFile();\n\n if (!fs.existsSync(manifestFile)) {\n return {};\n }\n\n this.routesAssets = JSON.parse(fs.readFileSync(manifestFile, { encoding: 'utf-8' })) as Record<\n string,\n IAsset[]\n >;\n\n return this.routesAssets;\n }\n\n /**\n * Recursive walk routes and return id's with route import path\n */\n protected async getRoutesIds(\n routes: RouteObject[],\n index?: string,\n ): Promise<Record<string, string | undefined>> {\n const result: Record<string, string | undefined> = {};\n\n for (const routeIndex in routes) {\n const route = routes[routeIndex];\n const routeId = [index, routeIndex].filter(Boolean).join('-');\n\n if (route.lazy) {\n try {\n const resolvedRoute: IAsyncRoute = await route.lazy();\n\n result[routeId] = this.normalizeRoutePath(resolvedRoute?.pathId);\n } catch (e) {\n console.error(chalk.red('Failed to load route:'), route.path, e);\n }\n } else if (route.children) {\n Object.assign(result, await this.getRoutesIds(route.children, routeId));\n }\n }\n\n return result;\n }\n\n /**\n * Sort assets\n */\n protected sortAssets(assets: IAsset[]): IAsset[] {\n return assets.sort((a, b) =>\n a.weight === b.weight ? Number(a.isNested) - Number(b.isNested) : a.weight - b.weight,\n );\n }\n\n /**\n * Get recursive module assets\n */\n protected getRouteAssets(\n manifest: IManifest,\n module: IManifest[string],\n isNested = false,\n ): Record<string, IAsset> {\n const rootAssets = [...(module?.assets ?? []), ...(module?.css ?? []), module?.file];\n\n const assets = rootAssets.reduce(\n (res, asset) => {\n if (asset) {\n const type = this.getAssetType(asset);\n const isEntry = module.isEntry && module.file === asset;\n\n // keep only js,css,image,fonts files\n if (type) {\n res[asset] = {\n url: `/${asset}`,\n weight: isEntry ? 1.9 : this.getAssetWeight(asset),\n type,\n isNested,\n isPreload: !isEntry,\n };\n }\n }\n\n return res;\n },\n {} as Record<string, IAsset>,\n );\n\n // nested assets\n if (module?.imports?.length) {\n module.imports.forEach((nestedAsset) => {\n const nestedModule = manifest[nestedAsset];\n\n if (nestedModule) {\n Object.assign(assets, this.getRouteAssets(manifest, nestedModule, true));\n }\n });\n }\n\n return assets;\n }\n\n /**\n * Build routes manifest file\n */\n public async buildRoutesManifest(): Promise<void> {\n const prepareServer = PrepareServer.init(ServerConfig.init({ isProd: true }));\n const manifest = this.loadClientManifest();\n const { routes } = await prepareServer.loadEntrypoint(false);\n const routesPaths = await this.getRoutesIds(routes as RouteObject[]);\n const postfixes = this.getRouteImportPostfix();\n\n const result: Record<string, IAsset[]> = {};\n\n // find route assets\n Object.entries(routesPaths).forEach(([routeId, routePath]) => {\n const routePostfix = postfixes.find((postfix) => {\n const filePath = `${routePath}${postfix}`;\n\n return manifest[filePath] !== undefined;\n });\n const routeFile = `${routePath}${routePostfix || ''}`;\n const routeMeta = manifest[routeFile];\n\n result[routeId] = this.sortAssets(Object.values(this.getRouteAssets(manifest, routeMeta)));\n });\n\n fs.writeFileSync(this.getAssetsManifestFile(), JSON.stringify(result, null, 2), {\n encoding: 'utf-8',\n });\n }\n\n /**\n * Get vite aliases\n */\n protected getAliases(): Record<string, string> {\n const aliases: Record<string, string> = {};\n\n this.viteAliases?.forEach(({ find, replacement }) => {\n if (typeof find !== 'string') {\n return;\n }\n\n aliases[find] = replacement;\n });\n\n return aliases;\n }\n\n /**\n * Return route postfix\n */\n protected getRouteImportPostfix(): string[] {\n return ['', '/index']\n .map((prefix) => ['', '.js', '.ts', '.tsx'].map((ext) => `${prefix}${ext}`))\n .flat();\n }\n\n /**\n * Normalized route path\n */\n protected normalizeRoutePath(routePath?: string, withRoot = false): string | undefined {\n if (!routePath) {\n return;\n }\n\n let fullPath = '';\n\n // relative import\n if (routePath.startsWith('./') || routePath.startsWith('../')) {\n fullPath = path.resolve(this.root, routePath);\n } else {\n // alias import\n const aliases = this.getAliases();\n // get alias\n const [routeAlias] = routePath.split('/');\n\n if (aliases[routeAlias]) {\n fullPath = routePath.replace(routeAlias, aliases[routeAlias]);\n }\n }\n\n // normalize slashes\n fullPath = fullPath.split(path.win32.sep).join(path.posix.sep);\n\n if (withRoot) {\n return fullPath;\n }\n\n return fullPath.replace(this.root, '').replace(/^\\/|\\/$/g, '');\n }\n\n /**\n * Get route assets\n */\n protected getAssets(routes?: AgnosticDataRouteMatch[]): IAsset[] {\n if (this.config.getVite()) {\n return this.getAssetsDev(routes);\n }\n\n const routeIds = routes?.map(({ route }) => route.id).filter(Boolean) ?? [];\n\n if (!routeIds.length) {\n return [];\n }\n\n const routesAssets = this.loadAssetsManifest();\n\n return this.sortAssets(\n routeIds\n .map((routeId) => routesAssets[routeId])\n .flat()\n .filter(Boolean),\n );\n }\n\n /**\n * Get development route assets\n */\n protected getAssetsDev(routes?: AgnosticDataRouteMatch[]): IAsset[] {\n const routeIds =\n (routes\n ?.map(({ route }) => this.normalizeRoutePath((route as IAsyncRoute)?.pathId, true))\n .filter(Boolean) as string[]) ?? [];\n\n if (!routeIds.length) {\n return [];\n }\n\n let assets: { [id: string]: IAsset } = {};\n const postfixes = this.getRouteImportPostfix();\n const rootId = `${this.root}/${this.config.getPluginConfig()?.clientFile ?? 'client.ts'}`;\n\n [rootId, ...routeIds].forEach((moduleId) => {\n for (const ext of postfixes) {\n const module = this.config.getVite()?.moduleGraph.getModuleById(`${moduleId}${ext}`);\n\n if (module) {\n assets = { ...assets, ...this.getModuleAssets(module) };\n break;\n }\n }\n });\n\n return Object.values(assets);\n }\n\n /**\n * Get module assets\n */\n protected getModuleAssets(module?: ModuleNode, isNested = false): { [id: string]: IAsset } {\n if (!module?.clientImportedModules.size) {\n return {};\n }\n\n let assets: { [id: string]: IAsset } = {};\n\n module.clientImportedModules.forEach((subModule) => {\n const { file, clientImportedModules, transformResult } = subModule;\n const ext = file?.split('.').at(-1);\n\n if (file && ext && ['css', 'scss'].includes(ext)) {\n // @TODO investigate better method?\n const code = transformResult?.code.match(/__vite__css\\s+=\\s+\"(?<css>.+)\"/)?.groups?.css;\n\n if (code) {\n try {\n assets[file] = {\n type: AssetType.style,\n url: file,\n weight: this.getAssetWeight(file),\n content: JSON.parse(`{\"style\": \"${code}\"}`).style,\n isNested,\n isPreload: false,\n };\n } catch (e) {\n console.warn(chalk.yellowBright('Failed to parse style: ', file));\n }\n }\n } else if (clientImportedModules.size) {\n assets = {\n ...assets,\n ...this.getModuleAssets(subModule, true),\n };\n }\n });\n\n return assets;\n }\n\n /**\n * Get asset weight\n */\n protected getAssetWeight(asset: string): number {\n const type = this.getAssetType(asset);\n\n switch (type) {\n case AssetType.style:\n return 1;\n\n case AssetType.script:\n return 2;\n\n default:\n return 3;\n }\n }\n\n /**\n * Get asset type\n */\n protected getAssetType(asset: string): AssetType | null {\n const ext = asset.split('.').at(-1)?.toLowerCase();\n\n switch (ext) {\n case 'css':\n case 'scss':\n return AssetType.style;\n\n case 'js':\n return AssetType.script;\n\n case 'svg':\n case 'jpg':\n case 'jpeg':\n case 'png':\n case 'webp':\n case 'gif':\n case 'ico':\n return AssetType.image;\n\n case 'ttf':\n case 'otf':\n case 'woff':\n case 'woff2':\n return AssetType.font;\n\n default:\n return null;\n }\n }\n\n /**\n * Write 103 Early Hits header\n */\n public writeEarlyHits(assets: IAsset[], socket: Socket): void {\n socket.write(`HTTP/1.1 103 Early Hints${CRLF}`);\n assets.forEach(({ type, url }) => {\n if (!type || !['style', 'script'].includes(type)) {\n return;\n }\n\n socket.write(`Link: <${url}>; rel=preload; as=${type}${CRLF}`);\n });\n socket.write(CRLF);\n }\n\n /**\n * Inject route assets to head html\n */\n public injectAssets({ routerContext, html, res, hasEarlyHints = false }: IRequestContext): void {\n const assets = this.getAssets(routerContext?.matches);\n const htmlAssets = assets\n .map(({ type, url, isPreload, content = '' }) => {\n switch (type) {\n case AssetType.style:\n return this.config.getVite()\n ? `<style data-vite-dev-id=\"${url}\">${content}</style>`\n : `<link rel=\"stylesheet\" href=\"${url}\">`;\n\n case AssetType.script:\n return isPreload\n ? this.config.isModulePreload\n ? // can reduce lighthouse performance\n `<link rel=\"modulepreload\" as=\"script\" crossorigin href=\"${url}\">`\n : null\n : `<script async type=\"module\" crossorigin src=\"${url}\"></script>`;\n }\n\n return null;\n })\n .filter(Boolean);\n\n html.header = html.header.replace('</head>', `${htmlAssets.join('\\n')}</head>`);\n\n if (hasEarlyHints && htmlAssets.length && res.socket) {\n this.writeEarlyHits(assets, res.socket);\n }\n }\n}\n\nexport default SsrManifest;\n"],"names":["AssetType","CRLF","SsrManifest","static","config","root","buildDir","manifestName","assetsManifest","viteAliases","routesAssets","constructor","this","getParams","getVite","resolve","alias","params","instance","getAssetsManifestFile","path","loadClientManifest","clientSsrManifest","fs","existsSync","result","JSON","parse","readFileSync","encoding","rmSync","loadAssetsManifest","manifestFile","async","routes","index","routeIndex","route","routeId","filter","Boolean","join","lazy","resolvedRoute","normalizeRoutePath","pathId","e","console","error","chalk","red","children","Object","assign","getRoutesIds","sortAssets","assets","sort","a","b","weight","Number","isNested","getRouteAssets","manifest","module","css","file","reduce","res","asset","type","getAssetType","isEntry","url","getAssetWeight","isPreload","imports","length","forEach","nestedAsset","nestedModule","prepareServer","PrepareServer","init","ServerConfig","isProd","loadEntrypoint","routesPaths","postfixes","getRouteImportPostfix","entries","routePath","routePostfix","find","postfix","undefined","routeMeta","values","writeFileSync","stringify","getAliases","aliases","replacement","map","prefix","ext","flat","withRoot","fullPath","startsWith","routeAlias","split","replace","win32","sep","posix","getAssets","getAssetsDev","routeIds","id","getPluginConfig","clientFile","moduleId","moduleGraph","getModuleById","getModuleAssets","clientImportedModules","size","subModule","transformResult","at","includes","code","match","groups","style","content","warn","yellowBright","script","toLowerCase","image","font","writeEarlyHits","socket","write","injectAssets","routerContext","html","hasEarlyHints","matches","htmlAssets","isModulePreload","header"],"mappings":"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"}
|