@lomray/vite-ssr-boost 4.0.0 → 6.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -3
- package/cli/helpers/keyboard-input.js.map +1 -1
- package/cli/helpers/vite-reset-cache.js.map +1 -1
- package/cli/run-amplify-build.js.map +1 -1
- package/cli/run-docker-build.js.map +1 -1
- package/cli/run-vercel-build.js.map +1 -1
- package/cli.js.map +1 -1
- package/components/navigate.js.map +1 -1
- package/components/render-client.d.ts +7 -0
- package/components/render-client.js +2 -0
- package/components/render-client.js.map +1 -0
- package/components/with-suspense.d.ts +1 -1
- package/components/with-suspense.js.map +1 -1
- package/constants/common.d.ts +2 -1
- package/constants/common.js +1 -1
- package/constants/common.js.map +1 -1
- package/helpers/dev-marker.js.map +1 -1
- package/helpers/get-server-state.js.map +1 -1
- package/helpers/import-route.d.ts +1 -1
- package/helpers/import-route.js +1 -1
- package/helpers/import-route.js.map +1 -1
- package/helpers/print-server-info.js.map +1 -1
- package/helpers/resolve-server-urls.js.map +1 -1
- package/helpers/serialize-errors.js.map +1 -1
- package/interfaces/route-object.d.ts +1 -0
- package/node/render.js.map +1 -1
- package/node/server.js.map +1 -1
- package/node/write-response.js.map +1 -1
- package/package.json +19 -18
- package/plugin.d.ts +0 -1
- package/plugin.js +1 -1
- package/plugin.js.map +1 -1
- package/plugins/handle-custom-entrypoint.js.map +1 -1
- package/plugins/make-aliases.js.map +1 -1
- package/plugins/normalize-route.d.ts +0 -3
- package/plugins/normalize-route.js +1 -1
- package/plugins/normalize-route.js.map +1 -1
- package/services/build.d.ts +1 -8
- package/services/build.js +1 -1
- package/services/build.js.map +1 -1
- package/services/logger.js.map +1 -1
- package/services/parse-routes.d.ts +5 -3
- package/services/parse-routes.js +1 -1
- package/services/parse-routes.js.map +1 -1
- package/services/path-normalize.js.map +1 -1
- package/services/prepare-server.js.map +1 -1
- package/services/server-api.js.map +1 -1
- package/services/server-config.js.map +1 -1
- package/services/ssr-manifest.d.ts +2 -9
- package/services/ssr-manifest.js +1 -1
- package/services/ssr-manifest.js.map +1 -1
- package/helpers/ssr-meta.d.ts +0 -18
- package/helpers/ssr-meta.js +0 -2
- package/helpers/ssr-meta.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"path-normalize.js","sources":["../../src/services/path-normalize.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'path';\nimport type { Alias } from 'vite';\nimport type ServerConfig from '@services/server-config';\n\n/**\n * Service for work with path and aliases\n */\nclass PathNormalize {\n /**\n * Vite resolve aliases\n */\n protected readonly viteAliases?: Alias[];\n\n /**\n * Server config\n */\n protected readonly config: ServerConfig;\n\n /**\n * @constructor\n */\n constructor(config: ServerConfig, viteAliases?: Alias[]) {\n this.config = config;\n this.viteAliases = viteAliases ?? config.getVite()?.config?.resolve.alias;\n }\n\n /**\n * Get vite aliases\n */\n public 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 filename postfix\n */\n public getImportPostfix(): string[] {\n return ['', '/index']\n .map((prefix) => ['', '.js', '.ts', '.tsx'].map((ext) => `${prefix}${ext}`))\n .flat();\n }\n\n /**\n * Resolve app path\n */\n public getAppPath(appPath?: string, withRoot = false): string | undefined {\n if (!appPath) {\n return;\n }\n\n const { root } = this.config.getParams();\n let fullPath = appPath;\n\n // relative import\n if (appPath.startsWith('./') || appPath.startsWith('../')) {\n fullPath = path.resolve(root, appPath);\n } else {\n // alias import\n const aliases = this.getAliases();\n // get alias\n const [routeAlias] = appPath.split('/');\n\n if (aliases[routeAlias]) {\n fullPath = appPath.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(root, '').replace(/^(\\/)|(\\/)$/g, '');\n }\n\n /**\n * Find app filepath\n */\n public findAppFile(basePath: string): string | null {\n const postfixes = this.getImportPostfix();\n\n for (const postfix of postfixes) {\n const filepath = `${basePath}${postfix}`;\n\n if (fs.existsSync(filepath) && fs.statSync(filepath).isFile()) {\n return filepath;\n }\n }\n\n return null;\n }\n}\n\nexport default PathNormalize;\n"],"names":["PathNormalize","viteAliases","config","constructor","this","getVite","resolve","alias","getAliases","aliases","forEach","find","replacement","getImportPostfix","map","prefix","ext","flat","getAppPath","appPath","withRoot","root","getParams","fullPath","startsWith","path","routeAlias","split","replace","win32","sep","join","posix","findAppFile","basePath","postfixes","postfix","filepath","fs","existsSync","statSync","isFile"],"mappings":"2CAQA,MAAMA,EAIeC,YAKAC,OAKnBC,YAAYD,EAAsBD,GAChCG,KAAKF,OAASA,EACdE,KAAKH,YAAcA,GAAeC,EAAOG,WAAWH,QAAQI,QAAQC,
|
|
1
|
+
{"version":3,"file":"path-normalize.js","sources":["../../src/services/path-normalize.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'path';\nimport type { Alias } from 'vite';\nimport type ServerConfig from '@services/server-config';\n\n/**\n * Service for work with path and aliases\n */\nclass PathNormalize {\n /**\n * Vite resolve aliases\n */\n protected readonly viteAliases?: Alias[];\n\n /**\n * Server config\n */\n protected readonly config: ServerConfig;\n\n /**\n * @constructor\n */\n constructor(config: ServerConfig, viteAliases?: Alias[]) {\n this.config = config;\n this.viteAliases = viteAliases ?? config.getVite()?.config?.resolve.alias;\n }\n\n /**\n * Get vite aliases\n */\n public 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 filename postfix\n */\n public getImportPostfix(): string[] {\n return ['', '/index']\n .map((prefix) => ['', '.js', '.ts', '.tsx'].map((ext) => `${prefix}${ext}`))\n .flat();\n }\n\n /**\n * Resolve app path\n */\n public getAppPath(appPath?: string, withRoot = false): string | undefined {\n if (!appPath) {\n return;\n }\n\n const { root } = this.config.getParams();\n let fullPath = appPath;\n\n // relative import\n if (appPath.startsWith('./') || appPath.startsWith('../')) {\n fullPath = path.resolve(root, appPath);\n } else {\n // alias import\n const aliases = this.getAliases();\n // get alias\n const [routeAlias] = appPath.split('/');\n\n if (aliases[routeAlias]) {\n fullPath = appPath.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(root, '').replace(/^(\\/)|(\\/)$/g, '');\n }\n\n /**\n * Find app filepath\n */\n public findAppFile(basePath: string): string | null {\n const postfixes = this.getImportPostfix();\n\n for (const postfix of postfixes) {\n const filepath = `${basePath}${postfix}`;\n\n if (fs.existsSync(filepath) && fs.statSync(filepath).isFile()) {\n return filepath;\n }\n }\n\n return null;\n }\n}\n\nexport default PathNormalize;\n"],"names":["PathNormalize","viteAliases","config","constructor","this","getVite","resolve","alias","getAliases","aliases","forEach","find","replacement","getImportPostfix","map","prefix","ext","flat","getAppPath","appPath","withRoot","root","getParams","fullPath","startsWith","path","routeAlias","split","replace","win32","sep","join","posix","findAppFile","basePath","postfixes","postfix","filepath","fs","existsSync","statSync","isFile"],"mappings":"2CAQA,MAAMA,EAIeC,YAKAC,OAKnBC,YAAYD,EAAsBD,GAChCG,KAAKF,OAASA,EACdE,KAAKH,YAAcA,GAAeC,EAAOG,WAAWH,QAAQI,QAAQC,MAM/DC,aACL,MAAMC,EAAkC,CAAE,EAU1C,OARAL,KAAKH,aAAaS,SAAQ,EAAGC,OAAMC,kBACb,iBAATD,IAIXF,EAAQE,GAAQC,EAAW,IAGtBH,EAMFI,mBACL,MAAO,CAAC,GAAI,UACTC,KAAKC,GAAW,CAAC,GAAI,MAAO,MAAO,QAAQD,KAAKE,GAAQ,GAAGD,IAASC,QACpEC,OAMEC,WAAWC,EAAkBC,GAAW,GAC7C,IAAKD,EACH,OAGF,MAAME,KAAEA,GAASjB,KAAKF,OAAOoB,YAC7B,IAAIC,EAAWJ,EAGf,GAAIA,EAAQK,WAAW,OAASL,EAAQK,WAAW,OACjDD,EAAWE,EAAKnB,QAAQe,EAAMF,OACzB,CAEL,MAAMV,EAAUL,KAAKI,cAEdkB,GAAcP,EAAQQ,MAAM,KAE/BlB,EAAQiB,KACVH,EAAWJ,EAAQS,QAAQF,EAAYjB,EAAQiB,KAOnD,OAFAH,EAAWA,EAASI,MAAMF,EAAKI,MAAMC,KAAKC,KAAKN,EAAKO,MAAMF,KAEtDV,EACKG,EAGFA,EAASK,QAAQP,EAAM,IAAIO,QAAQ,eAAgB,IAMrDK,YAAYC,GACjB,MAAMC,EAAY/B,KAAKS,mBAEvB,IAAK,MAAMuB,KAAWD,EAAW,CAC/B,MAAME,EAAW,GAAGH,IAAWE,IAE/B,GAAIE,EAAGC,WAAWF,IAAaC,EAAGE,SAASH,GAAUI,SACnD,OAAOJ,EAIX,OAAO"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prepare-server.js","sources":["../../src/services/prepare-server.ts"],"sourcesContent":["import fs from 'fs';\nimport path from 'node:path';\nimport process from 'node:process';\nimport { pathToFileURL } from 'node:url';\nimport chalk from 'chalk';\nimport type { Request } from 'express';\nimport type { TRouteObject } from '@interfaces/route-object';\nimport type { IEntrypointOptions, IPrepareRenderOut } from '@node/entry';\nimport type { TRender } from '@node/render';\nimport ServerApi from '@services/server-api';\nimport type ServerConfig from '@services/server-config';\n\ninterface IPrepareServerEntrypointLoadOut<TAppProps = Record<string, any>> {\n render: TRender;\n routes: TRouteObject[];\n abortDelay?: number;\n onRequest?: IEntrypointOptions<TAppProps>['onRequest'];\n onRouterReady?: IEntrypointOptions<TAppProps>['onRouterReady'];\n onShellReady?: IEntrypointOptions<TAppProps>['onShellReady'];\n onShellError?: IEntrypointOptions<TAppProps>['onShellError'];\n onResponse?: IEntrypointOptions<TAppProps>['onResponse'];\n onError?: IEntrypointOptions<TAppProps>['onError'];\n getState?: IEntrypointOptions<TAppProps>['getState'];\n}\n\n/**\n * Load server entrypoint and template\n * DEV MODE: refresh entrypoint and template\n */\nclass PrepareServer {\n /**\n * Server configuration\n */\n protected readonly config: ServerConfig;\n\n /**\n * Server API\n */\n protected readonly serverApi: ServerApi;\n\n /**\n * Entrypoint resolved params\n */\n protected entrypoint?: IPrepareServerEntrypointLoadOut;\n\n /**\n * Hook which calls after express server created\n */\n protected onServerCreated?: IEntrypointOptions['onServerCreated'];\n\n /**\n * Hook which calls after express server started\n */\n public onServerStarted?: IEntrypointOptions['onServerStarted'];\n\n /**\n * Html shell\n */\n protected html: string;\n\n /**\n * Middlewares configs\n */\n protected middlewaresConfigs?: IPrepareRenderOut['middlewares'];\n\n /**\n * @constructor\n */\n protected constructor(config: ServerConfig, serverApi?: ServerApi) {\n this.config = config;\n this.serverApi = serverApi ?? new ServerApi();\n }\n\n /**\n * Init service\n */\n public static init(config: ServerConfig, serverApi?: ServerApi): PrepareServer {\n return new PrepareServer(config, serverApi);\n }\n\n /**\n * Resolve and return entrypoint params\n */\n public async loadEntrypoint(shouldInit = true): Promise<IPrepareServerEntrypointLoadOut> {\n // load server entrypoint each time only in development mode (for fast refresh)\n if (this.entrypoint && this.config.isProd) {\n return this.entrypoint;\n }\n\n const { root, isProd, serverFile } = this.config.getParams();\n const entrypointPath = path.resolve(`${root}/${serverFile}`);\n\n let resolvedEntrypoint: IPrepareRenderOut;\n\n try {\n if (!isProd) {\n resolvedEntrypoint = (\n await this.config.getVite()!.ssrLoadModule(entrypointPath, {\n fixStacktrace: true,\n })\n ).default as IPrepareRenderOut;\n } else {\n resolvedEntrypoint = (\n (await import(pathToFileURL(entrypointPath).toString())) as { default: IPrepareRenderOut }\n ).default;\n }\n } catch (e) {\n if (\n e instanceof Error &&\n e.message.includes('Cannot find module') &&\n e.message.includes('/build/')\n ) {\n this.config\n .getLogger()\n .error(\n chalk.red(\n `Before starting the server, you need to create a build: ${chalk.yellow(\n 'ssr-boost build',\n )} or provide path to build dir: ${chalk.yellow(\n 'ssr-boost start --build-dir build',\n )}`,\n ),\n );\n\n return process.exit(1);\n }\n\n throw e;\n }\n\n if (!shouldInit && resolvedEntrypoint.init) {\n delete resolvedEntrypoint.init;\n }\n\n const { render, init, routes, abortDelay, loggerProd, loggerDev, middlewares } =\n resolvedEntrypoint;\n\n this.middlewaresConfigs = middlewares;\n\n if (loggerProd && isProd) {\n this.config.setLogger(loggerProd);\n } else if (loggerDev && !isProd) {\n this.config.setLogger(loggerDev);\n }\n\n const { onServerCreated, onServerStarted, ...renderParams } =\n (await init?.({\n config: this.config,\n })) ?? {};\n\n this.entrypoint = {\n render,\n routes,\n abortDelay,\n ...renderParams,\n };\n this.onServerCreated = onServerCreated;\n this.onServerStarted = onServerStarted;\n\n return this.entrypoint;\n }\n\n /**\n * Load and return html shell\n */\n public async loadHtml(req: Request): Promise<[string, string]> {\n const { isProd, root, indexFile, clientFile } = this.config.getParams();\n\n if (!this.html || !isProd) {\n this.html = fs.readFileSync(path.resolve(`${root}/${indexFile}`), 'utf-8');\n }\n\n let modifiedHtml = this.html;\n\n if (!isProd) {\n const clientFileEntry = path.posix.normalize(\n `${this.config.getVite()?.config.base}/${clientFile}`,\n );\n\n // Apply Vite HTML transforms. This injects the Vite HMR client,\n // and also applies HTML transforms from Vite plugins, e.g. global\n // preambles from @vitejs/plugin-react\n modifiedHtml = (\n await this.config.getVite()!.transformIndexHtml(req.originalUrl, this.html, indexFile)\n )\n // remove 'async' attribute from app entrypoint for development\n // it might cause problems with preambles from @vitejs/plugin-react\n .replace(\n new RegExp(\n `<script[^>]*?\\\\bsrc=[\"']/?${clientFileEntry}([^\"']*)[\"'][^>]*?\\\\sasync\\\\b`,\n 'g',\n ),\n (match) => match.replace(/\\sasync\\b/, ''),\n );\n }\n\n return modifiedHtml.split('<!--ssr-outlet-->') as [string, string];\n }\n\n /**\n * Run server created hook\n */\n public async onAppCreated(): Promise<PrepareServer> {\n await this.loadEntrypoint();\n await this.onServerCreated?.(this.config.getApp()!, this.serverApi);\n\n return this;\n }\n\n /**\n * Return SSR express middlewares configs\n */\n public getMiddlewaresConfig(): NonNullable<PrepareServer['middlewaresConfigs']> {\n const { compression, expressStatic } = this.middlewaresConfigs ?? {};\n\n return {\n compression:\n compression !== false\n ? {\n ...(compression ?? {}),\n }\n : false,\n expressStatic:\n expressStatic !== false\n ? {\n ...(expressStatic ?? {}),\n basename: expressStatic?.basename ?? '/',\n }\n : false,\n };\n }\n}\n\nexport default PrepareServer;\n"],"names":["PrepareServer","config","serverApi","entrypoint","onServerCreated","onServerStarted","html","middlewaresConfigs","constructor","this","ServerApi","static","async","shouldInit","isProd","root","serverFile","getParams","entrypointPath","path","resolve","resolvedEntrypoint","import","pathToFileURL","toString","default","getVite","ssrLoadModule","fixStacktrace","e","Error","message","includes","getLogger","error","chalk","red","yellow","process","exit","init","render","routes","abortDelay","loggerProd","loggerDev","middlewares","setLogger","renderParams","req","indexFile","clientFile","fs","readFileSync","modifiedHtml","clientFileEntry","posix","normalize","base","transformIndexHtml","originalUrl","replace","RegExp","match","split","loadEntrypoint","getApp","getMiddlewaresConfig","compression","expressStatic","basename"],"mappings":"oKA6BA,MAAMA,EAIeC,OAKAC,UAKTC,WAKAC,gBAKHC,gBAKGC,KAKAC,mBAKVC,YAAsBP,EAAsBC,GAC1CO,KAAKR,OAASA,EACdQ,KAAKP,UAAYA,GAAa,IAAIQ,
|
|
1
|
+
{"version":3,"file":"prepare-server.js","sources":["../../src/services/prepare-server.ts"],"sourcesContent":["import fs from 'fs';\nimport path from 'node:path';\nimport process from 'node:process';\nimport { pathToFileURL } from 'node:url';\nimport chalk from 'chalk';\nimport type { Request } from 'express';\nimport type { TRouteObject } from '@interfaces/route-object';\nimport type { IEntrypointOptions, IPrepareRenderOut } from '@node/entry';\nimport type { TRender } from '@node/render';\nimport ServerApi from '@services/server-api';\nimport type ServerConfig from '@services/server-config';\n\ninterface IPrepareServerEntrypointLoadOut<TAppProps = Record<string, any>> {\n render: TRender;\n routes: TRouteObject[];\n abortDelay?: number;\n onRequest?: IEntrypointOptions<TAppProps>['onRequest'];\n onRouterReady?: IEntrypointOptions<TAppProps>['onRouterReady'];\n onShellReady?: IEntrypointOptions<TAppProps>['onShellReady'];\n onShellError?: IEntrypointOptions<TAppProps>['onShellError'];\n onResponse?: IEntrypointOptions<TAppProps>['onResponse'];\n onError?: IEntrypointOptions<TAppProps>['onError'];\n getState?: IEntrypointOptions<TAppProps>['getState'];\n}\n\n/**\n * Load server entrypoint and template\n * DEV MODE: refresh entrypoint and template\n */\nclass PrepareServer {\n /**\n * Server configuration\n */\n protected readonly config: ServerConfig;\n\n /**\n * Server API\n */\n protected readonly serverApi: ServerApi;\n\n /**\n * Entrypoint resolved params\n */\n protected entrypoint?: IPrepareServerEntrypointLoadOut;\n\n /**\n * Hook which calls after express server created\n */\n protected onServerCreated?: IEntrypointOptions['onServerCreated'];\n\n /**\n * Hook which calls after express server started\n */\n public onServerStarted?: IEntrypointOptions['onServerStarted'];\n\n /**\n * Html shell\n */\n protected html: string;\n\n /**\n * Middlewares configs\n */\n protected middlewaresConfigs?: IPrepareRenderOut['middlewares'];\n\n /**\n * @constructor\n */\n protected constructor(config: ServerConfig, serverApi?: ServerApi) {\n this.config = config;\n this.serverApi = serverApi ?? new ServerApi();\n }\n\n /**\n * Init service\n */\n public static init(config: ServerConfig, serverApi?: ServerApi): PrepareServer {\n return new PrepareServer(config, serverApi);\n }\n\n /**\n * Resolve and return entrypoint params\n */\n public async loadEntrypoint(shouldInit = true): Promise<IPrepareServerEntrypointLoadOut> {\n // load server entrypoint each time only in development mode (for fast refresh)\n if (this.entrypoint && this.config.isProd) {\n return this.entrypoint;\n }\n\n const { root, isProd, serverFile } = this.config.getParams();\n const entrypointPath = path.resolve(`${root}/${serverFile}`);\n\n let resolvedEntrypoint: IPrepareRenderOut;\n\n try {\n if (!isProd) {\n resolvedEntrypoint = (\n await this.config.getVite()!.ssrLoadModule(entrypointPath, {\n fixStacktrace: true,\n })\n ).default as IPrepareRenderOut;\n } else {\n resolvedEntrypoint = (\n (await import(pathToFileURL(entrypointPath).toString())) as { default: IPrepareRenderOut }\n ).default;\n }\n } catch (e) {\n if (\n e instanceof Error &&\n e.message.includes('Cannot find module') &&\n e.message.includes('/build/')\n ) {\n this.config\n .getLogger()\n .error(\n chalk.red(\n `Before starting the server, you need to create a build: ${chalk.yellow(\n 'ssr-boost build',\n )} or provide path to build dir: ${chalk.yellow(\n 'ssr-boost start --build-dir build',\n )}`,\n ),\n );\n\n return process.exit(1);\n }\n\n throw e;\n }\n\n if (!shouldInit && resolvedEntrypoint.init) {\n delete resolvedEntrypoint.init;\n }\n\n const { render, init, routes, abortDelay, loggerProd, loggerDev, middlewares } =\n resolvedEntrypoint;\n\n this.middlewaresConfigs = middlewares;\n\n if (loggerProd && isProd) {\n this.config.setLogger(loggerProd);\n } else if (loggerDev && !isProd) {\n this.config.setLogger(loggerDev);\n }\n\n const { onServerCreated, onServerStarted, ...renderParams } =\n (await init?.({\n config: this.config,\n })) ?? {};\n\n this.entrypoint = {\n render,\n routes,\n abortDelay,\n ...renderParams,\n };\n this.onServerCreated = onServerCreated;\n this.onServerStarted = onServerStarted;\n\n return this.entrypoint;\n }\n\n /**\n * Load and return html shell\n */\n public async loadHtml(req: Request): Promise<[string, string]> {\n const { isProd, root, indexFile, clientFile } = this.config.getParams();\n\n if (!this.html || !isProd) {\n this.html = fs.readFileSync(path.resolve(`${root}/${indexFile}`), 'utf-8');\n }\n\n let modifiedHtml = this.html;\n\n if (!isProd) {\n const clientFileEntry = path.posix.normalize(\n `${this.config.getVite()?.config.base}/${clientFile}`,\n );\n\n // Apply Vite HTML transforms. This injects the Vite HMR client,\n // and also applies HTML transforms from Vite plugins, e.g. global\n // preambles from @vitejs/plugin-react\n modifiedHtml = (\n await this.config.getVite()!.transformIndexHtml(req.originalUrl, this.html, indexFile)\n )\n // remove 'async' attribute from app entrypoint for development\n // it might cause problems with preambles from @vitejs/plugin-react\n .replace(\n new RegExp(\n `<script[^>]*?\\\\bsrc=[\"']/?${clientFileEntry}([^\"']*)[\"'][^>]*?\\\\sasync\\\\b`,\n 'g',\n ),\n (match) => match.replace(/\\sasync\\b/, ''),\n );\n }\n\n return modifiedHtml.split('<!--ssr-outlet-->') as [string, string];\n }\n\n /**\n * Run server created hook\n */\n public async onAppCreated(): Promise<PrepareServer> {\n await this.loadEntrypoint();\n await this.onServerCreated?.(this.config.getApp()!, this.serverApi);\n\n return this;\n }\n\n /**\n * Return SSR express middlewares configs\n */\n public getMiddlewaresConfig(): NonNullable<PrepareServer['middlewaresConfigs']> {\n const { compression, expressStatic } = this.middlewaresConfigs ?? {};\n\n return {\n compression:\n compression !== false\n ? {\n ...(compression ?? {}),\n }\n : false,\n expressStatic:\n expressStatic !== false\n ? {\n ...(expressStatic ?? {}),\n basename: expressStatic?.basename ?? '/',\n }\n : false,\n };\n }\n}\n\nexport default PrepareServer;\n"],"names":["PrepareServer","config","serverApi","entrypoint","onServerCreated","onServerStarted","html","middlewaresConfigs","constructor","this","ServerApi","static","async","shouldInit","isProd","root","serverFile","getParams","entrypointPath","path","resolve","resolvedEntrypoint","import","pathToFileURL","toString","default","getVite","ssrLoadModule","fixStacktrace","e","Error","message","includes","getLogger","error","chalk","red","yellow","process","exit","init","render","routes","abortDelay","loggerProd","loggerDev","middlewares","setLogger","renderParams","req","indexFile","clientFile","fs","readFileSync","modifiedHtml","clientFileEntry","posix","normalize","base","transformIndexHtml","originalUrl","replace","RegExp","match","split","loadEntrypoint","getApp","getMiddlewaresConfig","compression","expressStatic","basename"],"mappings":"oKA6BA,MAAMA,EAIeC,OAKAC,UAKTC,WAKAC,gBAKHC,gBAKGC,KAKAC,mBAKVC,YAAsBP,EAAsBC,GAC1CO,KAAKR,OAASA,EACdQ,KAAKP,UAAYA,GAAa,IAAIQ,EAM7BC,YAAYV,EAAsBC,GACvC,OAAO,IAAIF,EAAcC,EAAQC,GAM5BU,qBAAqBC,GAAa,GAEvC,GAAIJ,KAAKN,YAAcM,KAAKR,OAAOa,OACjC,OAAOL,KAAKN,WAGd,MAAMY,KAAEA,EAAID,OAAEA,EAAME,WAAEA,GAAeP,KAAKR,OAAOgB,YAC3CC,EAAiBC,EAAKC,QAAQ,GAAGL,KAAQC,KAE/C,IAAIK,EAEJ,IAQIA,EAPGP,SAQMQ,OAAOC,EAAcL,GAAgBM,aAC5CC,eAPMhB,KAAKR,OAAOyB,UAAWC,cAAcT,EAAgB,CACzDU,eAAe,KAEjBH,QAMJ,MAAOI,GACP,GACEA,aAAaC,OACbD,EAAEE,QAAQC,SAAS,uBACnBH,EAAEE,QAAQC,SAAS,WAcnB,OAZAvB,KAAKR,OACFgC,YACAC,MACCC,EAAMC,IACJ,2DAA2DD,EAAME,OAC/D,oDACiCF,EAAME,OACvC,yCAKDC,EAAQC,KAAK,GAGtB,MAAMV,GAGHhB,GAAcQ,EAAmBmB,aAC7BnB,EAAmBmB,KAG5B,MAAMC,OAAEA,EAAMD,KAAEA,EAAIE,OAAEA,EAAMC,WAAEA,EAAUC,WAAEA,EAAUC,UAAEA,EAASC,YAAEA,GAC/DzB,EAEFZ,KAAKF,mBAAqBuC,EAEtBF,GAAc9B,EAChBL,KAAKR,OAAO8C,UAAUH,GACbC,IAAc/B,GACvBL,KAAKR,OAAO8C,UAAUF,GAGxB,MAAMzC,gBAAEA,EAAeC,gBAAEA,KAAoB2C,SACpCR,IAAO,CACZvC,OAAQQ,KAAKR,WACR,CAAE,EAWX,OATAQ,KAAKN,WAAa,CAChBsC,SACAC,SACAC,gBACGK,GAELvC,KAAKL,gBAAkBA,EACvBK,KAAKJ,gBAAkBA,EAEhBI,KAAKN,WAMPS,eAAeqC,GACpB,MAAMnC,OAAEA,EAAMC,KAAEA,EAAImC,UAAEA,EAASC,WAAEA,GAAe1C,KAAKR,OAAOgB,YAEvDR,KAAKH,MAASQ,IACjBL,KAAKH,KAAO8C,EAAGC,aAAalC,EAAKC,QAAQ,GAAGL,KAAQmC,KAAc,UAGpE,IAAII,EAAe7C,KAAKH,KAExB,IAAKQ,EAAQ,CACX,MAAMyC,EAAkBpC,EAAKqC,MAAMC,UACjC,GAAGhD,KAAKR,OAAOyB,WAAWzB,OAAOyD,QAAQP,KAM3CG,SACQ7C,KAAKR,OAAOyB,UAAWiC,mBAAmBV,EAAIW,YAAanD,KAAKH,KAAM4C,IAI3EW,QACC,IAAIC,OACF,6BAA6BP,iCAC7B,MAEDQ,GAAUA,EAAMF,QAAQ,YAAa,MAI5C,OAAOP,EAAaU,MAAM,2BAMrBpD,qBAIL,aAHMH,KAAKwD,uBACLxD,KAAKL,kBAAkBK,KAAKR,OAAOiE,SAAWzD,KAAKP,YAElDO,KAMF0D,uBACL,MAAMC,YAAEA,EAAWC,cAAEA,GAAkB5D,KAAKF,oBAAsB,CAAE,EAEpE,MAAO,CACL6D,aACkB,IAAhBA,GACI,IACMA,GAAe,CAAA,GAG3BC,eACoB,IAAlBA,GACI,IACMA,GAAiB,CAAA,EACrBC,SAAUD,GAAeC,UAAY"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server-api.js","sources":["../../src/services/server-api.ts"],"sourcesContent":["/**\n * Allow to configure server on fly\n */\nclass ServerApi {\n /**\n * Block access to index.html\n */\n protected isAllowIndexHtml = false;\n\n /**\n * Server can return index.html\n */\n public hasAccessIndexHtml(): boolean {\n return this.isAllowIndexHtml;\n }\n\n /**\n * Allow/disallow return index.html on request\n */\n public changeAccessIndexHtml(isAllowed: boolean): void {\n this.isAllowIndexHtml = isAllowed;\n }\n}\n\nexport default ServerApi;\n"],"names":["ServerApi","isAllowIndexHtml","hasAccessIndexHtml","this","changeAccessIndexHtml","isAllowed"],"mappings":"AAGA,MAAMA,EAIMC,kBAAmB,EAKtBC,qBACL,OAAOC,KAAKF,
|
|
1
|
+
{"version":3,"file":"server-api.js","sources":["../../src/services/server-api.ts"],"sourcesContent":["/**\n * Allow to configure server on fly\n */\nclass ServerApi {\n /**\n * Block access to index.html\n */\n protected isAllowIndexHtml = false;\n\n /**\n * Server can return index.html\n */\n public hasAccessIndexHtml(): boolean {\n return this.isAllowIndexHtml;\n }\n\n /**\n * Allow/disallow return index.html on request\n */\n public changeAccessIndexHtml(isAllowed: boolean): void {\n this.isAllowIndexHtml = isAllowed;\n }\n}\n\nexport default ServerApi;\n"],"names":["ServerApi","isAllowIndexHtml","hasAccessIndexHtml","this","changeAccessIndexHtml","isAllowed"],"mappings":"AAGA,MAAMA,EAIMC,kBAAmB,EAKtBC,qBACL,OAAOC,KAAKF,iBAMPG,sBAAsBC,GAC3BF,KAAKF,iBAAmBI"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server-config.js","sources":["../../src/services/server-config.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport type { Express } from 'express';\nimport type { Logger, ViteDevServer } from 'vite';\nimport type { IPluginConfig } from '@helpers/plugin-config';\nimport getPluginConfig from '@helpers/plugin-config';\nimport type { IBuildEntrypoint } from '@services/build';\nimport DefaultLogger from '@services/logger';\n\ninterface IConfigOptions {\n isProd?: boolean;\n isHost?: boolean;\n isOnlyClient?: boolean; // SPA mode\n isModulePreload?: boolean;\n mode?: string;\n entrypointName?: string;\n}\n\ninterface IConfigParams {\n root: string;\n publicDir: string;\n pluginPath: string;\n isProd: boolean;\n isSPA: boolean;\n indexFile: string;\n clientFile: string;\n serverFile: string;\n host: string;\n port: number;\n}\n\n/**\n * Server config\n */\nclass ServerConfig {\n /**\n * Production build\n */\n public readonly isProd: boolean;\n\n /**\n * Server host mode\n */\n public readonly isHost: boolean;\n\n /**\n * Add module preload scripts to server output\n */\n public readonly isModulePreload: boolean;\n\n /**\n * Env mode\n */\n public readonly mode: string;\n\n /**\n * Run specified entrypoint\n */\n protected readonly entrypointName?: string;\n\n /**\n * Vite config - only for development\n */\n protected vite?: ViteDevServer;\n\n /**\n * Express application\n */\n protected app?: Express;\n\n /**\n * Config params\n */\n protected params: IConfigParams;\n\n /**\n * Default params\n */\n protected defaultParams: Partial<IConfigParams>;\n\n /**\n * Vite logger for dev mode or console for production\n */\n protected logger: Logger;\n\n /**\n * Default root dir\n */\n protected defaultBuildRoots = ['./build', './dist'];\n\n /**\n * @constructor\n */\n protected constructor(\n {\n entrypointName,\n isProd = false,\n isHost = false,\n isOnlyClient = false,\n isModulePreload = false,\n mode = 'production',\n }: IConfigOptions,\n prodParams: Partial<IConfigParams>,\n ) {\n this.isProd = isProd;\n this.isHost = isHost;\n this.isModulePreload = isModulePreload;\n this.mode = mode;\n this.entrypointName = entrypointName;\n this.defaultParams = {\n publicDir: '/client', // default for production,\n indexFile: '/client/index.html',\n serverFile: '/server/server.js',\n host: '127.0.0.1',\n isSPA: isOnlyClient,\n ...prodParams,\n };\n\n this.makeParams();\n }\n\n /**\n * Initialize service\n */\n public static init(\n options: IConfigOptions = {},\n prodOptions: Partial<IConfigParams> = {},\n ): ServerConfig {\n return new ServerConfig(options, prodOptions);\n }\n\n /**\n * Lookup build folder\n */\n protected getBuildDir(root?: string): string {\n for (const dir of [root, ...this.defaultBuildRoots]) {\n if (dir && fs.existsSync(dir)) {\n return dir;\n }\n }\n\n return root ?? this.defaultBuildRoots[0];\n }\n\n /**\n * Make config params\n */\n protected makeParams(): void {\n this.applyEntrypointConfig();\n\n const pluginConfig = (this.getPluginConfig() ?? {}) as Partial<IPluginConfig>;\n const { config } = this.vite ?? {};\n const {\n root,\n publicDir,\n indexFile,\n clientFile,\n serverFile,\n host: defaultHost,\n isSPA,\n } = this.defaultParams;\n const dirInfo = new URL(import.meta.url);\n const pluginPath =\n pluginConfig.pluginPath ?? path.resolve(path.dirname(dirInfo.pathname), '../');\n const entrypoint = this.getEntrypoint();\n\n const host =\n typeof config?.server.host === 'boolean' || this.isHost\n ? '0.0.0.0'\n : (config?.server.host ?? defaultHost!);\n const port = Number(config?.env.VITE_PORT ?? config?.server.port ?? this.defaultParams.port!);\n\n this.params = {\n root: config?.root ?? this.getBuildDir(root),\n publicDir: config?.publicDir ?? publicDir!,\n indexFile: pluginConfig.indexFile ?? indexFile!,\n clientFile: pluginConfig.clientFile ?? clientFile!,\n serverFile: pluginConfig.serverFile ?? serverFile!,\n pluginPath,\n host,\n port,\n isSPA: entrypoint ? entrypoint.type === 'spa' : isSPA!,\n isProd: this.isProd,\n };\n this.logger = this.vite?.config.logger ?? new DefaultLogger();\n }\n\n /**\n * Set vite server\n */\n public setVite(vite: ViteDevServer): void {\n this.vite = vite;\n\n this.makeParams();\n }\n\n /**\n * Set express server\n */\n public setApp(express: Express): void {\n this.app = express;\n }\n\n /**\n * Return vite dev server\n * NOTE: only on development mode\n */\n public getVite(): ViteDevServer | undefined {\n return this.vite;\n }\n\n /**\n * Return express server\n */\n public getApp(): Express | undefined {\n return this.app;\n }\n\n /**\n * Return plugin config\n * NOTE: only on development mode\n */\n public getPluginConfig(): IPluginConfig | undefined {\n return this.vite ? getPluginConfig(this.vite.config) : undefined;\n }\n\n /**\n * Return config params\n */\n public getParams(): IConfigParams {\n return this.params;\n }\n\n /**\n * Get server logger\n */\n public getLogger(): Logger {\n return this.logger;\n }\n\n /**\n * Set custom logger\n */\n public setLogger(logger: Logger): void {\n this.logger = logger;\n }\n\n /**\n * Apply config to specified entrypoint\n */\n protected applyEntrypointConfig(): void {\n const config = this.getPluginConfig();\n\n if (!this.vite || !config || !this.entrypointName) {\n return;\n }\n\n const entrypointConfig = this.getEntrypoint();\n\n // apply specified entrypoint config\n if (entrypointConfig) {\n (['indexFile', 'clientFile', 'serverFile'] as const).forEach((optName) => {\n if (entrypointConfig[optName]) {\n config[optName] = entrypointConfig[optName]!;\n }\n });\n }\n }\n\n /**\n * Get current entrypoint\n */\n protected getEntrypoint(): IBuildEntrypoint | undefined {\n const config = this.vite ? getPluginConfig(this.vite.config) : undefined;\n\n return config?.entrypoint?.find(({ name }) => name === this.entrypointName);\n }\n}\n\nexport default ServerConfig;\n"],"names":["ServerConfig","isProd","isHost","isModulePreload","mode","entrypointName","vite","app","params","defaultParams","logger","defaultBuildRoots","constructor","isOnlyClient","prodParams","this","publicDir","indexFile","serverFile","host","isSPA","makeParams","static","options","prodOptions","getBuildDir","root","dir","fs","existsSync","applyEntrypointConfig","pluginConfig","getPluginConfig","config","clientFile","defaultHost","dirInfo","URL","url","pluginPath","path","resolve","dirname","pathname","entrypoint","getEntrypoint","server","port","Number","env","VITE_PORT","type","DefaultLogger","setVite","setApp","express","getVite","getApp","undefined","getParams","getLogger","setLogger","entrypointConfig","forEach","optName","find","name"],"mappings":"sHAkCA,MAAMA,EAIYC,OAKAC,OAKAC,gBAKAC,KAKGC,eAKTC,KAKAC,IAKAC,OAKAC,cAKAC,OAKAC,kBAAoB,CAAC,UAAW,UAK1CC,aACEP,eACEA,EAAcJ,OACdA,GAAS,EAAKC,OACdA,GAAS,EAAKW,aACdA,GAAe,EAAKV,gBACpBA,GAAkB,EAAKC,KACvBA,EAAO,cAETU,GAEAC,KAAKd,OAASA,EACdc,KAAKb,OAASA,EACda,KAAKZ,gBAAkBA,EACvBY,KAAKX,KAAOA,EACZW,KAAKV,eAAiBA,EACtBU,KAAKN,cAAgB,CACnBO,UAAW,UACXC,UAAW,qBACXC,WAAY,oBACZC,KAAM,YACNC,MAAOP,KACJC,GAGLC,KAAKM,
|
|
1
|
+
{"version":3,"file":"server-config.js","sources":["../../src/services/server-config.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport type { Express } from 'express';\nimport type { Logger, ViteDevServer } from 'vite';\nimport type { IPluginConfig } from '@helpers/plugin-config';\nimport getPluginConfig from '@helpers/plugin-config';\nimport type { IBuildEntrypoint } from '@services/build';\nimport DefaultLogger from '@services/logger';\n\ninterface IConfigOptions {\n isProd?: boolean;\n isHost?: boolean;\n isOnlyClient?: boolean; // SPA mode\n isModulePreload?: boolean;\n mode?: string;\n entrypointName?: string;\n}\n\ninterface IConfigParams {\n root: string;\n publicDir: string;\n pluginPath: string;\n isProd: boolean;\n isSPA: boolean;\n indexFile: string;\n clientFile: string;\n serverFile: string;\n host: string;\n port: number;\n}\n\n/**\n * Server config\n */\nclass ServerConfig {\n /**\n * Production build\n */\n public readonly isProd: boolean;\n\n /**\n * Server host mode\n */\n public readonly isHost: boolean;\n\n /**\n * Add module preload scripts to server output\n */\n public readonly isModulePreload: boolean;\n\n /**\n * Env mode\n */\n public readonly mode: string;\n\n /**\n * Run specified entrypoint\n */\n protected readonly entrypointName?: string;\n\n /**\n * Vite config - only for development\n */\n protected vite?: ViteDevServer;\n\n /**\n * Express application\n */\n protected app?: Express;\n\n /**\n * Config params\n */\n protected params: IConfigParams;\n\n /**\n * Default params\n */\n protected defaultParams: Partial<IConfigParams>;\n\n /**\n * Vite logger for dev mode or console for production\n */\n protected logger: Logger;\n\n /**\n * Default root dir\n */\n protected defaultBuildRoots = ['./build', './dist'];\n\n /**\n * @constructor\n */\n protected constructor(\n {\n entrypointName,\n isProd = false,\n isHost = false,\n isOnlyClient = false,\n isModulePreload = false,\n mode = 'production',\n }: IConfigOptions,\n prodParams: Partial<IConfigParams>,\n ) {\n this.isProd = isProd;\n this.isHost = isHost;\n this.isModulePreload = isModulePreload;\n this.mode = mode;\n this.entrypointName = entrypointName;\n this.defaultParams = {\n publicDir: '/client', // default for production,\n indexFile: '/client/index.html',\n serverFile: '/server/server.js',\n host: '127.0.0.1',\n isSPA: isOnlyClient,\n ...prodParams,\n };\n\n this.makeParams();\n }\n\n /**\n * Initialize service\n */\n public static init(\n options: IConfigOptions = {},\n prodOptions: Partial<IConfigParams> = {},\n ): ServerConfig {\n return new ServerConfig(options, prodOptions);\n }\n\n /**\n * Lookup build folder\n */\n protected getBuildDir(root?: string): string {\n for (const dir of [root, ...this.defaultBuildRoots]) {\n if (dir && fs.existsSync(dir)) {\n return dir;\n }\n }\n\n return root ?? this.defaultBuildRoots[0];\n }\n\n /**\n * Make config params\n */\n protected makeParams(): void {\n this.applyEntrypointConfig();\n\n const pluginConfig = (this.getPluginConfig() ?? {}) as Partial<IPluginConfig>;\n const { config } = this.vite ?? {};\n const {\n root,\n publicDir,\n indexFile,\n clientFile,\n serverFile,\n host: defaultHost,\n isSPA,\n } = this.defaultParams;\n const dirInfo = new URL(import.meta.url);\n const pluginPath =\n pluginConfig.pluginPath ?? path.resolve(path.dirname(dirInfo.pathname), '../');\n const entrypoint = this.getEntrypoint();\n\n const host =\n typeof config?.server.host === 'boolean' || this.isHost\n ? '0.0.0.0'\n : (config?.server.host ?? defaultHost!);\n const port = Number(config?.env.VITE_PORT ?? config?.server.port ?? this.defaultParams.port!);\n\n this.params = {\n root: config?.root ?? this.getBuildDir(root),\n publicDir: config?.publicDir ?? publicDir!,\n indexFile: pluginConfig.indexFile ?? indexFile!,\n clientFile: pluginConfig.clientFile ?? clientFile!,\n serverFile: pluginConfig.serverFile ?? serverFile!,\n pluginPath,\n host,\n port,\n isSPA: entrypoint ? entrypoint.type === 'spa' : isSPA!,\n isProd: this.isProd,\n };\n this.logger = this.vite?.config.logger ?? new DefaultLogger();\n }\n\n /**\n * Set vite server\n */\n public setVite(vite: ViteDevServer): void {\n this.vite = vite;\n\n this.makeParams();\n }\n\n /**\n * Set express server\n */\n public setApp(express: Express): void {\n this.app = express;\n }\n\n /**\n * Return vite dev server\n * NOTE: only on development mode\n */\n public getVite(): ViteDevServer | undefined {\n return this.vite;\n }\n\n /**\n * Return express server\n */\n public getApp(): Express | undefined {\n return this.app;\n }\n\n /**\n * Return plugin config\n * NOTE: only on development mode\n */\n public getPluginConfig(): IPluginConfig | undefined {\n return this.vite ? getPluginConfig(this.vite.config) : undefined;\n }\n\n /**\n * Return config params\n */\n public getParams(): IConfigParams {\n return this.params;\n }\n\n /**\n * Get server logger\n */\n public getLogger(): Logger {\n return this.logger;\n }\n\n /**\n * Set custom logger\n */\n public setLogger(logger: Logger): void {\n this.logger = logger;\n }\n\n /**\n * Apply config to specified entrypoint\n */\n protected applyEntrypointConfig(): void {\n const config = this.getPluginConfig();\n\n if (!this.vite || !config || !this.entrypointName) {\n return;\n }\n\n const entrypointConfig = this.getEntrypoint();\n\n // apply specified entrypoint config\n if (entrypointConfig) {\n (['indexFile', 'clientFile', 'serverFile'] as const).forEach((optName) => {\n if (entrypointConfig[optName]) {\n config[optName] = entrypointConfig[optName]!;\n }\n });\n }\n }\n\n /**\n * Get current entrypoint\n */\n protected getEntrypoint(): IBuildEntrypoint | undefined {\n const config = this.vite ? getPluginConfig(this.vite.config) : undefined;\n\n return config?.entrypoint?.find(({ name }) => name === this.entrypointName);\n }\n}\n\nexport default ServerConfig;\n"],"names":["ServerConfig","isProd","isHost","isModulePreload","mode","entrypointName","vite","app","params","defaultParams","logger","defaultBuildRoots","constructor","isOnlyClient","prodParams","this","publicDir","indexFile","serverFile","host","isSPA","makeParams","static","options","prodOptions","getBuildDir","root","dir","fs","existsSync","applyEntrypointConfig","pluginConfig","getPluginConfig","config","clientFile","defaultHost","dirInfo","URL","url","pluginPath","path","resolve","dirname","pathname","entrypoint","getEntrypoint","server","port","Number","env","VITE_PORT","type","DefaultLogger","setVite","setApp","express","getVite","getApp","undefined","getParams","getLogger","setLogger","entrypointConfig","forEach","optName","find","name"],"mappings":"sHAkCA,MAAMA,EAIYC,OAKAC,OAKAC,gBAKAC,KAKGC,eAKTC,KAKAC,IAKAC,OAKAC,cAKAC,OAKAC,kBAAoB,CAAC,UAAW,UAK1CC,aACEP,eACEA,EAAcJ,OACdA,GAAS,EAAKC,OACdA,GAAS,EAAKW,aACdA,GAAe,EAAKV,gBACpBA,GAAkB,EAAKC,KACvBA,EAAO,cAETU,GAEAC,KAAKd,OAASA,EACdc,KAAKb,OAASA,EACda,KAAKZ,gBAAkBA,EACvBY,KAAKX,KAAOA,EACZW,KAAKV,eAAiBA,EACtBU,KAAKN,cAAgB,CACnBO,UAAW,UACXC,UAAW,qBACXC,WAAY,oBACZC,KAAM,YACNC,MAAOP,KACJC,GAGLC,KAAKM,aAMAC,YACLC,EAA0B,GAC1BC,EAAsC,CAAA,GAEtC,OAAO,IAAIxB,EAAauB,EAASC,GAMzBC,YAAYC,GACpB,IAAK,MAAMC,IAAO,CAACD,KAASX,KAAKJ,mBAC/B,GAAIgB,GAAOC,EAAGC,WAAWF,GACvB,OAAOA,EAIX,OAAOD,GAAQX,KAAKJ,kBAAkB,GAM9BU,aACRN,KAAKe,wBAEL,MAAMC,EAAgBhB,KAAKiB,mBAAqB,CAAA,GAC1CC,OAAEA,GAAWlB,KAAKT,MAAQ,CAAE,GAC5BoB,KACJA,EAAIV,UACJA,EAASC,UACTA,EAASiB,WACTA,EAAUhB,WACVA,EACAC,KAAMgB,EAAWf,MACjBA,GACEL,KAAKN,cACH2B,EAAU,IAAIC,gBAAgBC,KAC9BC,EACJR,EAAaQ,YAAcC,EAAKC,QAAQD,EAAKE,QAAQN,EAAQO,UAAW,OACpEC,EAAa7B,KAAK8B,gBAElB1B,EAC2B,kBAAxBc,GAAQa,OAAO3B,MAAsBJ,KAAKb,OAC7C,UACC+B,GAAQa,OAAO3B,MAAQgB,EACxBY,EAAOC,OAAOf,GAAQgB,IAAIC,WAAajB,GAAQa,OAAOC,MAAQhC,KAAKN,cAAcsC,MAEvFhC,KAAKP,OAAS,CACZkB,KAAMO,GAAQP,MAAQX,KAAKU,YAAYC,GACvCV,UAAWiB,GAAQjB,WAAaA,EAChCC,UAAWc,EAAad,WAAaA,EACrCiB,WAAYH,EAAaG,YAAcA,EACvChB,WAAYa,EAAab,YAAcA,EACvCqB,aACApB,OACA4B,OACA3B,MAAOwB,EAAiC,QAApBA,EAAWO,KAAiB/B,EAChDnB,OAAQc,KAAKd,QAEfc,KAAKL,OAASK,KAAKT,MAAM2B,OAAOvB,QAAU,IAAI0C,EAMzCC,QAAQ/C,GACbS,KAAKT,KAAOA,EAEZS,KAAKM,aAMAiC,OAAOC,GACZxC,KAAKR,IAAMgD,EAONC,UACL,OAAOzC,KAAKT,KAMPmD,SACL,OAAO1C,KAAKR,IAOPyB,kBACL,OAAOjB,KAAKT,KAAO0B,EAAgBjB,KAAKT,KAAK2B,aAAUyB,EAMlDC,YACL,OAAO5C,KAAKP,OAMPoD,YACL,OAAO7C,KAAKL,OAMPmD,UAAUnD,GACfK,KAAKL,OAASA,EAMNoB,wBACR,MAAMG,EAASlB,KAAKiB,kBAEpB,IAAKjB,KAAKT,OAAS2B,IAAWlB,KAAKV,eACjC,OAGF,MAAMyD,EAAmB/C,KAAK8B,gBAG1BiB,GACD,CAAC,YAAa,aAAc,cAAwBC,SAASC,IACxDF,EAAiBE,KACnB/B,EAAO+B,GAAWF,EAAiBE,OASjCnB,gBACR,MAAMZ,EAASlB,KAAKT,KAAO0B,EAAgBjB,KAAKT,KAAK2B,aAAUyB,EAE/D,OAAOzB,GAAQW,YAAYqB,MAAK,EAAGC,UAAWA,IAASnD,KAAKV"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
import { Socket } from 'node:net';
|
|
3
|
-
import {
|
|
3
|
+
import { RouterState } from 'react-router';
|
|
4
4
|
import { Alias, ModuleNode } from 'vite';
|
|
5
5
|
import { IRequestContext } from "../node/render.js";
|
|
6
6
|
import { TRoutesTree } from "./parse-routes.js";
|
|
@@ -123,13 +123,6 @@ declare class SsrManifest {
|
|
|
123
123
|
* Load assets manifest
|
|
124
124
|
*/
|
|
125
125
|
protected loadAssetsManifest(): Record<string, IAsset[]>;
|
|
126
|
-
/**
|
|
127
|
-
* Recursive walk routes and return id's with route import path
|
|
128
|
-
*/
|
|
129
|
-
/**
|
|
130
|
-
* Recursive walk routes and return id's with route import path
|
|
131
|
-
*/
|
|
132
|
-
protected getAsyncRoutesIds(routes: RouteObject[], index?: string): Promise<Record<string, string | undefined>>;
|
|
133
126
|
/**
|
|
134
127
|
* Same as 'getAsyncRoutesIds' but for routes tree from 'ParseRoutes'
|
|
135
128
|
*/
|
|
@@ -157,7 +150,7 @@ declare class SsrManifest {
|
|
|
157
150
|
/**
|
|
158
151
|
* Build routes manifest file
|
|
159
152
|
*/
|
|
160
|
-
buildRoutesManifest(
|
|
153
|
+
buildRoutesManifest(): void;
|
|
161
154
|
/**
|
|
162
155
|
* Get route assets
|
|
163
156
|
*/
|
package/services/ssr-manifest.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import
|
|
1
|
+
import e from"node:fs";import t from"node:path";import s from"chalk";import i from"./parse-routes.js";import r from"./path-normalize.js";var n;!function(e){e.style="style",e.script="script",e.image="image",e.font="font"}(n||(n={}));const o="\r\n";class a{static instance=null;config;pathNormalize;root;buildDir;manifestName="manifest.json";assetsManifest="assets-manifest.json";viteAliases;basename;routesAssets=null;constructor(e,{buildDir:t,viteAliases:s,basename:i}={}){this.config=e,this.root=e.getParams().root,this.buildDir=t,this.viteAliases=s??e.getVite()?.config?.resolve.alias,this.pathNormalize=new r(e,s),this.basename=i}static get(e,t={}){return null===a.instance&&(a.instance=new a(e,t)),a.instance}getOutDir(){return t.resolve(this.root,this.buildDir||"")}getAssetsManifestFile(){return`${this.getOutDir()}/server/${this.assetsManifest}`}loadClientManifest(){const s=t.resolve(this.root,`${this.buildDir||""}/client/.vite`),i=`${s}/${this.manifestName}`;if(!e.existsSync(i))return{};const r=JSON.parse(e.readFileSync(i,{encoding:"utf-8"}));return e.rmSync(i),0===e.readdirSync(s).length&&e.rmSync(s,{recursive:!0}),r}loadAssetsManifest(){if(null!==this.routesAssets)return this.routesAssets;const t=this.getAssetsManifestFile();return e.existsSync(t)?(this.routesAssets=JSON.parse(e.readFileSync(t,{encoding:"utf-8"})),this.routesAssets):{}}getRoutesTreeIds(e,t){const s={};return e.forEach(((e,i)=>{const r=[t,String(i)].filter(Boolean).join("-");e.import&&(s[r]=this.pathNormalize.getAppPath(e.import)),e.children.length>0&&Object.assign(s,this.getRoutesTreeIds(e.children,r))})),s}sortAssets(e){return e.sort(((e,t)=>e.weight===t.weight?Number(e.isNested)-Number(t.isNested):e.weight-t.weight))}getRouteAssets(e,s,i=!1){const r=[...s?.assets??[],...s?.css??[],s?.file].reduce(((e,r)=>{if(r){const n=this.getAssetType(r),o=s.isEntry&&s.file===r;n&&(e[r]={url:t.posix.normalize(`${this.basename}/${r}`),weight:o?1.9:this.getAssetWeight(r),type:n,isNested:i,isPreload:!o})}return e}),{});return s?.imports?.length&&s.imports.forEach((t=>{const s=e[t];s&&Object.assign(r,this.getRouteAssets(e,s,!0))})),r}buildRoutesManifest(){const t=this.loadClientManifest(),s=new i(this.config,this.viteAliases),r=this.getRoutesTreeIds(s.parse()),n=this.pathNormalize.getImportPostfix(),o={};Object.entries(r).forEach((([e,s])=>{const i=n.find((e=>void 0!==t[`${s}${e}`])),r=t[`${s}${i||""}`];o[e]=this.sortAssets(Object.values(this.getRouteAssets(t,r)))})),e.writeFileSync(this.getAssetsManifestFile(),JSON.stringify(o,null,2),{encoding:"utf-8"})}getAssets(e){if(this.config.getVite())return this.getAssetsDev(e);const t=e?.map((({route:e})=>e.id)).filter(Boolean)??[];if(!t.length)return[];const s=this.loadAssetsManifest();return this.sortAssets(t.map((e=>s[e])).flat().filter(Boolean))}getAssetsDev(e){const s=e?.map((({route:e})=>this.pathNormalize.getAppPath(e?.pathId,!0))).filter(Boolean)??[];if(!s.length)return[];let i={};const r=this.pathNormalize.getImportPostfix();return[t.resolve(this.root,this.config.getPluginConfig()?.clientFile??"client.ts"),...s].forEach((e=>{for(const t of r){const s=this.config.getVite()?.moduleGraph.getModuleById(`${e}${t}`);if(s){i={...i,...this.getModuleAssets(s)};break}}})),Object.values(i)}getModuleAssets(e,t=new Set){if(!e?.clientImportedModules.size||t.has(e.file))return{};let i={};return t.add(e.file),e.clientImportedModules.forEach((e=>{const{file:r,clientImportedModules:o,transformResult:a}=e,l=r?.split(".").at(-1);if(r&&l&&["css","scss"].includes(l)){const e=a?.code.match(/__vite__css\s+=\s+"(?<css>.+)"/)?.groups?.css;if(e)try{i[r]={type:n.style,url:r,weight:this.getAssetWeight(r),content:JSON.parse(`{"style": "${e}"}`).style,isNested:Boolean(t.size),isPreload:!1}}catch(e){console.warn(s.yellowBright("Failed to parse style: ",r))}}else o.size&&(i={...i,...this.getModuleAssets(e,t)})})),i}getAssetWeight(e){switch(this.getAssetType(e)){case n.style:return 1;case n.script:return 2;default:return 3}}getAssetType(e){const t=e.split(".").at(-1)?.toLowerCase();switch(t){case"css":case"scss":return n.style;case"js":return n.script;case"svg":case"jpg":case"jpeg":case"png":case"webp":case"gif":case"ico":return n.image;case"ttf":case"otf":case"woff":case"woff2":return n.font;default:return null}}writeEarlyHits(e,t){t.write(`HTTP/1.1 103 Early Hints${o}`),e.forEach((({type:e,url:s})=>{e&&["style","script"].includes(e)&&t.write(`Link: <${s}>; rel=preload; as=${e}${o}`)})),t.write(o)}injectAssets({routerContext:e,html:t,res:s,hasEarlyHints:i=!1}){const r=this.getAssets(e?.matches),o=r.map((({type:e,url:t,isPreload:s,content:i=""})=>{switch(e){case n.style:return this.config.getVite()?`<style data-vite-dev-id="${t}">${i}</style>`:`<link rel="stylesheet" href="${t}">`;case n.script:return s?this.config.isModulePreload?`<link rel="modulepreload" as="script" crossorigin href="${t}">`:null:`<script async type="module" crossorigin src="${t}"><\/script>`}return null})).filter(Boolean);t.header=t.header.replace("</head>",`${o.join("\n")}</head>`),i&&o.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 chalk from 'chalk';\nimport type { RouteObject, RouterState } from 'react-router';\nimport type { Alias, ModuleNode } from 'vite';\nimport type { IAsyncRoute } from '@helpers/import-route';\nimport type { IRequestContext } from '@node/render';\nimport type { TRoutesTree } from '@services/parse-routes';\nimport ParseRoutes from '@services/parse-routes';\nimport PathNormalize from '@services/path-normalize';\nimport PrepareServer from '@services/prepare-server';\nimport ServerConfig from '@services/server-config';\n\ninterface ISsrManifestParams {\n buildDir?: string;\n viteAliases?: Alias[];\n basename?: string;\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\ntype TAssets = { [id: string]: IAsset };\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 * Path normalize service\n */\n protected readonly pathNormalize: PathNormalize;\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 * Vite base\n */\n protected readonly basename?: string;\n\n /**\n * Loaded assets manifest file\n */\n protected routesAssets: Record<string, IAsset[]> | null = null;\n\n /**\n * @constructor\n */\n protected constructor(\n config: ServerConfig,\n { buildDir, viteAliases, basename }: ISsrManifestParams = {},\n ) {\n this.config = config;\n this.root = config.getParams().root;\n this.buildDir = buildDir;\n this.viteAliases = viteAliases ?? config.getVite()?.config?.resolve.alias;\n this.pathNormalize = new PathNormalize(config, viteAliases);\n this.basename = basename;\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 output dir\n */\n protected getOutDir() {\n return path.resolve(this.root, this.buildDir || '');\n }\n\n /**\n * Get assets manifest file name\n */\n protected getAssetsManifestFile(): string {\n return `${this.getOutDir()}/server/${this.assetsManifest}`;\n }\n\n /**\n * Load client ssr manifest\n */\n protected loadClientManifest(): IManifest {\n const clientManifestDir = path.resolve(this.root, `${this.buildDir || ''}/client/.vite`);\n const clientSsrManifest = `${clientManifestDir}/${this.manifestName}`;\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 // try to remove empty .vite dir\n if (fs.readdirSync(clientManifestDir).length === 0) {\n fs.rmSync(clientManifestDir, { recursive: true });\n }\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 getAsyncRoutesIds(\n routes: RouteObject[],\n index?: string,\n ): Promise<Record<string, string | undefined>> {\n const result: Record<string, string | undefined> = {};\n\n // reason: await + array index\n // eslint-disable-next-line @typescript-eslint/no-for-in-array\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.pathNormalize.getAppPath(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.getAsyncRoutesIds(route.children, routeId));\n }\n }\n\n return result;\n }\n\n /**\n * Same as 'getAsyncRoutesIds' but for routes tree from 'ParseRoutes'\n */\n protected getRoutesTreeIds(\n routes: TRoutesTree[],\n index?: string,\n ): Record<string, string | undefined> {\n const result: Record<string, string | undefined> = {};\n\n routes.forEach((route, routeIndex) => {\n const routeId = [index, String(routeIndex)].filter(Boolean).join('-');\n\n if (route.import) {\n result[routeId] = this.pathNormalize.getAppPath(route.import);\n }\n\n if (route.children.length > 0) {\n Object.assign(result, this.getRoutesTreeIds(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: path.posix.normalize(`${this.basename}/${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(isNodeParsing: boolean): Promise<void> {\n const prepareServer = PrepareServer.init(\n ServerConfig.init({ isProd: true }, { root: this.getOutDir() }),\n );\n const manifest = this.loadClientManifest();\n let routesPaths: Record<string, string | undefined>;\n\n if (isNodeParsing) {\n const { routes } = await prepareServer.loadEntrypoint(false);\n\n routesPaths = await this.getAsyncRoutesIds(routes as RouteObject[]);\n } else {\n const routesService = new ParseRoutes(this.config, this.viteAliases);\n\n routesPaths = this.getRoutesTreeIds(routesService.parse());\n }\n\n const postfixes = this.pathNormalize.getImportPostfix();\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 route assets\n */\n protected getAssets(routes?: RouterState['matches']): 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?: RouterState['matches']): IAsset[] {\n const routeIds =\n (routes\n ?.map(({ route }) => this.pathNormalize.getAppPath((route as IAsyncRoute)?.pathId, true))\n .filter(Boolean) as string[]) ?? [];\n\n if (!routeIds.length) {\n return [];\n }\n\n let assets: TAssets = {};\n const postfixes = this.pathNormalize.getImportPostfix();\n const rootId = path.resolve(\n this.root,\n this.config.getPluginConfig()?.clientFile ?? 'client.ts',\n );\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, skipModules: Set<string> = new Set()): TAssets {\n if (!module?.clientImportedModules.size || skipModules.has(module.file!)) {\n return {};\n }\n\n let assets: TAssets = {};\n\n skipModules.add(module.file!);\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}\"}`) as { style: string }).style,\n isNested: Boolean(skipModules.size),\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, skipModules),\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","pathNormalize","root","buildDir","manifestName","assetsManifest","viteAliases","basename","routesAssets","constructor","this","getParams","getVite","resolve","alias","PathNormalize","params","instance","getOutDir","path","getAssetsManifestFile","loadClientManifest","clientManifestDir","clientSsrManifest","fs","existsSync","result","JSON","parse","readFileSync","encoding","rmSync","readdirSync","length","recursive","loadAssetsManifest","manifestFile","async","routes","index","routeIndex","route","routeId","filter","Boolean","join","lazy","resolvedRoute","getAppPath","pathId","e","console","error","chalk","red","children","Object","assign","getAsyncRoutesIds","getRoutesTreeIds","forEach","String","import","sortAssets","assets","sort","a","b","weight","Number","isNested","getRouteAssets","manifest","module","css","file","reduce","res","asset","type","getAssetType","isEntry","url","posix","normalize","getAssetWeight","isPreload","imports","nestedAsset","nestedModule","isNodeParsing","prepareServer","PrepareServer","init","ServerConfig","isProd","routesPaths","loadEntrypoint","routesService","ParseRoutes","postfixes","getImportPostfix","entries","routePath","routePostfix","find","postfix","undefined","routeMeta","values","writeFileSync","stringify","getAssets","getAssetsDev","routeIds","map","id","flat","getPluginConfig","clientFile","moduleId","ext","moduleGraph","getModuleById","getModuleAssets","skipModules","Set","clientImportedModules","size","has","add","subModule","transformResult","split","at","includes","code","match","groups","style","content","warn","yellowBright","script","toLowerCase","image","font","writeEarlyHits","socket","write","injectAssets","routerContext","html","hasEarlyHints","matches","htmlAssets","isModulePreload","header","replace"],"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 chalk from 'chalk';\nimport type { RouterState } from 'react-router';\nimport type { Alias, ModuleNode } from 'vite';\nimport type { IAsyncRoute } from '@helpers/import-route';\nimport type { IRequestContext } from '@node/render';\nimport type { TRoutesTree } from '@services/parse-routes';\nimport ParseRoutes from '@services/parse-routes';\nimport PathNormalize from '@services/path-normalize';\nimport type ServerConfig from '@services/server-config';\n\ninterface ISsrManifestParams {\n buildDir?: string;\n viteAliases?: Alias[];\n basename?: string;\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\ntype TAssets = { [id: string]: IAsset };\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 * Path normalize service\n */\n protected readonly pathNormalize: PathNormalize;\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 * Vite base\n */\n protected readonly basename?: string;\n\n /**\n * Loaded assets manifest file\n */\n protected routesAssets: Record<string, IAsset[]> | null = null;\n\n /**\n * @constructor\n */\n protected constructor(\n config: ServerConfig,\n { buildDir, viteAliases, basename }: ISsrManifestParams = {},\n ) {\n this.config = config;\n this.root = config.getParams().root;\n this.buildDir = buildDir;\n this.viteAliases = viteAliases ?? config.getVite()?.config?.resolve.alias;\n this.pathNormalize = new PathNormalize(config, viteAliases);\n this.basename = basename;\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 output dir\n */\n protected getOutDir() {\n return path.resolve(this.root, this.buildDir || '');\n }\n\n /**\n * Get assets manifest file name\n */\n protected getAssetsManifestFile(): string {\n return `${this.getOutDir()}/server/${this.assetsManifest}`;\n }\n\n /**\n * Load client ssr manifest\n */\n protected loadClientManifest(): IManifest {\n const clientManifestDir = path.resolve(this.root, `${this.buildDir || ''}/client/.vite`);\n const clientSsrManifest = `${clientManifestDir}/${this.manifestName}`;\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 // try to remove empty .vite dir\n if (fs.readdirSync(clientManifestDir).length === 0) {\n fs.rmSync(clientManifestDir, { recursive: true });\n }\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 * Same as 'getAsyncRoutesIds' but for routes tree from 'ParseRoutes'\n */\n protected getRoutesTreeIds(\n routes: TRoutesTree[],\n index?: string,\n ): Record<string, string | undefined> {\n const result: Record<string, string | undefined> = {};\n\n routes.forEach((route, routeIndex) => {\n const routeId = [index, String(routeIndex)].filter(Boolean).join('-');\n\n if (route.import) {\n result[routeId] = this.pathNormalize.getAppPath(route.import);\n }\n\n if (route.children.length > 0) {\n Object.assign(result, this.getRoutesTreeIds(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: path.posix.normalize(`${this.basename}/${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 buildRoutesManifest(): void {\n const manifest = this.loadClientManifest();\n const routesService = new ParseRoutes(this.config, this.viteAliases);\n const routesPaths = this.getRoutesTreeIds(routesService.parse());\n\n const postfixes = this.pathNormalize.getImportPostfix();\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 route assets\n */\n protected getAssets(routes?: RouterState['matches']): 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?: RouterState['matches']): IAsset[] {\n const routeIds =\n (routes\n ?.map(({ route }) => this.pathNormalize.getAppPath((route as IAsyncRoute)?.pathId, true))\n .filter(Boolean) as string[]) ?? [];\n\n if (!routeIds.length) {\n return [];\n }\n\n let assets: TAssets = {};\n const postfixes = this.pathNormalize.getImportPostfix();\n const rootId = path.resolve(\n this.root,\n this.config.getPluginConfig()?.clientFile ?? 'client.ts',\n );\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, skipModules: Set<string> = new Set()): TAssets {\n if (!module?.clientImportedModules.size || skipModules.has(module.file!)) {\n return {};\n }\n\n let assets: TAssets = {};\n\n skipModules.add(module.file!);\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}\"}`) as { style: string }).style,\n isNested: Boolean(skipModules.size),\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, skipModules),\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","pathNormalize","root","buildDir","manifestName","assetsManifest","viteAliases","basename","routesAssets","constructor","this","getParams","getVite","resolve","alias","PathNormalize","params","instance","getOutDir","path","getAssetsManifestFile","loadClientManifest","clientManifestDir","clientSsrManifest","fs","existsSync","result","JSON","parse","readFileSync","encoding","rmSync","readdirSync","length","recursive","loadAssetsManifest","manifestFile","getRoutesTreeIds","routes","index","forEach","route","routeIndex","routeId","String","filter","Boolean","join","import","getAppPath","children","Object","assign","sortAssets","assets","sort","a","b","weight","Number","isNested","getRouteAssets","manifest","module","css","file","reduce","res","asset","type","getAssetType","isEntry","url","posix","normalize","getAssetWeight","isPreload","imports","nestedAsset","nestedModule","buildRoutesManifest","routesService","ParseRoutes","routesPaths","postfixes","getImportPostfix","entries","routePath","routePostfix","find","postfix","undefined","routeMeta","values","writeFileSync","stringify","getAssets","getAssetsDev","routeIds","map","id","flat","pathId","getPluginConfig","clientFile","moduleId","ext","moduleGraph","getModuleById","getModuleAssets","skipModules","Set","clientImportedModules","size","has","add","subModule","transformResult","split","at","includes","code","match","groups","style","content","e","console","warn","chalk","yellowBright","script","toLowerCase","image","font","writeEarlyHits","socket","write","injectAssets","routerContext","html","hasEarlyHints","matches","htmlAssets","isModulePreload","header","replace"],"mappings":"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"}
|
package/helpers/ssr-meta.d.ts
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
interface ISsrMetadata {
|
|
2
|
-
routeFiles?: {
|
|
3
|
-
[originalFileName: string]: string;
|
|
4
|
-
};
|
|
5
|
-
}
|
|
6
|
-
/**
|
|
7
|
-
* Write build metadata
|
|
8
|
-
*/
|
|
9
|
-
declare const writeMeta: (buildDir: string, data: ISsrMetadata) => void;
|
|
10
|
-
/**
|
|
11
|
-
* Read build metadata
|
|
12
|
-
*/
|
|
13
|
-
declare const readMeta: (buildDir: string) => ISsrMetadata;
|
|
14
|
-
/**
|
|
15
|
-
* Remove metadata file
|
|
16
|
-
*/
|
|
17
|
-
declare const removeMeta: (buildDir: string) => void;
|
|
18
|
-
export { writeMeta, readMeta, removeMeta };
|
package/helpers/ssr-meta.js
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import n from"node:fs";const t=n=>`${n}/meta.json`,r=(r,e)=>{const o=c(r);n.writeFileSync(t(r),JSON.stringify({...o,...e},null,2),{encoding:"utf-8"})},c=r=>{const c=t(r);try{return JSON.parse(n.readFileSync(c,{encoding:"utf-8"}))}catch(n){}return{}},e=r=>{try{n.unlinkSync(t(r))}catch(n){}};export{c as readMeta,e as removeMeta,r as writeMeta};
|
|
2
|
-
//# sourceMappingURL=ssr-meta.js.map
|
package/helpers/ssr-meta.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ssr-meta.js","sources":["../../src/helpers/ssr-meta.ts"],"sourcesContent":["import fs from 'node:fs';\n\ninterface ISsrMetadata {\n routeFiles?: {\n // original => generated file\n [originalFileName: string]: string;\n };\n}\n\n/**\n * Return meta file path\n */\nconst getMetaFilepath = (buildDir: string): string => `${buildDir}/meta.json`;\n\n/**\n * Write build metadata\n */\nconst writeMeta = (buildDir: string, data: ISsrMetadata): void => {\n const meta = readMeta(buildDir);\n\n fs.writeFileSync(getMetaFilepath(buildDir), JSON.stringify({ ...meta, ...data }, null, 2), {\n encoding: 'utf-8',\n });\n};\n\n/**\n * Read build metadata\n */\nconst readMeta = (buildDir: string): ISsrMetadata => {\n const metaFile = getMetaFilepath(buildDir);\n\n try {\n return JSON.parse(fs.readFileSync(metaFile, { encoding: 'utf-8' })) as ISsrMetadata;\n } catch (e) {\n // ignore, file not exist\n }\n\n return {};\n};\n\n/**\n * Remove metadata file\n */\nconst removeMeta = (buildDir: string): void => {\n try {\n fs.unlinkSync(getMetaFilepath(buildDir));\n } catch (e) {\n // ignore\n }\n};\n\nexport { writeMeta, readMeta, removeMeta };\n"],"names":["getMetaFilepath","buildDir","writeMeta","data","meta","readMeta","fs","writeFileSync","JSON","stringify","encoding","metaFile","parse","readFileSync","e","removeMeta","unlinkSync"],"mappings":"uBAYA,MAAMA,EAAmBC,GAA6B,GAAGA,cAKnDC,EAAY,CAACD,EAAkBE,KACnC,MAAMC,EAAOC,EAASJ,GAEtBK,EAAGC,cAAcP,EAAgBC,GAAWO,KAAKC,UAAU,IAAKL,KAASD,GAAQ,KAAM,GAAI,CACzFO,SAAU,SACV,EAMEL,EAAYJ,IAChB,MAAMU,EAAWX,EAAgBC,GAEjC,IACE,OAAOO,KAAKI,MAAMN,EAAGO,aAAaF,EAAU,CAAED,SAAU,UACzD,CAAC,MAAOI,GAER,CAED,MAAO,EAAE,EAMLC,EAAcd,IAClB,IACEK,EAAGU,WAAWhB,EAAgBC,GAC/B,CAAC,MAAOa,GAER"}
|