@lomray/vite-ssr-boost 4.0.0 → 5.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.
@@ -1 +1 @@
1
- {"version":3,"file":"keyboard-input.js","sources":["../../../src/cli/helpers/keyboard-input.ts"],"sourcesContent":["import chalk from 'chalk';\nimport cliContext from '@constants/cli-context';\nimport defaultShortcuts from '@constants/cli-shortcuts';\nimport getPluginConfig from '@helpers/plugin-config';\nimport processStop from '@helpers/process-stop';\n\nlet isActionRunning = false;\n\n/**\n * Handle keyboard press buttons\n */\nfunction onKeyPress(input: string): void {\n void runAction(input);\n}\n\n/**\n * Run shortcut\n */\nasync function runAction(input: string): Promise<void> {\n // ctrl+c or ctrl+d\n if (input === '\\x03' || input === '\\x04') {\n if (!cliContext.server?.close((e) => processStop(e ? 1 : 0))) {\n processStop();\n }\n\n return;\n }\n\n if (isActionRunning) {\n return;\n }\n\n const { config } = cliContext;\n const Logger = config?.getLogger();\n const { customShortcuts = [] } =\n typeof config?.getVite()?.config === 'object' ? getPluginConfig(config.getVite()!.config) : {};\n\n const shortcuts = customShortcuts\n .filter(Boolean)\n .concat(defaultShortcuts)\n .filter(({ isOnlyDev = false }) => !isOnlyDev || (isOnlyDev && !config?.isProd));\n\n // print empty line\n if (input === '\\r') {\n return Logger?.info('\\r');\n }\n\n // print help\n if (input === 'h') {\n Logger?.info(\n [\n '',\n chalk.bold(' Shortcuts'),\n ...shortcuts.map(\n (shortcut) =>\n chalk.dim(' press ') +\n chalk.bold(shortcut.key) +\n chalk.dim(` to ${shortcut.description}`),\n ),\n ].join('\\n'),\n );\n }\n\n // execute shortcut command\n const shortcut = shortcuts.find(({ key }) => key === input);\n\n if (!shortcut) {\n return;\n }\n\n isActionRunning = true;\n await shortcut.action(cliContext);\n isActionRunning = false;\n}\n\nexport default onKeyPress;\n"],"names":["isActionRunning","onKeyPress","input","async","cliContext","server","close","e","processStop","config","Logger","getLogger","customShortcuts","getVite","getPluginConfig","shortcuts","filter","Boolean","concat","defaultShortcuts","isOnlyDev","isProd","info","chalk","bold","map","shortcut","dim","key","description","join","find","action","runAction"],"mappings":"8MAMA,IAAIA,GAAkB,EAKtB,SAASC,EAAWC,IAOpBC,eAAyBD,GAEvB,GAAc,MAAVA,GAA8B,MAAVA,EAKtB,YAJKE,EAAWC,QAAQC,OAAOC,GAAMC,EAAYD,EAAI,EAAI,MACvDC,KAMJ,GAAIR,EACF,OAGF,MAAMS,OAAEA,GAAWL,EACbM,EAASD,GAAQE,aACjBC,gBAAEA,EAAkB,IACa,iBAA9BH,GAAQI,WAAWJ,OAAsBK,EAAgBL,EAAOI,UAAWJ,QAAU,CAAA,EAExFM,EAAYH,EACfI,OAAOC,SACPC,OAAOC,GACPH,QAAO,EAAGI,aAAY,MAAaA,GAAcA,IAAcX,GAAQY,SAG1E,GAAc,OAAVnB,EACF,OAAOQ,GAAQY,KAAK,MAIR,MAAVpB,GACFQ,GAAQY,KACN,CACE,GACAC,EAAMC,KAAK,kBACRT,EAAUU,KACVC,GACCH,EAAMI,IAAI,YACVJ,EAAMC,KAAKE,EAASE,KACpBL,EAAMI,IAAI,OAAOD,EAASG,kBAE9BC,KAAK,OAKX,MAAMJ,EAAWX,EAAUgB,MAAK,EAAGH,SAAUA,IAAQ1B,IAErD,IAAKwB,EACH,OAGF1B,GAAkB,QACZ0B,EAASM,OAAO5B,GACtBJ,GAAkB,CACpB,CA7DOiC,CAAU/B,EACjB"}
1
+ {"version":3,"file":"keyboard-input.js","sources":["../../../src/cli/helpers/keyboard-input.ts"],"sourcesContent":["import chalk from 'chalk';\nimport cliContext from '@constants/cli-context';\nimport defaultShortcuts from '@constants/cli-shortcuts';\nimport getPluginConfig from '@helpers/plugin-config';\nimport processStop from '@helpers/process-stop';\n\nlet isActionRunning = false;\n\n/**\n * Handle keyboard press buttons\n */\nfunction onKeyPress(input: string): void {\n void runAction(input);\n}\n\n/**\n * Run shortcut\n */\nasync function runAction(input: string): Promise<void> {\n // ctrl+c or ctrl+d\n if (input === '\\x03' || input === '\\x04') {\n if (!cliContext.server?.close((e) => processStop(e ? 1 : 0))) {\n processStop();\n }\n\n return;\n }\n\n if (isActionRunning) {\n return;\n }\n\n const { config } = cliContext;\n const Logger = config?.getLogger();\n const { customShortcuts = [] } =\n typeof config?.getVite()?.config === 'object' ? getPluginConfig(config.getVite()!.config) : {};\n\n const shortcuts = customShortcuts\n .filter(Boolean)\n .concat(defaultShortcuts)\n .filter(({ isOnlyDev = false }) => !isOnlyDev || (isOnlyDev && !config?.isProd));\n\n // print empty line\n if (input === '\\r') {\n return Logger?.info('\\r');\n }\n\n // print help\n if (input === 'h') {\n Logger?.info(\n [\n '',\n chalk.bold(' Shortcuts'),\n ...shortcuts.map(\n (shortcut) =>\n chalk.dim(' press ') +\n chalk.bold(shortcut.key) +\n chalk.dim(` to ${shortcut.description}`),\n ),\n ].join('\\n'),\n );\n }\n\n // execute shortcut command\n const shortcut = shortcuts.find(({ key }) => key === input);\n\n if (!shortcut) {\n return;\n }\n\n isActionRunning = true;\n await shortcut.action(cliContext);\n isActionRunning = false;\n}\n\nexport default onKeyPress;\n"],"names":["isActionRunning","onKeyPress","input","async","cliContext","server","close","e","processStop","config","Logger","getLogger","customShortcuts","getVite","getPluginConfig","shortcuts","filter","Boolean","concat","defaultShortcuts","isOnlyDev","isProd","info","chalk","bold","map","shortcut","dim","key","description","join","find","action","runAction"],"mappings":"8MAMA,IAAIA,GAAkB,EAKtB,SAASC,EAAWC,IAOpBC,eAAyBD,GAEvB,GAAc,MAAVA,GAA8B,MAAVA,EAKtB,YAJKE,EAAWC,QAAQC,OAAOC,GAAMC,EAAYD,EAAI,EAAI,MACvDC,KAMJ,GAAIR,EACF,OAGF,MAAMS,OAAEA,GAAWL,EACbM,EAASD,GAAQE,aACjBC,gBAAEA,EAAkB,IACa,iBAA9BH,GAAQI,WAAWJ,OAAsBK,EAAgBL,EAAOI,UAAWJ,QAAU,CAAE,EAE1FM,EAAYH,EACfI,OAAOC,SACPC,OAAOC,GACPH,QAAO,EAAGI,aAAY,MAAaA,GAAcA,IAAcX,GAAQY,SAG1E,GAAc,OAAVnB,EACF,OAAOQ,GAAQY,KAAK,MAIR,MAAVpB,GACFQ,GAAQY,KACN,CACE,GACAC,EAAMC,KAAK,kBACRT,EAAUU,KACVC,GACCH,EAAMI,IAAI,YACVJ,EAAMC,KAAKE,EAASE,KACpBL,EAAMI,IAAI,OAAOD,EAASG,kBAE9BC,KAAK,OAKX,MAAMJ,EAAWX,EAAUgB,MAAK,EAAGH,SAAUA,IAAQ1B,IAErD,IAAKwB,EACH,OAGF1B,GAAkB,QACZ0B,EAASM,OAAO5B,GACtBJ,GAAkB,CACpB,CA7DOiC,CAAU/B,EACjB"}
@@ -1 +1 @@
1
- {"version":3,"file":"vite-reset-cache.js","sources":["../../../src/cli/helpers/vite-reset-cache.ts"],"sourcesContent":["import fs from 'node:fs';\nimport chalk from 'chalk';\nimport { resolveConfig } from 'vite';\n\n/**\n * Reset vite cache\n */\nasync function viteResetCache(): Promise<void> {\n const config = await resolveConfig({}, 'build');\n const { cacheDir } = config;\n\n if (fs.existsSync(cacheDir)) {\n fs.rmSync(cacheDir, { recursive: true, force: true });\n }\n\n console.info(chalk.dim(chalk.yellowBright('vite cache cleared.')));\n}\n\nexport default viteResetCache;\n"],"names":["async","viteResetCache","config","resolveConfig","cacheDir","fs","existsSync","rmSync","recursive","force","console","info","chalk","dim","yellowBright"],"mappings":"iFAOAA,eAAeC,IACb,MAAMC,QAAeC,EAAc,CAAE,EAAE,UACjCC,SAAEA,GAAaF,EAEjBG,EAAGC,WAAWF,IAChBC,EAAGE,OAAOH,EAAU,CAAEI,WAAW,EAAMC,OAAO,IAGhDC,QAAQC,KAAKC,EAAMC,IAAID,EAAME,aAAa,wBAC5C"}
1
+ {"version":3,"file":"vite-reset-cache.js","sources":["../../../src/cli/helpers/vite-reset-cache.ts"],"sourcesContent":["import fs from 'node:fs';\nimport chalk from 'chalk';\nimport { resolveConfig } from 'vite';\n\n/**\n * Reset vite cache\n */\nasync function viteResetCache(): Promise<void> {\n const config = await resolveConfig({}, 'build');\n const { cacheDir } = config;\n\n if (fs.existsSync(cacheDir)) {\n fs.rmSync(cacheDir, { recursive: true, force: true });\n }\n\n console.info(chalk.dim(chalk.yellowBright('vite cache cleared.')));\n}\n\nexport default viteResetCache;\n"],"names":["async","viteResetCache","config","resolveConfig","cacheDir","fs","existsSync","rmSync","recursive","force","console","info","chalk","dim","yellowBright"],"mappings":"iFAOAA,eAAeC,IACb,MAAMC,QAAeC,EAAc,CAAA,EAAI,UACjCC,SAAEA,GAAaF,EAEjBG,EAAGC,WAAWF,IAChBC,EAAGE,OAAOH,EAAU,CAAEI,WAAW,EAAMC,OAAO,IAGhDC,QAAQC,KAAKC,EAAMC,IAAID,EAAME,aAAa,wBAC5C"}
@@ -1 +1 @@
1
- {"version":3,"file":"run-amplify-build.js","sources":["../../src/cli/run-amplify-build.ts"],"sourcesContent":["import type { ExecSyncOptions } from 'child_process';\nimport childProcess from 'node:child_process';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { cwd } from 'node:process';\nimport chalk from 'chalk';\nimport { resolveConfig } from 'vite';\nimport getPluginConfig from '@helpers/plugin-config';\n\ninterface IRunAmplifyBuildParams {\n manifestFile?: string;\n mode?: string;\n isOptimize?: boolean;\n}\n\n/**\n * Create AWS Amplify SSR build\n */\nasync function runAmplifyBuild({\n manifestFile,\n mode = '',\n isOptimize = false,\n}: IRunAmplifyBuildParams): Promise<void> {\n const config = await resolveConfig({}, 'build', mode);\n const pluginConfig = getPluginConfig(config);\n const {\n root,\n build: { outDir },\n } = config;\n const projectRoot = cwd();\n const buildDir = `.${path.resolve(root, outDir).replace(projectRoot, '')}`; // relative path\n const manFile = manifestFile || `${pluginConfig.pluginPath}/workflow/amplify-manifest.json`;\n const amplifyDir = `${projectRoot}/.amplify-hosting`;\n const computeDir = `${amplifyDir}/compute/default`;\n const stdOpts: ExecSyncOptions = {\n stdio: 'inherit',\n };\n\n // Check build server\n if (!fs.existsSync(`${buildDir}/server/start.js`)) {\n console.error(\n chalk.red(\n 'Failed create Amplify build: Before, you should create standard build with `eject` option.',\n ),\n );\n\n return;\n }\n\n if (fs.existsSync(amplifyDir)) {\n childProcess.execSync(`rm -rf ${amplifyDir}`, stdOpts);\n }\n\n fs.mkdirSync(computeDir, { recursive: true });\n childProcess.execSync(`cp -r ${buildDir} ${computeDir}/build`, stdOpts);\n childProcess.execSync(`cp ${projectRoot}/package.json ${computeDir}/package.json`, stdOpts);\n childProcess.execSync(\n `cp ${projectRoot}/package-lock.json ${computeDir}/package-lock.json`,\n stdOpts,\n );\n childProcess.execSync(`cp -r ${buildDir}/client ${amplifyDir}/static`, stdOpts);\n childProcess.execSync(`cp ${manFile} ${amplifyDir}/deploy-manifest.json`, stdOpts);\n childProcess.execSync(`cp -r ${projectRoot}/node_modules ${computeDir}/node_modules`);\n\n if (isOptimize) {\n childProcess.execSync(`cd ${computeDir} && npm ci --omit=dev`, stdOpts);\n }\n\n // cleanup\n childProcess.execSync(`rm -rf ${computeDir}/build/client/assets`, stdOpts);\n\n console.info(`\\n${chalk.cyan('AWS Amplify build success created.')}`);\n}\n\nexport default runAmplifyBuild;\n"],"names":["async","runAmplifyBuild","manifestFile","mode","isOptimize","config","resolveConfig","pluginConfig","getPluginConfig","root","build","outDir","projectRoot","cwd","buildDir","path","resolve","replace","manFile","pluginPath","amplifyDir","computeDir","stdOpts","stdio","fs","existsSync","childProcess","execSync","mkdirSync","recursive","console","info","chalk","cyan","error","red"],"mappings":"0NAkBAA,eAAeC,GAAgBC,aAC7BA,EAAYC,KACZA,EAAO,GAAEC,WACTA,GAAa,IAEb,MAAMC,QAAeC,EAAc,CAAE,EAAE,QAASH,GAC1CI,EAAeC,EAAgBH,IAC/BI,KACJA,EACAC,OAAOC,OAAEA,IACPN,EACEO,EAAcC,IACdC,EAAW,IAAIC,EAAKC,QAAQP,EAAME,GAAQM,QAAQL,EAAa,MAC/DM,EAAUhB,GAAgB,GAAGK,EAAaY,4CAC1CC,EAAa,GAAGR,qBAChBS,EAAa,GAAGD,oBAChBE,EAA2B,CAC/BC,MAAO,WAIJC,EAAGC,WAAW,GAAGX,sBAUlBU,EAAGC,WAAWL,IAChBM,EAAaC,SAAS,UAAUP,IAAcE,GAGhDE,EAAGI,UAAUP,EAAY,CAAEQ,WAAW,IACtCH,EAAaC,SAAS,SAASb,KAAYO,UAAoBC,GAC/DI,EAAaC,SAAS,MAAMf,kBAA4BS,iBAA2BC,GACnFI,EAAaC,SACX,MAAMf,uBAAiCS,sBACvCC,GAEFI,EAAaC,SAAS,SAASb,YAAmBM,WAAqBE,GACvEI,EAAaC,SAAS,MAAMT,KAAWE,yBAAmCE,GAC1EI,EAAaC,SAAS,SAASf,kBAA4BS,kBAEvDjB,GACFsB,EAAaC,SAAS,MAAMN,yBAAmCC,GAIjEI,EAAaC,SAAS,UAAUN,wBAAkCC,GAElEQ,QAAQC,KAAK,KAAKC,EAAMC,KAAK,0CA/B3BH,QAAQI,MACNF,EAAMG,IACJ,8FA8BR"}
1
+ {"version":3,"file":"run-amplify-build.js","sources":["../../src/cli/run-amplify-build.ts"],"sourcesContent":["import type { ExecSyncOptions } from 'child_process';\nimport childProcess from 'node:child_process';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { cwd } from 'node:process';\nimport chalk from 'chalk';\nimport { resolveConfig } from 'vite';\nimport getPluginConfig from '@helpers/plugin-config';\n\ninterface IRunAmplifyBuildParams {\n manifestFile?: string;\n mode?: string;\n isOptimize?: boolean;\n}\n\n/**\n * Create AWS Amplify SSR build\n */\nasync function runAmplifyBuild({\n manifestFile,\n mode = '',\n isOptimize = false,\n}: IRunAmplifyBuildParams): Promise<void> {\n const config = await resolveConfig({}, 'build', mode);\n const pluginConfig = getPluginConfig(config);\n const {\n root,\n build: { outDir },\n } = config;\n const projectRoot = cwd();\n const buildDir = `.${path.resolve(root, outDir).replace(projectRoot, '')}`; // relative path\n const manFile = manifestFile || `${pluginConfig.pluginPath}/workflow/amplify-manifest.json`;\n const amplifyDir = `${projectRoot}/.amplify-hosting`;\n const computeDir = `${amplifyDir}/compute/default`;\n const stdOpts: ExecSyncOptions = {\n stdio: 'inherit',\n };\n\n // Check build server\n if (!fs.existsSync(`${buildDir}/server/start.js`)) {\n console.error(\n chalk.red(\n 'Failed create Amplify build: Before, you should create standard build with `eject` option.',\n ),\n );\n\n return;\n }\n\n if (fs.existsSync(amplifyDir)) {\n childProcess.execSync(`rm -rf ${amplifyDir}`, stdOpts);\n }\n\n fs.mkdirSync(computeDir, { recursive: true });\n childProcess.execSync(`cp -r ${buildDir} ${computeDir}/build`, stdOpts);\n childProcess.execSync(`cp ${projectRoot}/package.json ${computeDir}/package.json`, stdOpts);\n childProcess.execSync(\n `cp ${projectRoot}/package-lock.json ${computeDir}/package-lock.json`,\n stdOpts,\n );\n childProcess.execSync(`cp -r ${buildDir}/client ${amplifyDir}/static`, stdOpts);\n childProcess.execSync(`cp ${manFile} ${amplifyDir}/deploy-manifest.json`, stdOpts);\n childProcess.execSync(`cp -r ${projectRoot}/node_modules ${computeDir}/node_modules`);\n\n if (isOptimize) {\n childProcess.execSync(`cd ${computeDir} && npm ci --omit=dev`, stdOpts);\n }\n\n // cleanup\n childProcess.execSync(`rm -rf ${computeDir}/build/client/assets`, stdOpts);\n\n console.info(`\\n${chalk.cyan('AWS Amplify build success created.')}`);\n}\n\nexport default runAmplifyBuild;\n"],"names":["async","runAmplifyBuild","manifestFile","mode","isOptimize","config","resolveConfig","pluginConfig","getPluginConfig","root","build","outDir","projectRoot","cwd","buildDir","path","resolve","replace","manFile","pluginPath","amplifyDir","computeDir","stdOpts","stdio","fs","existsSync","childProcess","execSync","mkdirSync","recursive","console","info","chalk","cyan","error","red"],"mappings":"0NAkBAA,eAAeC,GAAgBC,aAC7BA,EAAYC,KACZA,EAAO,GAAEC,WACTA,GAAa,IAEb,MAAMC,QAAeC,EAAc,CAAA,EAAI,QAASH,GAC1CI,EAAeC,EAAgBH,IAC/BI,KACJA,EACAC,OAAOC,OAAEA,IACPN,EACEO,EAAcC,IACdC,EAAW,IAAIC,EAAKC,QAAQP,EAAME,GAAQM,QAAQL,EAAa,MAC/DM,EAAUhB,GAAgB,GAAGK,EAAaY,4CAC1CC,EAAa,GAAGR,qBAChBS,EAAa,GAAGD,oBAChBE,EAA2B,CAC/BC,MAAO,WAIJC,EAAGC,WAAW,GAAGX,sBAUlBU,EAAGC,WAAWL,IAChBM,EAAaC,SAAS,UAAUP,IAAcE,GAGhDE,EAAGI,UAAUP,EAAY,CAAEQ,WAAW,IACtCH,EAAaC,SAAS,SAASb,KAAYO,UAAoBC,GAC/DI,EAAaC,SAAS,MAAMf,kBAA4BS,iBAA2BC,GACnFI,EAAaC,SACX,MAAMf,uBAAiCS,sBACvCC,GAEFI,EAAaC,SAAS,SAASb,YAAmBM,WAAqBE,GACvEI,EAAaC,SAAS,MAAMT,KAAWE,yBAAmCE,GAC1EI,EAAaC,SAAS,SAASf,kBAA4BS,kBAEvDjB,GACFsB,EAAaC,SAAS,MAAMN,yBAAmCC,GAIjEI,EAAaC,SAAS,UAAUN,wBAAkCC,GAElEQ,QAAQC,KAAK,KAAKC,EAAMC,KAAK,0CA/B3BH,QAAQI,MACNF,EAAMG,IACJ,8FA8BR"}
@@ -1 +1 @@
1
- {"version":3,"file":"run-docker-build.js","sources":["../../src/cli/run-docker-build.ts"],"sourcesContent":["import childProcess from 'node:child_process';\nimport path from 'node:path';\nimport { cwd } from 'node:process';\nimport { resolveConfig } from 'vite';\nimport createFocusOnly from '@helpers/create-focus-only';\nimport getPluginConfig from '@helpers/plugin-config';\nimport type { IBuildParams } from '@services/build';\n\ninterface IRunDockerBuildParams {\n imageName: string;\n dockerOptions?: string;\n dockerFile?: string;\n focusOnly?: IBuildParams['focusOnly'];\n mode?: string;\n}\n\n/**\n * Build docker image\n */\nasync function runDockerBuild({\n imageName,\n dockerFile,\n focusOnly,\n dockerOptions = '',\n mode = '',\n}: IRunDockerBuildParams): Promise<void> {\n const nodeEnv = mode === 'production' ? 'production' : 'development';\n const config = await resolveConfig({}, 'build', mode);\n const pluginConfig = getPluginConfig(config);\n const {\n root,\n build: { outDir },\n } = config;\n const projectRoot = cwd();\n const buildDir = `.${path.resolve(root, outDir).replace(projectRoot, '')}`; // relative path\n const runType = createFocusOnly(focusOnly).isOnlyClient() ? 'spa' : 'ssr';\n const docFile = dockerFile || `${pluginConfig.pluginPath}/workflow/Dockerfile`;\n\n childProcess.execSync(\n `docker build -f ${docFile}` +\n ` --build-arg BUILD_PATH=${buildDir}` +\n ` --build-arg RUN_TYPE=${runType} --build-arg ENV_MODE=${nodeEnv}` +\n ` ${dockerOptions} -t ${imageName} ${projectRoot}`,\n {\n stdio: 'inherit',\n env: {\n ...process.env,\n },\n },\n );\n}\n\nexport default runDockerBuild;\n"],"names":["async","runDockerBuild","imageName","dockerFile","focusOnly","dockerOptions","mode","nodeEnv","config","resolveConfig","pluginConfig","getPluginConfig","root","build","outDir","projectRoot","cwd","buildDir","path","resolve","replace","runType","createFocusOnly","isOnlyClient","docFile","pluginPath","childProcess","execSync","stdio","env","process"],"mappings":"6NAmBAA,eAAeC,GAAeC,UAC5BA,EAASC,WACTA,EAAUC,UACVA,EAASC,cACTA,EAAgB,GAAEC,KAClBA,EAAO,KAEP,MAAMC,EAAmB,eAATD,EAAwB,aAAe,cACjDE,QAAeC,EAAc,CAAE,EAAE,QAASH,GAC1CI,EAAeC,EAAgBH,IAC/BI,KACJA,EACAC,OAAOC,OAAEA,IACPN,EACEO,EAAcC,IACdC,EAAW,IAAIC,EAAKC,QAAQP,EAAME,GAAQM,QAAQL,EAAa,MAC/DM,EAAUC,EAAgBlB,GAAWmB,eAAiB,MAAQ,MAC9DC,EAAUrB,GAAc,GAAGO,EAAae,iCAE9CC,EAAaC,SACX,mBAAmBH,4BACUP,0BACFI,0BAAgCd,KACrDF,QAAoBH,KAAaa,IACvC,CACEa,MAAO,UACPC,IAAK,IACAC,QAAQD,MAInB"}
1
+ {"version":3,"file":"run-docker-build.js","sources":["../../src/cli/run-docker-build.ts"],"sourcesContent":["import childProcess from 'node:child_process';\nimport path from 'node:path';\nimport { cwd } from 'node:process';\nimport { resolveConfig } from 'vite';\nimport createFocusOnly from '@helpers/create-focus-only';\nimport getPluginConfig from '@helpers/plugin-config';\nimport type { IBuildParams } from '@services/build';\n\ninterface IRunDockerBuildParams {\n imageName: string;\n dockerOptions?: string;\n dockerFile?: string;\n focusOnly?: IBuildParams['focusOnly'];\n mode?: string;\n}\n\n/**\n * Build docker image\n */\nasync function runDockerBuild({\n imageName,\n dockerFile,\n focusOnly,\n dockerOptions = '',\n mode = '',\n}: IRunDockerBuildParams): Promise<void> {\n const nodeEnv = mode === 'production' ? 'production' : 'development';\n const config = await resolveConfig({}, 'build', mode);\n const pluginConfig = getPluginConfig(config);\n const {\n root,\n build: { outDir },\n } = config;\n const projectRoot = cwd();\n const buildDir = `.${path.resolve(root, outDir).replace(projectRoot, '')}`; // relative path\n const runType = createFocusOnly(focusOnly).isOnlyClient() ? 'spa' : 'ssr';\n const docFile = dockerFile || `${pluginConfig.pluginPath}/workflow/Dockerfile`;\n\n childProcess.execSync(\n `docker build -f ${docFile}` +\n ` --build-arg BUILD_PATH=${buildDir}` +\n ` --build-arg RUN_TYPE=${runType} --build-arg ENV_MODE=${nodeEnv}` +\n ` ${dockerOptions} -t ${imageName} ${projectRoot}`,\n {\n stdio: 'inherit',\n env: {\n ...process.env,\n },\n },\n );\n}\n\nexport default runDockerBuild;\n"],"names":["async","runDockerBuild","imageName","dockerFile","focusOnly","dockerOptions","mode","nodeEnv","config","resolveConfig","pluginConfig","getPluginConfig","root","build","outDir","projectRoot","cwd","buildDir","path","resolve","replace","runType","createFocusOnly","isOnlyClient","docFile","pluginPath","childProcess","execSync","stdio","env","process"],"mappings":"6NAmBAA,eAAeC,GAAeC,UAC5BA,EAASC,WACTA,EAAUC,UACVA,EAASC,cACTA,EAAgB,GAAEC,KAClBA,EAAO,KAEP,MAAMC,EAAmB,eAATD,EAAwB,aAAe,cACjDE,QAAeC,EAAc,CAAA,EAAI,QAASH,GAC1CI,EAAeC,EAAgBH,IAC/BI,KACJA,EACAC,OAAOC,OAAEA,IACPN,EACEO,EAAcC,IACdC,EAAW,IAAIC,EAAKC,QAAQP,EAAME,GAAQM,QAAQL,EAAa,MAC/DM,EAAUC,EAAgBlB,GAAWmB,eAAiB,MAAQ,MAC9DC,EAAUrB,GAAc,GAAGO,EAAae,iCAE9CC,EAAaC,SACX,mBAAmBH,4BACUP,0BACFI,0BAAgCd,KACrDF,QAAoBH,KAAaa,IACvC,CACEa,MAAO,UACPC,IAAK,IACAC,QAAQD,MAInB"}
@@ -1 +1 @@
1
- {"version":3,"file":"run-vercel-build.js","sources":["../../src/cli/run-vercel-build.ts"],"sourcesContent":["import type { ExecSyncOptions } from 'child_process';\nimport childProcess from 'node:child_process';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { cwd } from 'node:process';\nimport chalk from 'chalk';\nimport { resolveConfig } from 'vite';\nimport getPluginConfig from '@helpers/plugin-config';\n\ninterface IRunVercelBuildParams {\n configFile?: string;\n configVcFile?: string;\n mode?: string;\n isOptimize?: boolean;\n}\n\n/**\n * Create Vercel SSR build\n */\nasync function runVercelBuild({\n configFile,\n configVcFile,\n mode = '',\n isOptimize = false,\n}: IRunVercelBuildParams): Promise<void> {\n const config = await resolveConfig({}, 'build', mode);\n const pluginConfig = getPluginConfig(config);\n const {\n root,\n build: { outDir },\n } = config;\n const projectRoot = cwd();\n const buildDir = `.${path.resolve(root, outDir).replace(projectRoot, '')}`; // relative path\n const manFile = configFile || `${pluginConfig.pluginPath}/workflow/vercel.config.json`;\n const manVcFile = configVcFile || `${pluginConfig.pluginPath}/workflow/vercel.vc-config.json`;\n const outputDir = `${projectRoot}/.vercel/output`;\n const stdOpts: ExecSyncOptions = {\n stdio: 'inherit',\n };\n\n // Check build serverless\n if (!fs.existsSync(`${buildDir}/server/serverless.js`)) {\n console.error(\n chalk.red(\n 'Failed create Vercel build: Before, you should create standard build with `serverless` option.',\n ),\n );\n\n return;\n }\n\n if (fs.existsSync(outputDir)) {\n childProcess.execSync(`rm -rf ${outputDir}`, stdOpts);\n }\n\n fs.mkdirSync(outputDir, { recursive: true });\n fs.mkdirSync(`${outputDir}/functions/index.func`, { recursive: true });\n childProcess.execSync(`cp ${manFile} ${outputDir}/config.json`, stdOpts);\n childProcess.execSync(\n `cp ${manVcFile} ${outputDir}/functions/index.func/.vc-config.json`,\n stdOpts,\n );\n childProcess.execSync(\n `cp ${buildDir}/server/serverless.js ${outputDir}/functions/index.func/index.js`,\n stdOpts,\n );\n childProcess.execSync(\n `cp -r ${projectRoot}/node_modules ${outputDir}/functions/index.func/node_modules`,\n stdOpts,\n );\n childProcess.execSync(`cp -r ${buildDir} ${outputDir}/functions/index.func/build`, stdOpts);\n childProcess.execSync(\n `cp -r ${projectRoot}/package.json ${outputDir}/functions/index.func/package.json`,\n stdOpts,\n );\n childProcess.execSync(\n `cp -r ${projectRoot}/package-lock.json ${outputDir}/functions/index.func/package-lock.json`,\n stdOpts,\n );\n childProcess.execSync(`cp -r ${buildDir}/client ${outputDir}/static`, stdOpts);\n\n if (isOptimize) {\n childProcess.execSync(`cd ${outputDir}/functions/index.func && npm ci --omit=dev`, stdOpts);\n }\n\n console.info(`\\n${chalk.cyan('Vercel build success created.')}`);\n}\n\nexport default runVercelBuild;\n"],"names":["async","runVercelBuild","configFile","configVcFile","mode","isOptimize","config","resolveConfig","pluginConfig","getPluginConfig","root","build","outDir","projectRoot","cwd","buildDir","path","resolve","replace","manFile","pluginPath","manVcFile","outputDir","stdOpts","stdio","fs","existsSync","childProcess","execSync","mkdirSync","recursive","console","info","chalk","cyan","error","red"],"mappings":"0NAmBAA,eAAeC,GAAeC,WAC5BA,EAAUC,aACVA,EAAYC,KACZA,EAAO,GAAEC,WACTA,GAAa,IAEb,MAAMC,QAAeC,EAAc,CAAE,EAAE,QAASH,GAC1CI,EAAeC,EAAgBH,IAC/BI,KACJA,EACAC,OAAOC,OAAEA,IACPN,EACEO,EAAcC,IACdC,EAAW,IAAIC,EAAKC,QAAQP,EAAME,GAAQM,QAAQL,EAAa,MAC/DM,EAAUjB,GAAc,GAAGM,EAAaY,yCACxCC,EAAYlB,GAAgB,GAAGK,EAAaY,4CAC5CE,EAAY,GAAGT,mBACfU,EAA2B,CAC/BC,MAAO,WAIJC,EAAGC,WAAW,GAAGX,2BAUlBU,EAAGC,WAAWJ,IAChBK,EAAaC,SAAS,UAAUN,IAAaC,GAG/CE,EAAGI,UAAUP,EAAW,CAAEQ,WAAW,IACrCL,EAAGI,UAAU,GAAGP,yBAAkC,CAAEQ,WAAW,IAC/DH,EAAaC,SAAS,MAAMT,KAAWG,gBAAyBC,GAChEI,EAAaC,SACX,MAAMP,KAAaC,yCACnBC,GAEFI,EAAaC,SACX,MAAMb,0BAAiCO,kCACvCC,GAEFI,EAAaC,SACX,SAASf,kBAA4BS,sCACrCC,GAEFI,EAAaC,SAAS,SAASb,KAAYO,+BAAwCC,GACnFI,EAAaC,SACX,SAASf,kBAA4BS,sCACrCC,GAEFI,EAAaC,SACX,SAASf,uBAAiCS,2CAC1CC,GAEFI,EAAaC,SAAS,SAASb,YAAmBO,WAAoBC,GAElElB,GACFsB,EAAaC,SAAS,MAAMN,8CAAuDC,GAGrFQ,QAAQC,KAAK,KAAKC,EAAMC,KAAK,qCA3C3BH,QAAQI,MACNF,EAAMG,IACJ,kGA0CR"}
1
+ {"version":3,"file":"run-vercel-build.js","sources":["../../src/cli/run-vercel-build.ts"],"sourcesContent":["import type { ExecSyncOptions } from 'child_process';\nimport childProcess from 'node:child_process';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { cwd } from 'node:process';\nimport chalk from 'chalk';\nimport { resolveConfig } from 'vite';\nimport getPluginConfig from '@helpers/plugin-config';\n\ninterface IRunVercelBuildParams {\n configFile?: string;\n configVcFile?: string;\n mode?: string;\n isOptimize?: boolean;\n}\n\n/**\n * Create Vercel SSR build\n */\nasync function runVercelBuild({\n configFile,\n configVcFile,\n mode = '',\n isOptimize = false,\n}: IRunVercelBuildParams): Promise<void> {\n const config = await resolveConfig({}, 'build', mode);\n const pluginConfig = getPluginConfig(config);\n const {\n root,\n build: { outDir },\n } = config;\n const projectRoot = cwd();\n const buildDir = `.${path.resolve(root, outDir).replace(projectRoot, '')}`; // relative path\n const manFile = configFile || `${pluginConfig.pluginPath}/workflow/vercel.config.json`;\n const manVcFile = configVcFile || `${pluginConfig.pluginPath}/workflow/vercel.vc-config.json`;\n const outputDir = `${projectRoot}/.vercel/output`;\n const stdOpts: ExecSyncOptions = {\n stdio: 'inherit',\n };\n\n // Check build serverless\n if (!fs.existsSync(`${buildDir}/server/serverless.js`)) {\n console.error(\n chalk.red(\n 'Failed create Vercel build: Before, you should create standard build with `serverless` option.',\n ),\n );\n\n return;\n }\n\n if (fs.existsSync(outputDir)) {\n childProcess.execSync(`rm -rf ${outputDir}`, stdOpts);\n }\n\n fs.mkdirSync(outputDir, { recursive: true });\n fs.mkdirSync(`${outputDir}/functions/index.func`, { recursive: true });\n childProcess.execSync(`cp ${manFile} ${outputDir}/config.json`, stdOpts);\n childProcess.execSync(\n `cp ${manVcFile} ${outputDir}/functions/index.func/.vc-config.json`,\n stdOpts,\n );\n childProcess.execSync(\n `cp ${buildDir}/server/serverless.js ${outputDir}/functions/index.func/index.js`,\n stdOpts,\n );\n childProcess.execSync(\n `cp -r ${projectRoot}/node_modules ${outputDir}/functions/index.func/node_modules`,\n stdOpts,\n );\n childProcess.execSync(`cp -r ${buildDir} ${outputDir}/functions/index.func/build`, stdOpts);\n childProcess.execSync(\n `cp -r ${projectRoot}/package.json ${outputDir}/functions/index.func/package.json`,\n stdOpts,\n );\n childProcess.execSync(\n `cp -r ${projectRoot}/package-lock.json ${outputDir}/functions/index.func/package-lock.json`,\n stdOpts,\n );\n childProcess.execSync(`cp -r ${buildDir}/client ${outputDir}/static`, stdOpts);\n\n if (isOptimize) {\n childProcess.execSync(`cd ${outputDir}/functions/index.func && npm ci --omit=dev`, stdOpts);\n }\n\n console.info(`\\n${chalk.cyan('Vercel build success created.')}`);\n}\n\nexport default runVercelBuild;\n"],"names":["async","runVercelBuild","configFile","configVcFile","mode","isOptimize","config","resolveConfig","pluginConfig","getPluginConfig","root","build","outDir","projectRoot","cwd","buildDir","path","resolve","replace","manFile","pluginPath","manVcFile","outputDir","stdOpts","stdio","fs","existsSync","childProcess","execSync","mkdirSync","recursive","console","info","chalk","cyan","error","red"],"mappings":"0NAmBAA,eAAeC,GAAeC,WAC5BA,EAAUC,aACVA,EAAYC,KACZA,EAAO,GAAEC,WACTA,GAAa,IAEb,MAAMC,QAAeC,EAAc,CAAA,EAAI,QAASH,GAC1CI,EAAeC,EAAgBH,IAC/BI,KACJA,EACAC,OAAOC,OAAEA,IACPN,EACEO,EAAcC,IACdC,EAAW,IAAIC,EAAKC,QAAQP,EAAME,GAAQM,QAAQL,EAAa,MAC/DM,EAAUjB,GAAc,GAAGM,EAAaY,yCACxCC,EAAYlB,GAAgB,GAAGK,EAAaY,4CAC5CE,EAAY,GAAGT,mBACfU,EAA2B,CAC/BC,MAAO,WAIJC,EAAGC,WAAW,GAAGX,2BAUlBU,EAAGC,WAAWJ,IAChBK,EAAaC,SAAS,UAAUN,IAAaC,GAG/CE,EAAGI,UAAUP,EAAW,CAAEQ,WAAW,IACrCL,EAAGI,UAAU,GAAGP,yBAAkC,CAAEQ,WAAW,IAC/DH,EAAaC,SAAS,MAAMT,KAAWG,gBAAyBC,GAChEI,EAAaC,SACX,MAAMP,KAAaC,yCACnBC,GAEFI,EAAaC,SACX,MAAMb,0BAAiCO,kCACvCC,GAEFI,EAAaC,SACX,SAASf,kBAA4BS,sCACrCC,GAEFI,EAAaC,SAAS,SAASb,KAAYO,+BAAwCC,GACnFI,EAAaC,SACX,SAASf,kBAA4BS,sCACrCC,GAEFI,EAAaC,SACX,SAASf,uBAAiCS,2CAC1CC,GAEFI,EAAaC,SAAS,SAASb,YAAmBO,WAAoBC,GAElElB,GACFsB,EAAaC,SAAS,MAAMN,8CAAuDC,GAGrFQ,QAAQC,KAAK,KAAKC,EAAMC,KAAK,qCA3C3BH,QAAQI,MACNF,EAAMG,IACJ,kGA0CR"}
package/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { readFileSync } from 'fs';\nimport chalk from 'chalk';\nimport { Command, Option } from 'commander';\nimport runBuild from '@cli/build';\nimport onKeyPress from '@cli/helpers/keyboard-input';\nimport viteResetCache from '@cli/helpers/vite-reset-cache';\nimport type {\n IBuildActionParams,\n IBuildAmplifyActionParams,\n IBuildDockerActionParams,\n IBuildVercelActionParams,\n IDevActionParams,\n IPreviewActionParams,\n IStartActionParams,\n} from '@cli/interfaces/actions';\nimport runAmplifyBuild from '@cli/run-amplify-build';\nimport runDev from '@cli/run-dev';\nimport runDockerBuild from '@cli/run-docker-build';\nimport runProd from '@cli/run-prod';\nimport runVercelBuild from '@cli/run-vercel-build';\nimport CliActions from '@constants/cli-actions';\nimport cliContext from '@constants/cli-context';\nimport cliName from '@constants/cli-name';\n\n/**\n * Parse package meta\n */\nconst { description, version } = JSON.parse(\n readFileSync(new URL('./package.json', import.meta.url), 'utf8'),\n) as { name: string; description: string; version: string };\n\n/**\n * Enable shortcuts\n * listen keyboard command\n */\nconst enableShortcuts = (): void => {\n if (process.stdin.isTTY) {\n process.stdin.setRawMode(true);\n process.stdin.on('data', onKeyPress).setEncoding('utf8').resume();\n }\n};\n\nconst program = new Command();\n\nprogram\n .name(cliName)\n .description(description)\n .version(version)\n .hook('preAction', (_, actionCommand) => {\n // pass cli action to plugin config\n global.viteBoostAction = actionCommand.name();\n });\n\n/**\n * Common options\n */\nconst hostOption = new Option(\n '--host',\n 'Ability to access the local instance on other devices under the same network.',\n).default(false);\nconst focusOnlyOption = new Option(\n '--focus-only [focusOnly]',\n 'Build or Start only specified part of app.',\n)\n .default('app')\n .choices(['all', 'app', 'client', 'server', 'entrypoint']);\nconst portOption = new Option('--port [port]', 'Server port.').default(3000);\nconst envModeOption = new Option('--mode [mode]', 'Env mode.')\n .env('VITE_ENV_MODE')\n .default('production');\nconst buildDirOption = new Option('--build-dir [buildDir]', 'Build directory output.');\n\n/**\n * Cli commands\n */\n\nprogram\n .command(CliActions.dev)\n .description('Run development server.')\n .addOption(hostOption)\n .addOption(portOption)\n .addOption(new Option('--reset-cache', 'Clear vite cache before run.').default(false))\n .addOption(new Option('--mode [mode]', 'Env mode.').env('VITE_ENV_MODE').default('development'))\n .addOption(new Option('--entrypoint [entrypoint]', 'Run only entrypoint by name.'))\n .action(async ({ host, port, resetCache, mode, entrypoint }: IDevActionParams) => {\n if (resetCache) {\n await viteResetCache();\n }\n\n const command = async (isPrintInfo?: boolean): Promise<void> => {\n console.info(chalk.cyan('Starting the development server...'));\n\n const { server, config } = await runDev({\n version,\n isHost: host,\n isPrintInfo,\n port,\n mode,\n entrypointName: entrypoint,\n });\n\n cliContext.server = server;\n cliContext.config = config;\n };\n\n cliContext.reboot = command;\n\n enableShortcuts();\n\n return command();\n });\n\nprogram\n .command(CliActions.build)\n .description('Create production build.')\n .addOption(focusOnlyOption)\n .addOption(envModeOption)\n .addOption(\n new Option(\n '--client-options [client-options]',\n 'Pass vite build options for client. Example: --client-options=\"--ssrManifest\"',\n )\n .env('VITE_BUILD_CLIENT_OPTIONS')\n .default(''),\n )\n .addOption(\n new Option('--server-options [server-options]', 'Pass vite build options for server.')\n .env('VITE_BUILD_SERVER_OPTIONS')\n .default(''),\n )\n .addOption(\n new Option(\n '--unlock-robots',\n 'Change general directive Disallow to Allow in robots.txt',\n ).default(false),\n )\n .addOption(\n new Option('--eject', 'Produces entrypoint file to run app without cli').default(false),\n )\n .addOption(\n new Option(\n '--serverless',\n 'Produces entrypoint file to run app like serverless function',\n ).default(false),\n )\n .addOption(\n new Option(\n '--throw-warnings',\n 'The build will abort with an error if warnings occur in the process.',\n ).default(false),\n )\n .action(\n async ({\n focusOnly,\n clientOptions,\n serverOptions,\n mode,\n unlockRobots,\n eject,\n serverless,\n throwWarnings,\n }: IBuildActionParams) => {\n await runBuild({\n focusOnly,\n isUnlockRobots: unlockRobots,\n isNoWarnings: throwWarnings,\n isEject: eject,\n isServerless: serverless,\n clientOptions,\n serverOptions,\n mode: mode!,\n });\n },\n );\n\nprogram\n .command(CliActions.start)\n .description('Run production server.')\n .addOption(hostOption)\n .addOption(portOption)\n .addOption(focusOnlyOption)\n .addOption(buildDirOption)\n .addOption(\n new Option('--module-preload', 'Add module preload scripts to server output.').default(false),\n )\n .action(({ host, port, focusOnly, modulePreload, buildDir }: IStartActionParams) => {\n const command = async (isPrintInfo?: boolean): Promise<void> => {\n const { server, config } = await runProd({\n version,\n isHost: host,\n isPrintInfo,\n port,\n focusOnly,\n modulePreload,\n buildDir,\n });\n\n cliContext.server = server;\n cliContext.config = config;\n };\n\n cliContext.reboot = command;\n\n enableShortcuts();\n\n return command();\n });\n\nprogram\n .command(CliActions.preview)\n .description('Build and preview production.')\n .addOption(focusOnlyOption)\n .addOption(hostOption)\n .addOption(portOption)\n .addOption(envModeOption)\n .addOption(buildDirOption)\n .action(async ({ host, port, focusOnly, mode, buildDir }: IPreviewActionParams) => {\n global.viteBoostStartTime = performance.now();\n\n const command = async (isPrintInfo?: boolean): Promise<void> => {\n const { server, config } = await runProd({\n version,\n isHost: host,\n isPrintInfo,\n port,\n focusOnly,\n buildDir,\n });\n\n server.on('listening', () => {\n setTimeout(() => {\n config.getLogger().info(chalk.yellow('\\n Running preview mode... \\n'));\n }, 0);\n });\n\n cliContext.server = server;\n cliContext.config = config;\n };\n\n cliContext.reboot = command;\n\n enableShortcuts();\n\n const buildOptions = '-w';\n\n await runBuild({\n mode: mode!,\n isWatch: true,\n focusOnly,\n clientOptions: buildOptions,\n serverOptions: buildOptions,\n onFinish: () => {\n void command();\n },\n });\n });\n\nprogram\n .command(CliActions.buildDocker)\n .description('Create docker image with production build.')\n .requiredOption('--image-name <image-name>', 'Docker image name.')\n .addOption(\n new Option(\n '--docker-options [docker-options]',\n 'Extra docker options which pass to docker build command.',\n ),\n )\n .addOption(\n new Option(\n '--docker-file [docker-file]',\n 'Name of the Dockerfile (Default is PLUGIN_PATH/workflow/Dockerfile).',\n ),\n )\n .addOption(focusOnlyOption)\n .addOption(envModeOption)\n .action(\n async ({ imageName, dockerOptions, dockerFile, focusOnly, mode }: IBuildDockerActionParams) => {\n await runDockerBuild({\n imageName,\n dockerOptions,\n dockerFile,\n focusOnly,\n mode,\n });\n },\n );\n\nprogram\n .command(CliActions.buildAmplify)\n .description('Create AWS Amplify production build.')\n .addOption(\n new Option(\n '--manifest-file [manifest-file]',\n 'Path to the Amplify manifest file (Default is PLUGIN_PATH/workflow/amplify-manifest.json).',\n ),\n )\n .addOption(new Option('--is-optimize', 'Optimize node_modules folder.').default(false))\n .addOption(envModeOption)\n .action(async ({ manifestFile, mode, isOptimize }: IBuildAmplifyActionParams) => {\n await runAmplifyBuild({\n manifestFile,\n mode,\n isOptimize,\n });\n });\n\nprogram\n .command(CliActions.buildVercel)\n .description('Create Vercel serverless production build.')\n .addOption(\n new Option(\n '--config-file [config-file]',\n 'Path to the Vercel config.json file (Default is PLUGIN_PATH/workflow/vercel.config.json).',\n ),\n )\n .addOption(\n new Option(\n '--config-vc-file [config-vc-file]',\n 'Path to the Vercel vc-config.json file (Default is PLUGIN_PATH/workflow/vercel.vc-config.json).',\n ),\n )\n .addOption(new Option('--is-optimize', 'Optimize node_modules folder.').default(false))\n .addOption(envModeOption)\n .action(async ({ configFile, configVcFile, mode, isOptimize }: IBuildVercelActionParams) => {\n await runVercelBuild({\n configFile,\n configVcFile,\n mode,\n isOptimize,\n });\n });\n\nprogram.parse();\n"],"names":["description","version","JSON","parse","readFileSync","URL","url","enableShortcuts","process","stdin","isTTY","setRawMode","on","onKeyPress","setEncoding","resume","program","Command","name","cliName","hook","_","actionCommand","global","viteBoostAction","hostOption","Option","default","focusOnlyOption","choices","portOption","envModeOption","env","buildDirOption","command","CliActions","dev","addOption","action","async","host","port","resetCache","mode","entrypoint","viteResetCache","isPrintInfo","console","info","chalk","cyan","server","config","runDev","isHost","entrypointName","cliContext","reboot","build","focusOnly","clientOptions","serverOptions","unlockRobots","eject","serverless","throwWarnings","runBuild","isUnlockRobots","isNoWarnings","isEject","isServerless","start","modulePreload","buildDir","runProd","preview","viteBoostStartTime","performance","now","setTimeout","getLogger","yellow","isWatch","onFinish","buildDocker","requiredOption","imageName","dockerOptions","dockerFile","runDockerBuild","buildAmplify","manifestFile","isOptimize","runAmplifyBuild","buildVercel","configFile","configVcFile","runVercelBuild"],"mappings":";6hBA6BA,MAAMA,YAAEA,EAAWC,QAAEA,GAAYC,KAAKC,MACpCC,EAAa,IAAIC,IAAI,6BAA8BC,KAAM,SAOrDC,EAAkB,KAClBC,QAAQC,MAAMC,QAChBF,QAAQC,MAAME,YAAW,GACzBH,QAAQC,MAAMG,GAAG,OAAQC,GAAYC,YAAY,QAAQC,SAC1D,EAGGC,EAAU,IAAIC,EAEpBD,EACGE,KAAKC,GACLnB,YAAYA,GACZC,QAAQA,GACRmB,KAAK,aAAa,CAACC,EAAGC,KAErBC,OAAOC,gBAAkBF,EAAcJ,MAAM,IAMjD,MAAMO,EAAa,IAAIC,EACrB,SACA,iFACAC,SAAQ,GACJC,EAAkB,IAAIF,EAC1B,2BACA,8CAECC,QAAQ,OACRE,QAAQ,CAAC,MAAO,MAAO,SAAU,SAAU,eACxCC,EAAa,IAAIJ,EAAO,gBAAiB,gBAAgBC,QAAQ,KACjEI,EAAgB,IAAIL,EAAO,gBAAiB,aAC/CM,IAAI,iBACJL,QAAQ,cACLM,EAAiB,IAAIP,EAAO,yBAA0B,2BAM5DV,EACGkB,QAAQC,EAAWC,KACnBpC,YAAY,2BACZqC,UAAUZ,GACVY,UAAUP,GACVO,UAAU,IAAIX,EAAO,gBAAiB,gCAAgCC,SAAQ,IAC9EU,UAAU,IAAIX,EAAO,gBAAiB,aAAaM,IAAI,iBAAiBL,QAAQ,gBAChFU,UAAU,IAAIX,EAAO,4BAA6B,iCAClDY,QAAOC,OAASC,OAAMC,OAAMC,aAAYC,OAAMC,iBACzCF,SACIG,IAGR,MAAMX,EAAUK,MAAOO,IACrBC,QAAQC,KAAKC,EAAMC,KAAK,uCAExB,MAAMC,OAAEA,EAAMC,OAAEA,SAAiBC,EAAO,CACtCpD,UACAqD,OAAQd,EACRM,cACAL,OACAE,OACAY,eAAgBX,IAGlBY,EAAWL,OAASA,EACpBK,EAAWJ,OAASA,CAAM,EAO5B,OAJAI,EAAWC,OAASvB,EAEpB3B,IAEO2B,GAAS,IAGpBlB,EACGkB,QAAQC,EAAWuB,OACnB1D,YAAY,4BACZqC,UAAUT,GACVS,UAAUN,GACVM,UACC,IAAIX,EACF,oCACA,iFAECM,IAAI,6BACJL,QAAQ,KAEZU,UACC,IAAIX,EAAO,oCAAqC,uCAC7CM,IAAI,6BACJL,QAAQ,KAEZU,UACC,IAAIX,EACF,kBACA,4DACAC,SAAQ,IAEXU,UACC,IAAIX,EAAO,UAAW,mDAAmDC,SAAQ,IAElFU,UACC,IAAIX,EACF,eACA,gEACAC,SAAQ,IAEXU,UACC,IAAIX,EACF,mBACA,wEACAC,SAAQ,IAEXW,QACCC,OACEoB,YACAC,gBACAC,gBACAlB,OACAmB,eACAC,QACAC,aACAC,0BAEMC,EAAS,CACbP,YACAQ,eAAgBL,EAChBM,aAAcH,EACdI,QAASN,EACTO,aAAcN,EACdJ,gBACAC,gBACAlB,KAAMA,GACN,IAIR3B,EACGkB,QAAQC,EAAWoC,OACnBvE,YAAY,0BACZqC,UAAUZ,GACVY,UAAUP,GACVO,UAAUT,GACVS,UAAUJ,GACVI,UACC,IAAIX,EAAO,mBAAoB,gDAAgDC,SAAQ,IAExFW,QAAO,EAAGE,OAAMC,OAAMkB,YAAWa,gBAAeC,eAC/C,MAAMvC,EAAUK,MAAOO,IACrB,MAAMK,OAAEA,EAAMC,OAAEA,SAAiBsB,EAAQ,CACvCzE,UACAqD,OAAQd,EACRM,cACAL,OACAkB,YACAa,gBACAC,aAGFjB,EAAWL,OAASA,EACpBK,EAAWJ,OAASA,CAAM,EAO5B,OAJAI,EAAWC,OAASvB,EAEpB3B,IAEO2B,GAAS,IAGpBlB,EACGkB,QAAQC,EAAWwC,SACnB3E,YAAY,iCACZqC,UAAUT,GACVS,UAAUZ,GACVY,UAAUP,GACVO,UAAUN,GACVM,UAAUJ,GACVK,QAAOC,OAASC,OAAMC,OAAMkB,YAAWhB,OAAM8B,eAC5ClD,OAAOqD,mBAAqBC,YAAYC,MAExC,MAAM5C,EAAUK,MAAOO,IACrB,MAAMK,OAAEA,EAAMC,OAAEA,SAAiBsB,EAAQ,CACvCzE,UACAqD,OAAQd,EACRM,cACAL,OACAkB,YACAc,aAGFtB,EAAOvC,GAAG,aAAa,KACrBmE,YAAW,KACT3B,EAAO4B,YAAYhC,KAAKC,EAAMgC,OAAO,kCAAkC,GACtE,EAAE,IAGPzB,EAAWL,OAASA,EACpBK,EAAWJ,OAASA,CAAM,EAG5BI,EAAWC,OAASvB,EAEpB3B,UAIM2D,EAAS,CACbvB,KAAMA,EACNuC,SAAS,EACTvB,YACAC,cANmB,KAOnBC,cAPmB,KAQnBsB,SAAU,KACHjD,GAAS,GAEhB,IAGNlB,EACGkB,QAAQC,EAAWiD,aACnBpF,YAAY,8CACZqF,eAAe,4BAA6B,sBAC5ChD,UACC,IAAIX,EACF,oCACA,6DAGHW,UACC,IAAIX,EACF,8BACA,yEAGHW,UAAUT,GACVS,UAAUN,GACVO,QACCC,OAAS+C,YAAWC,gBAAeC,aAAY7B,YAAWhB,iBAClD8C,EAAe,CACnBH,YACAC,gBACAC,aACA7B,YACAhB,QACA,IAIR3B,EACGkB,QAAQC,EAAWuD,cACnB1F,YAAY,wCACZqC,UACC,IAAIX,EACF,kCACA,+FAGHW,UAAU,IAAIX,EAAO,gBAAiB,iCAAiCC,SAAQ,IAC/EU,UAAUN,GACVO,QAAOC,OAASoD,eAAchD,OAAMiD,uBAC7BC,EAAgB,CACpBF,eACAhD,OACAiD,cACA,IAGN5E,EACGkB,QAAQC,EAAW2D,aACnB9F,YAAY,8CACZqC,UACC,IAAIX,EACF,8BACA,8FAGHW,UACC,IAAIX,EACF,oCACA,oGAGHW,UAAU,IAAIX,EAAO,gBAAiB,iCAAiCC,SAAQ,IAC/EU,UAAUN,GACVO,QAAOC,OAASwD,aAAYC,eAAcrD,OAAMiD,uBACzCK,EAAe,CACnBF,aACAC,eACArD,OACAiD,cACA,IAGN5E,EAAQb"}
1
+ {"version":3,"file":"cli.js","sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { readFileSync } from 'fs';\nimport chalk from 'chalk';\nimport { Command, Option } from 'commander';\nimport runBuild from '@cli/build';\nimport onKeyPress from '@cli/helpers/keyboard-input';\nimport viteResetCache from '@cli/helpers/vite-reset-cache';\nimport type {\n IBuildActionParams,\n IBuildAmplifyActionParams,\n IBuildDockerActionParams,\n IBuildVercelActionParams,\n IDevActionParams,\n IPreviewActionParams,\n IStartActionParams,\n} from '@cli/interfaces/actions';\nimport runAmplifyBuild from '@cli/run-amplify-build';\nimport runDev from '@cli/run-dev';\nimport runDockerBuild from '@cli/run-docker-build';\nimport runProd from '@cli/run-prod';\nimport runVercelBuild from '@cli/run-vercel-build';\nimport CliActions from '@constants/cli-actions';\nimport cliContext from '@constants/cli-context';\nimport cliName from '@constants/cli-name';\n\n/**\n * Parse package meta\n */\nconst { description, version } = JSON.parse(\n readFileSync(new URL('./package.json', import.meta.url), 'utf8'),\n) as { name: string; description: string; version: string };\n\n/**\n * Enable shortcuts\n * listen keyboard command\n */\nconst enableShortcuts = (): void => {\n if (process.stdin.isTTY) {\n process.stdin.setRawMode(true);\n process.stdin.on('data', onKeyPress).setEncoding('utf8').resume();\n }\n};\n\nconst program = new Command();\n\nprogram\n .name(cliName)\n .description(description)\n .version(version)\n .hook('preAction', (_, actionCommand) => {\n // pass cli action to plugin config\n global.viteBoostAction = actionCommand.name();\n });\n\n/**\n * Common options\n */\nconst hostOption = new Option(\n '--host',\n 'Ability to access the local instance on other devices under the same network.',\n).default(false);\nconst focusOnlyOption = new Option(\n '--focus-only [focusOnly]',\n 'Build or Start only specified part of app.',\n)\n .default('app')\n .choices(['all', 'app', 'client', 'server', 'entrypoint']);\nconst portOption = new Option('--port [port]', 'Server port.').default(3000);\nconst envModeOption = new Option('--mode [mode]', 'Env mode.')\n .env('VITE_ENV_MODE')\n .default('production');\nconst buildDirOption = new Option('--build-dir [buildDir]', 'Build directory output.');\n\n/**\n * Cli commands\n */\n\nprogram\n .command(CliActions.dev)\n .description('Run development server.')\n .addOption(hostOption)\n .addOption(portOption)\n .addOption(new Option('--reset-cache', 'Clear vite cache before run.').default(false))\n .addOption(new Option('--mode [mode]', 'Env mode.').env('VITE_ENV_MODE').default('development'))\n .addOption(new Option('--entrypoint [entrypoint]', 'Run only entrypoint by name.'))\n .action(async ({ host, port, resetCache, mode, entrypoint }: IDevActionParams) => {\n if (resetCache) {\n await viteResetCache();\n }\n\n const command = async (isPrintInfo?: boolean): Promise<void> => {\n console.info(chalk.cyan('Starting the development server...'));\n\n const { server, config } = await runDev({\n version,\n isHost: host,\n isPrintInfo,\n port,\n mode,\n entrypointName: entrypoint,\n });\n\n cliContext.server = server;\n cliContext.config = config;\n };\n\n cliContext.reboot = command;\n\n enableShortcuts();\n\n return command();\n });\n\nprogram\n .command(CliActions.build)\n .description('Create production build.')\n .addOption(focusOnlyOption)\n .addOption(envModeOption)\n .addOption(\n new Option(\n '--client-options [client-options]',\n 'Pass vite build options for client. Example: --client-options=\"--ssrManifest\"',\n )\n .env('VITE_BUILD_CLIENT_OPTIONS')\n .default(''),\n )\n .addOption(\n new Option('--server-options [server-options]', 'Pass vite build options for server.')\n .env('VITE_BUILD_SERVER_OPTIONS')\n .default(''),\n )\n .addOption(\n new Option(\n '--unlock-robots',\n 'Change general directive Disallow to Allow in robots.txt',\n ).default(false),\n )\n .addOption(\n new Option('--eject', 'Produces entrypoint file to run app without cli').default(false),\n )\n .addOption(\n new Option(\n '--serverless',\n 'Produces entrypoint file to run app like serverless function',\n ).default(false),\n )\n .addOption(\n new Option(\n '--throw-warnings',\n 'The build will abort with an error if warnings occur in the process.',\n ).default(false),\n )\n .action(\n async ({\n focusOnly,\n clientOptions,\n serverOptions,\n mode,\n unlockRobots,\n eject,\n serverless,\n throwWarnings,\n }: IBuildActionParams) => {\n await runBuild({\n focusOnly,\n isUnlockRobots: unlockRobots,\n isNoWarnings: throwWarnings,\n isEject: eject,\n isServerless: serverless,\n clientOptions,\n serverOptions,\n mode: mode!,\n });\n },\n );\n\nprogram\n .command(CliActions.start)\n .description('Run production server.')\n .addOption(hostOption)\n .addOption(portOption)\n .addOption(focusOnlyOption)\n .addOption(buildDirOption)\n .addOption(\n new Option('--module-preload', 'Add module preload scripts to server output.').default(false),\n )\n .action(({ host, port, focusOnly, modulePreload, buildDir }: IStartActionParams) => {\n const command = async (isPrintInfo?: boolean): Promise<void> => {\n const { server, config } = await runProd({\n version,\n isHost: host,\n isPrintInfo,\n port,\n focusOnly,\n modulePreload,\n buildDir,\n });\n\n cliContext.server = server;\n cliContext.config = config;\n };\n\n cliContext.reboot = command;\n\n enableShortcuts();\n\n return command();\n });\n\nprogram\n .command(CliActions.preview)\n .description('Build and preview production.')\n .addOption(focusOnlyOption)\n .addOption(hostOption)\n .addOption(portOption)\n .addOption(envModeOption)\n .addOption(buildDirOption)\n .action(async ({ host, port, focusOnly, mode, buildDir }: IPreviewActionParams) => {\n global.viteBoostStartTime = performance.now();\n\n const command = async (isPrintInfo?: boolean): Promise<void> => {\n const { server, config } = await runProd({\n version,\n isHost: host,\n isPrintInfo,\n port,\n focusOnly,\n buildDir,\n });\n\n server.on('listening', () => {\n setTimeout(() => {\n config.getLogger().info(chalk.yellow('\\n Running preview mode... \\n'));\n }, 0);\n });\n\n cliContext.server = server;\n cliContext.config = config;\n };\n\n cliContext.reboot = command;\n\n enableShortcuts();\n\n const buildOptions = '-w';\n\n await runBuild({\n mode: mode!,\n isWatch: true,\n focusOnly,\n clientOptions: buildOptions,\n serverOptions: buildOptions,\n onFinish: () => {\n void command();\n },\n });\n });\n\nprogram\n .command(CliActions.buildDocker)\n .description('Create docker image with production build.')\n .requiredOption('--image-name <image-name>', 'Docker image name.')\n .addOption(\n new Option(\n '--docker-options [docker-options]',\n 'Extra docker options which pass to docker build command.',\n ),\n )\n .addOption(\n new Option(\n '--docker-file [docker-file]',\n 'Name of the Dockerfile (Default is PLUGIN_PATH/workflow/Dockerfile).',\n ),\n )\n .addOption(focusOnlyOption)\n .addOption(envModeOption)\n .action(\n async ({ imageName, dockerOptions, dockerFile, focusOnly, mode }: IBuildDockerActionParams) => {\n await runDockerBuild({\n imageName,\n dockerOptions,\n dockerFile,\n focusOnly,\n mode,\n });\n },\n );\n\nprogram\n .command(CliActions.buildAmplify)\n .description('Create AWS Amplify production build.')\n .addOption(\n new Option(\n '--manifest-file [manifest-file]',\n 'Path to the Amplify manifest file (Default is PLUGIN_PATH/workflow/amplify-manifest.json).',\n ),\n )\n .addOption(new Option('--is-optimize', 'Optimize node_modules folder.').default(false))\n .addOption(envModeOption)\n .action(async ({ manifestFile, mode, isOptimize }: IBuildAmplifyActionParams) => {\n await runAmplifyBuild({\n manifestFile,\n mode,\n isOptimize,\n });\n });\n\nprogram\n .command(CliActions.buildVercel)\n .description('Create Vercel serverless production build.')\n .addOption(\n new Option(\n '--config-file [config-file]',\n 'Path to the Vercel config.json file (Default is PLUGIN_PATH/workflow/vercel.config.json).',\n ),\n )\n .addOption(\n new Option(\n '--config-vc-file [config-vc-file]',\n 'Path to the Vercel vc-config.json file (Default is PLUGIN_PATH/workflow/vercel.vc-config.json).',\n ),\n )\n .addOption(new Option('--is-optimize', 'Optimize node_modules folder.').default(false))\n .addOption(envModeOption)\n .action(async ({ configFile, configVcFile, mode, isOptimize }: IBuildVercelActionParams) => {\n await runVercelBuild({\n configFile,\n configVcFile,\n mode,\n isOptimize,\n });\n });\n\nprogram.parse();\n"],"names":["description","version","JSON","parse","readFileSync","URL","url","enableShortcuts","process","stdin","isTTY","setRawMode","on","onKeyPress","setEncoding","resume","program","Command","name","cliName","hook","_","actionCommand","global","viteBoostAction","hostOption","Option","default","focusOnlyOption","choices","portOption","envModeOption","env","buildDirOption","command","CliActions","dev","addOption","action","async","host","port","resetCache","mode","entrypoint","viteResetCache","isPrintInfo","console","info","chalk","cyan","server","config","runDev","isHost","entrypointName","cliContext","reboot","build","focusOnly","clientOptions","serverOptions","unlockRobots","eject","serverless","throwWarnings","runBuild","isUnlockRobots","isNoWarnings","isEject","isServerless","start","modulePreload","buildDir","runProd","preview","viteBoostStartTime","performance","now","setTimeout","getLogger","yellow","isWatch","onFinish","buildDocker","requiredOption","imageName","dockerOptions","dockerFile","runDockerBuild","buildAmplify","manifestFile","isOptimize","runAmplifyBuild","buildVercel","configFile","configVcFile","runVercelBuild"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"navigate.js","sources":["../../src/components/navigate.tsx"],"sourcesContent":["import type { FC } from 'react';\nimport React from 'react';\nimport type { NavigateProps } from 'react-router';\nimport { Navigate as DefaultNavigate } from 'react-router';\nimport { useServerContext } from '@context/server';\n\ninterface INavigate {\n status?: number;\n}\n\ntype TProps = INavigate & NavigateProps;\n\n/**\n * React router navigate with server support\n * @constructor\n */\nconst Navigate: FC<TProps> = ({ to, status = 301, ...rest }) => {\n const context = useServerContext();\n\n if (!context.isServer) {\n return <DefaultNavigate to={to} {...rest} />;\n }\n\n if (context) {\n const { basename } = context;\n const location = [basename, typeof to === 'string' ? to : [to.pathname, to.search, to.hash]]\n .flat()\n .filter(Boolean)\n .join('')\n .replace(/\\/+/g, '/');\n\n context.response = new Response('', { status, headers: new Headers({ Location: location }) });\n }\n\n return null;\n};\n\nexport default Navigate;\n"],"names":["Navigate","to","status","rest","context","useServerContext","isServer","React","createElement","DefaultNavigate","basename","location","pathname","search","hash","flat","filter","Boolean","join","replace","response","Response","headers","Headers","Location"],"mappings":"qHAgBA,MAAMA,EAAuB,EAAGC,KAAIC,SAAS,OAAQC,MACnD,MAAMC,EAAUC,IAEhB,IAAKD,EAAQE,SACX,OAAOC,EAAAC,cAACC,EAAgB,CAAAR,GAAIA,KAAQE,IAGtC,GAAIC,EAAS,CACX,MAAMM,SAAEA,GAAaN,EACfO,EAAW,CAACD,EAAwB,iBAAPT,EAAkBA,EAAK,CAACA,EAAGW,SAAUX,EAAGY,OAAQZ,EAAGa,OACnFC,OACAC,OAAOC,SACPC,KAAK,IACLC,QAAQ,OAAQ,KAEnBf,EAAQgB,SAAW,IAAIC,SAAS,GAAI,CAAEnB,SAAQoB,QAAS,IAAIC,QAAQ,CAAEC,SAAUb,KAChF,CAED,OAAO,IAAI"}
1
+ {"version":3,"file":"navigate.js","sources":["../../src/components/navigate.tsx"],"sourcesContent":["import type { FC } from 'react';\nimport React from 'react';\nimport type { NavigateProps } from 'react-router';\nimport { Navigate as DefaultNavigate } from 'react-router';\nimport { useServerContext } from '@context/server';\n\ninterface INavigate {\n status?: number;\n}\n\ntype TProps = INavigate & NavigateProps;\n\n/**\n * React router navigate with server support\n * @constructor\n */\nconst Navigate: FC<TProps> = ({ to, status = 301, ...rest }) => {\n const context = useServerContext();\n\n if (!context.isServer) {\n return <DefaultNavigate to={to} {...rest} />;\n }\n\n if (context) {\n const { basename } = context;\n const location = [basename, typeof to === 'string' ? to : [to.pathname, to.search, to.hash]]\n .flat()\n .filter(Boolean)\n .join('')\n .replace(/\\/+/g, '/');\n\n context.response = new Response('', { status, headers: new Headers({ Location: location }) });\n }\n\n return null;\n};\n\nexport default Navigate;\n"],"names":["Navigate","to","status","rest","context","useServerContext","isServer","React","createElement","DefaultNavigate","basename","location","pathname","search","hash","flat","filter","Boolean","join","replace","response","Response","headers","Headers","Location"],"mappings":"qHAgBA,MAAMA,EAAuB,EAAGC,KAAIC,SAAS,OAAQC,MACnD,MAAMC,EAAUC,IAEhB,IAAKD,EAAQE,SACX,OAAOC,EAAAC,cAACC,EAAgB,CAAAR,GAAIA,KAAQE,IAGtC,GAAIC,EAAS,CACX,MAAMM,SAAEA,GAAaN,EACfO,EAAW,CAACD,EAAwB,iBAAPT,EAAkBA,EAAK,CAACA,EAAGW,SAAUX,EAAGY,OAAQZ,EAAGa,OACnFC,OACAC,OAAOC,SACPC,KAAK,IACLC,QAAQ,OAAQ,KAEnBf,EAAQgB,SAAW,IAAIC,SAAS,GAAI,CAAEnB,SAAQoB,QAAS,IAAIC,QAAQ,CAAEC,SAAUb,MAGjF,OAAO,IAAI"}
@@ -1 +1 @@
1
- {"version":3,"file":"dev-marker.js","sources":["../../src/helpers/dev-marker.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport type { ResolvedConfig } from 'vite';\n\nconst getMarkerFile = (root: string, withFile = true): string =>\n [root, 'server', withFile && '.dev'].filter(Boolean).join('/');\n\n/**\n * Create dev marker\n *\n * @see printServerInfo\n */\nconst createDevMarker = (isProd: boolean, { root, build: buildConf }: ResolvedConfig): void => {\n const buildRoot = path.resolve(root, buildConf.outDir);\n const devMarkerPath = getMarkerFile(buildRoot, false);\n const devMarker = getMarkerFile(buildRoot);\n\n if (!isProd) {\n if (!fs.existsSync(devMarkerPath)) {\n fs.mkdirSync(devMarkerPath, { recursive: true });\n }\n\n fs.writeFileSync(devMarker, '');\n } else if (fs.existsSync(devMarker)) {\n fs.rmSync(devMarker);\n }\n};\n\nexport { createDevMarker, getMarkerFile };\n"],"names":["getMarkerFile","root","withFile","filter","Boolean","join","createDevMarker","isProd","build","buildConf","buildRoot","path","resolve","outDir","devMarkerPath","devMarker","fs","existsSync","rmSync","mkdirSync","recursive","writeFileSync"],"mappings":"gDAIA,MAAMA,EAAgB,CAACC,EAAcC,GAAW,IAC9C,CAACD,EAAM,SAAUC,GAAY,QAAQC,OAAOC,SAASC,KAAK,KAOtDC,EAAkB,CAACC,GAAmBN,OAAMO,MAAOC,MACvD,MAAMC,EAAYC,EAAKC,QAAQX,EAAMQ,EAAUI,QACzCC,EAAgBd,EAAcU,GAAW,GACzCK,EAAYf,EAAcU,GAE3BH,EAMMS,EAAGC,WAAWF,IACvBC,EAAGE,OAAOH,IANLC,EAAGC,WAAWH,IACjBE,EAAGG,UAAUL,EAAe,CAAEM,WAAW,IAG3CJ,EAAGK,cAAcN,EAAW,IAG7B"}
1
+ {"version":3,"file":"dev-marker.js","sources":["../../src/helpers/dev-marker.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport type { ResolvedConfig } from 'vite';\n\nconst getMarkerFile = (root: string, withFile = true): string =>\n [root, 'server', withFile && '.dev'].filter(Boolean).join('/');\n\n/**\n * Create dev marker\n *\n * @see printServerInfo\n */\nconst createDevMarker = (isProd: boolean, { root, build: buildConf }: ResolvedConfig): void => {\n const buildRoot = path.resolve(root, buildConf.outDir);\n const devMarkerPath = getMarkerFile(buildRoot, false);\n const devMarker = getMarkerFile(buildRoot);\n\n if (!isProd) {\n if (!fs.existsSync(devMarkerPath)) {\n fs.mkdirSync(devMarkerPath, { recursive: true });\n }\n\n fs.writeFileSync(devMarker, '');\n } else if (fs.existsSync(devMarker)) {\n fs.rmSync(devMarker);\n }\n};\n\nexport { createDevMarker, getMarkerFile };\n"],"names":["getMarkerFile","root","withFile","filter","Boolean","join","createDevMarker","isProd","build","buildConf","buildRoot","path","resolve","outDir","devMarkerPath","devMarker","fs","existsSync","rmSync","mkdirSync","recursive","writeFileSync"],"mappings":"gDAIA,MAAMA,EAAgB,CAACC,EAAcC,GAAW,IAC9C,CAACD,EAAM,SAAUC,GAAY,QAAQC,OAAOC,SAASC,KAAK,KAOtDC,EAAkB,CAACC,GAAmBN,OAAMO,MAAOC,MACvD,MAAMC,EAAYC,EAAKC,QAAQX,EAAMQ,EAAUI,QACzCC,EAAgBd,EAAcU,GAAW,GACzCK,EAAYf,EAAcU,GAE3BH,EAMMS,EAAGC,WAAWF,IACvBC,EAAGE,OAAOH,IANLC,EAAGC,WAAWH,IACjBE,EAAGG,UAAUL,EAAe,CAAEM,WAAW,IAG3CJ,EAAGK,cAAcN,EAAW"}
@@ -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 = <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"}
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,CAAE,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"import-route.js","sources":["../../src/helpers/import-route.ts"],"sourcesContent":["import type { IndexRouteObject, NonIndexRouteObject } from 'react-router';\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 ImmutableRouteKey = 'lazy' | 'caseSensitive' | 'path' | 'id' | 'index' | 'children';\n\nexport type IAsyncRoute = { pathId?: string } & (\n | Omit<IndexRouteObject, ImmutableRouteKey>\n | Omit<NonIndexRouteObject, ImmutableRouteKey>\n);\n\n/**\n * Import dynamic route\n */\nconst importRoute = (route: IDynamicRoute, id?: string): (() => Promise<IAsyncRoute>) => {\n return async (): 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 // @ts-ignore\n result[key] = Component[key] as NonNullable<IAsyncRoute[typeof key]>;\n }\n });\n\n if (Component.Suspense) {\n result.Component = withSuspense(Component, Component.Suspense);\n }\n\n return result;\n };\n};\n\nexport default importRoute;\n"],"names":["importRoute","route","id","async","resolved","pathId","Component","default","result","keys","forEach","key","Suspense","withSuspense"],"mappings":"+FAiBA,MAAMA,EAAc,CAACC,EAAsBC,IAClCC,UACL,MAAMC,QAAiBH,IAGvB,GAAI,cAAeG,EACjB,MAAO,IAAKA,EAAUC,OAAQH,GAGhC,MAAMI,EAAYF,EAASG,QACrBC,EAAsB,CAAEF,YAAWD,OAAQH,GAajD,OAXAO,EAAKC,SAASC,IACRL,EAAUK,KAEZH,EAAOG,GAAOL,EAAUK,GACzB,IAGCL,EAAUM,WACZJ,EAAOF,UAAYO,EAAaP,EAAWA,EAAUM,WAGhDJ,CAAM"}
1
+ {"version":3,"file":"import-route.js","sources":["../../src/helpers/import-route.ts"],"sourcesContent":["import type { IndexRouteObject, NonIndexRouteObject } from 'react-router';\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 ImmutableRouteKey = 'lazy' | 'caseSensitive' | 'path' | 'id' | 'index' | 'children';\n\nexport type IAsyncRoute = { pathId?: string } & (\n | Omit<IndexRouteObject, ImmutableRouteKey>\n | Omit<NonIndexRouteObject, ImmutableRouteKey>\n);\n\n/**\n * Import dynamic route\n */\nconst importRoute = (route: IDynamicRoute, id?: string): (() => Promise<IAsyncRoute>) => {\n return async (): 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 // @ts-ignore\n result[key] = Component[key] as NonNullable<IAsyncRoute[typeof key]>;\n }\n });\n\n if (Component.Suspense) {\n result.Component = withSuspense(Component, Component.Suspense);\n }\n\n return result;\n };\n};\n\nexport default importRoute;\n"],"names":["importRoute","route","id","async","resolved","pathId","Component","default","result","keys","forEach","key","Suspense","withSuspense"],"mappings":"+FAiBA,MAAMA,EAAc,CAACC,EAAsBC,IAClCC,UACL,MAAMC,QAAiBH,IAGvB,GAAI,cAAeG,EACjB,MAAO,IAAKA,EAAUC,OAAQH,GAGhC,MAAMI,EAAYF,EAASG,QACrBC,EAAsB,CAAEF,YAAWD,OAAQH,GAajD,OAXAO,EAAKC,SAASC,IACRL,EAAUK,KAEZH,EAAOG,GAAOL,EAAUK,OAIxBL,EAAUM,WACZJ,EAAOF,UAAYO,EAAaP,EAAWA,EAAUM,WAGhDJ,CAAM"}
@@ -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 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 server?: Server;\n}\n\n/**\n * Print server info\n */\nasync function printServerInfo(\n config: ServerConfig,\n { server, version = 'unknown' }: IPrintServerInfoParams = {},\n): Promise<void> {\n const { action } = config.getPluginConfig() ?? {};\n const { isProd, host, root, isSPA } = 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 = server\n ? await resolveServerUrls(server, {\n host,\n isHttps: Boolean(viteConfig?.server.https),\n rawBase: viteConfig?.rawBase,\n })\n : null;\n const mode =\n viteConfig?.mode || isProdBuild\n ? config.mode\n : `production ${chalk.red('NODE_ENV=development')}`;\n const type = isSPA ? 'SPA' : 'SSR';\n\n Logger.info(chalk.dim(chalk.green(' ➜')) + chalk.dim(' Mode: ') + chalk.blue(mode));\n Logger.info(chalk.dim(chalk.green(' ➜')) + chalk.dim(' Type: ') + chalk.blue(type));\n\n if (!isProd) {\n const vite = config.getVite()!;\n\n vite.resolvedUrls = resolvedUrls;\n vite.printUrls();\n } else if (resolvedUrls) {\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","config","server","version","action","getPluginConfig","isProd","host","root","isSPA","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","Boolean","https","rawBase","red","type","blue","printServerUrls","msg","vite","printUrls","CliActions","dev"],"mappings":"2SAoBAA,eAAeC,EACbC,GACAC,OAAEA,EAAMC,QAAEA,EAAU,WAAsC,IAE1D,MAAMC,OAAEA,GAAWH,EAAOI,mBAAqB,CAAA,GACzCC,OAAEA,EAAMC,KAAEA,EAAIC,KAAEA,EAAIC,MAAEA,GAAUR,EAAOS,YACvCC,EAAYC,EAAcJ,GAE1BK,EAASZ,EAAOa,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,mBAAmB3B,SACrCiB,MACN,CAAEW,OAAQlB,EAAOmB,YAGnB,MAAMC,EAAahC,EAAOiC,WAAWjC,OAG/BkC,GAAeF,GAAYG,OAASC,EAAGC,WAAW3B,GAClD4B,EAAerC,QACXsC,EAAkBtC,EAAQ,CAC9BK,OACAkC,QAASC,QAAQT,GAAY/B,OAAOyC,OACpCC,QAASX,GAAYW,UAEvB,KACER,EACJH,GAAYG,MAAQD,EAChBlC,EAAOmC,KACP,cAAcf,EAAMwB,IAAI,0BACxBC,EAAOrC,EAAQ,MAAQ,MAK7B,GAHAI,EAAOc,KAAKN,EAAMC,IAAID,EAAMO,MAAM,QAAUP,EAAMC,IAAI,eAAiBD,EAAM0B,KAAKX,IAClFvB,EAAOc,KAAKN,EAAMC,IAAID,EAAMO,MAAM,QAAUP,EAAMC,IAAI,eAAiBD,EAAM0B,KAAKD,IAE7ExC,EAKMiC,GACTS,EAAgBT,GAAeU,GAAQpC,EAAOc,KAAKsB,SANxC,CACX,MAAMC,EAAOjD,EAAOiC,UAEpBgB,EAAKX,aAAeA,EACpBW,EAAKC,WACN,CAIG/C,IAAWgD,EAAWC,KACxBxC,EAAOc,KACLN,EAAMC,IAAID,EAAMO,MAAM,QACpBP,EAAMC,IAAI,YACVD,EAAMG,KAAK,KACXH,EAAMC,IAAI,iBAGlB"}
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 server?: Server;\n}\n\n/**\n * Print server info\n */\nasync function printServerInfo(\n config: ServerConfig,\n { server, version = 'unknown' }: IPrintServerInfoParams = {},\n): Promise<void> {\n const { action } = config.getPluginConfig() ?? {};\n const { isProd, host, root, isSPA } = 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 = server\n ? await resolveServerUrls(server, {\n host,\n isHttps: Boolean(viteConfig?.server.https),\n rawBase: viteConfig?.rawBase,\n })\n : null;\n const mode =\n viteConfig?.mode || isProdBuild\n ? config.mode\n : `production ${chalk.red('NODE_ENV=development')}`;\n const type = isSPA ? 'SPA' : 'SSR';\n\n Logger.info(chalk.dim(chalk.green(' ➜')) + chalk.dim(' Mode: ') + chalk.blue(mode));\n Logger.info(chalk.dim(chalk.green(' ➜')) + chalk.dim(' Type: ') + chalk.blue(type));\n\n if (!isProd) {\n const vite = config.getVite()!;\n\n vite.resolvedUrls = resolvedUrls;\n vite.printUrls();\n } else if (resolvedUrls) {\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","config","server","version","action","getPluginConfig","isProd","host","root","isSPA","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","Boolean","https","rawBase","red","type","blue","printServerUrls","msg","vite","printUrls","CliActions","dev"],"mappings":"2SAoBAA,eAAeC,EACbC,GACAC,OAAEA,EAAMC,QAAEA,EAAU,WAAsC,IAE1D,MAAMC,OAAEA,GAAWH,EAAOI,mBAAqB,CAAE,GAC3CC,OAAEA,EAAMC,KAAEA,EAAIC,KAAEA,EAAIC,MAAEA,GAAUR,EAAOS,YACvCC,EAAYC,EAAcJ,GAE1BK,EAASZ,EAAOa,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,mBAAmB3B,SACrCiB,MACN,CAAEW,OAAQlB,EAAOmB,YAGnB,MAAMC,EAAahC,EAAOiC,WAAWjC,OAG/BkC,GAAeF,GAAYG,OAASC,EAAGC,WAAW3B,GAClD4B,EAAerC,QACXsC,EAAkBtC,EAAQ,CAC9BK,OACAkC,QAASC,QAAQT,GAAY/B,OAAOyC,OACpCC,QAASX,GAAYW,UAEvB,KACER,EACJH,GAAYG,MAAQD,EAChBlC,EAAOmC,KACP,cAAcf,EAAMwB,IAAI,0BACxBC,EAAOrC,EAAQ,MAAQ,MAK7B,GAHAI,EAAOc,KAAKN,EAAMC,IAAID,EAAMO,MAAM,QAAUP,EAAMC,IAAI,eAAiBD,EAAM0B,KAAKX,IAClFvB,EAAOc,KAAKN,EAAMC,IAAID,EAAMO,MAAM,QAAUP,EAAMC,IAAI,eAAiBD,EAAM0B,KAAKD,IAE7ExC,EAKMiC,GACTS,EAAgBT,GAAeU,GAAQpC,EAAOc,KAAKsB,SANxC,CACX,MAAMC,EAAOjD,EAAOiC,UAEpBgB,EAAKX,aAAeA,EACpBW,EAAKC,YAKH/C,IAAWgD,EAAWC,KACxBxC,EAAOc,KACLN,EAAMC,IAAID,EAAMO,MAAM,QACpBP,EAAMC,IAAI,YACVD,EAAMG,KAAK,KACXH,EAAMC,IAAI,iBAGlB"}
@@ -1 +1 @@
1
- {"version":3,"file":"resolve-server-urls.js","sources":["../../src/helpers/resolve-server-urls.ts"],"sourcesContent":["import { promises as dns } from 'node:dns';\nimport type { AddressInfo, Server } from 'node:net';\nimport os from 'node:os';\nimport type { ResolvedServerUrls } from 'vite';\n\ninterface IHostname {\n host: string | undefined;\n name: string;\n}\n\nconst loopbackHosts = new Set([\n 'localhost',\n '127.0.0.1',\n '::1',\n '0000:0000:0000:0000:0000:0000:0000:0001',\n]);\n\nconst wildcardHosts = new Set(['0.0.0.0', '::', '0000:0000:0000:0000:0000:0000:0000:0000']);\n\n/**\n * @see https://github.com/vitejs/vite/blob/main/packages/vite/src/node/utils.ts#LL819C8-L830C2\n */\nasync function getLocalhostAddressIfDiffersFromDNS(): Promise<string | undefined> {\n const [nodeResult, dnsResult] = await Promise.all([\n dns.lookup('localhost'),\n dns.lookup('localhost', { verbatim: true }),\n ]);\n const isSame = nodeResult.family === dnsResult.family && nodeResult.address === dnsResult.address;\n\n return isSame ? undefined : nodeResult.address;\n}\n\n/**\n * Resolve hostname\n * @see https://github.com/vitejs/vite/blob/main/packages/vite/src/node/utils.ts#LL852C1-L878C2\n * vite not export this function\n */\nasync function resolveHostname(optionsHost: string | boolean | undefined): Promise<IHostname> {\n let host: string | undefined;\n\n if (optionsHost === undefined || optionsHost === false) {\n // Use a secure default\n host = 'localhost';\n } else if (optionsHost === true) {\n // If passed --host in the CLI without arguments\n host = undefined; // undefined typically means 0.0.0.0 or :: (listen on all IPs)\n } else {\n host = optionsHost;\n }\n\n // Set host name to localhost when possible\n let name = host === undefined || wildcardHosts.has(host) ? 'localhost' : host;\n\n if (host === 'localhost') {\n // See #8647 for more details.\n const localhostAddr = await getLocalhostAddressIfDiffersFromDNS();\n\n if (localhostAddr) {\n name = localhostAddr;\n }\n }\n\n return { host, name };\n}\n\ninterface IResolveServerUrlsOptions {\n host: string;\n isHttps?: boolean;\n rawBase?: string;\n}\n\n/**\n * Resolve server urls\n * @see https://github.com/vitejs/vite/blob/main/packages/vite/src/node/utils.ts#L956\n * vite not export this function\n */\nasync function resolveServerUrls(\n server: Server,\n options: IResolveServerUrlsOptions,\n): Promise<ResolvedServerUrls> {\n const address = server.address();\n\n const isAddressInfo = (x: AddressInfo | null | string): x is AddressInfo =>\n (typeof x === 'object' && Boolean(x?.address)) || false;\n\n if (!isAddressInfo(address)) {\n return { local: [], network: [] };\n }\n\n const { host, isHttps, rawBase } = options;\n\n const local: string[] = [];\n const network: string[] = [];\n const hostname = await resolveHostname(host);\n const protocol = isHttps ? 'https' : 'http';\n const { port } = address;\n const base = rawBase === './' || rawBase === '' || !rawBase ? '/' : rawBase;\n\n if (hostname.host !== undefined && !wildcardHosts.has(hostname.host)) {\n let hostnameName = hostname.name;\n\n // ipv6 host\n if (hostnameName.includes(':')) {\n hostnameName = `[${hostnameName}]`;\n }\n\n const addressUrl = `${protocol}://${hostnameName}:${port}${base}`;\n\n if (loopbackHosts.has(hostname.host)) {\n local.push(addressUrl);\n } else {\n network.push(addressUrl);\n }\n } else {\n Object.values(os.networkInterfaces())\n .flatMap((nInterface) => nInterface ?? [])\n .filter(\n (detail) =>\n detail &&\n detail.address &&\n (detail.family === 'IPv4' ||\n // @ts-expect-error Node 18.0 - 18.3 returns number\n detail.family === 4),\n )\n .forEach((detail) => {\n let resultHost = detail.address.replace('127.0.0.1', hostname.name);\n\n // ipv6 host\n if (resultHost.includes(':')) {\n resultHost = `[${resultHost}]`;\n }\n\n const url = `${protocol}://${resultHost}:${port}${base}`;\n\n if (detail.address.includes('127.0.0.1')) {\n local.push(url);\n } else {\n network.push(url);\n }\n });\n }\n\n return { local, network };\n}\n\nexport default resolveServerUrls;\n"],"names":["loopbackHosts","Set","wildcardHosts","async","resolveHostname","optionsHost","host","undefined","name","has","localhostAddr","nodeResult","dnsResult","Promise","all","dns","lookup","verbatim","family","address","getLocalhostAddressIfDiffersFromDNS","resolveServerUrls","server","options","x","Boolean","local","network","isHttps","rawBase","hostname","protocol","port","base","Object","values","os","networkInterfaces","flatMap","nInterface","filter","detail","forEach","resultHost","replace","includes","url","push","hostnameName","addressUrl"],"mappings":"2DAUA,MAAMA,EAAgB,IAAIC,IAAI,CAC5B,YACA,YACA,MACA,4CAGIC,EAAgB,IAAID,IAAI,CAAC,UAAW,KAAM,4CAoBhDE,eAAeC,EAAgBC,GAC7B,IAAIC,EAIFA,OAFkBC,IAAhBF,IAA6C,IAAhBA,EAExB,aACkB,IAAhBA,OAEFE,EAEAF,EAIT,IAAIG,OAAgBD,IAATD,GAAsBJ,EAAcO,IAAIH,GAAQ,YAAcA,EAEzE,GAAa,cAATA,EAAsB,CAExB,MAAMI,QAjCVP,iBACE,MAAOQ,EAAYC,SAAmBC,QAAQC,IAAI,CAChDC,EAAIC,OAAO,aACXD,EAAIC,OAAO,YAAa,CAAEC,UAAU,MAItC,OAFeN,EAAWO,SAAWN,EAAUM,QAAUP,EAAWQ,UAAYP,EAAUO,aAE1EZ,EAAYI,EAAWQ,OACzC,CAyBgCC,GAExBV,IACFF,EAAOE,EAEV,CAED,MAAO,CAAEJ,OAAME,OACjB,CAaAL,eAAekB,EACbC,EACAC,GAEA,MAAMJ,EAAUG,EAAOH,UAKvB,GAFgB,iBADOK,EAGJL,KAFSM,QAAQD,GAAGL,SAGrC,MAAO,CAAEO,MAAO,GAAIC,QAAS,IAJT,IAACH,EAOvB,MAAMlB,KAAEA,EAAIsB,QAAEA,EAAOC,QAAEA,GAAYN,EAE7BG,EAAkB,GAClBC,EAAoB,GACpBG,QAAiB1B,EAAgBE,GACjCyB,EAAWH,EAAU,QAAU,QAC/BI,KAAEA,GAASb,EACXc,EAAmB,OAAZJ,GAAgC,KAAZA,GAAmBA,EAAgBA,EAAN,IAE9D,QAAsBtB,IAAlBuB,EAASxB,MAAuBJ,EAAcO,IAAIqB,EAASxB,MAgB7D4B,OAAOC,OAAOC,EAAGC,qBACdC,SAASC,GAAeA,GAAc,KACtCC,QACEC,GACCA,GACAA,EAAOtB,UACY,SAAlBsB,EAAOvB,QAEY,IAAlBuB,EAAOvB,UAEZwB,SAASD,IACR,IAAIE,EAAaF,EAAOtB,QAAQyB,QAAQ,YAAad,EAAStB,MAG1DmC,EAAWE,SAAS,OACtBF,EAAa,IAAIA,MAGnB,MAAMG,EAAM,GAAGf,OAAcY,KAAcX,IAAOC,IAE9CQ,EAAOtB,QAAQ0B,SAAS,aAC1BnB,EAAMqB,KAAKD,GAEXnB,EAAQoB,KAAKD,EACd,QAxC+D,CACpE,IAAIE,EAAelB,EAAStB,KAGxBwC,EAAaH,SAAS,OACxBG,EAAe,IAAIA,MAGrB,MAAMC,EAAa,GAAGlB,OAAciB,KAAgBhB,IAAOC,IAEvDjC,EAAcS,IAAIqB,EAASxB,MAC7BoB,EAAMqB,KAAKE,GAEXtB,EAAQoB,KAAKE,EAEhB,CA6BD,MAAO,CAAEvB,QAAOC,UAClB"}
1
+ {"version":3,"file":"resolve-server-urls.js","sources":["../../src/helpers/resolve-server-urls.ts"],"sourcesContent":["import { promises as dns } from 'node:dns';\nimport type { AddressInfo, Server } from 'node:net';\nimport os from 'node:os';\nimport type { ResolvedServerUrls } from 'vite';\n\ninterface IHostname {\n host: string | undefined;\n name: string;\n}\n\nconst loopbackHosts = new Set([\n 'localhost',\n '127.0.0.1',\n '::1',\n '0000:0000:0000:0000:0000:0000:0000:0001',\n]);\n\nconst wildcardHosts = new Set(['0.0.0.0', '::', '0000:0000:0000:0000:0000:0000:0000:0000']);\n\n/**\n * @see https://github.com/vitejs/vite/blob/main/packages/vite/src/node/utils.ts#LL819C8-L830C2\n */\nasync function getLocalhostAddressIfDiffersFromDNS(): Promise<string | undefined> {\n const [nodeResult, dnsResult] = await Promise.all([\n dns.lookup('localhost'),\n dns.lookup('localhost', { verbatim: true }),\n ]);\n const isSame = nodeResult.family === dnsResult.family && nodeResult.address === dnsResult.address;\n\n return isSame ? undefined : nodeResult.address;\n}\n\n/**\n * Resolve hostname\n * @see https://github.com/vitejs/vite/blob/main/packages/vite/src/node/utils.ts#LL852C1-L878C2\n * vite not export this function\n */\nasync function resolveHostname(optionsHost: string | boolean | undefined): Promise<IHostname> {\n let host: string | undefined;\n\n if (optionsHost === undefined || optionsHost === false) {\n // Use a secure default\n host = 'localhost';\n } else if (optionsHost === true) {\n // If passed --host in the CLI without arguments\n host = undefined; // undefined typically means 0.0.0.0 or :: (listen on all IPs)\n } else {\n host = optionsHost;\n }\n\n // Set host name to localhost when possible\n let name = host === undefined || wildcardHosts.has(host) ? 'localhost' : host;\n\n if (host === 'localhost') {\n // See #8647 for more details.\n const localhostAddr = await getLocalhostAddressIfDiffersFromDNS();\n\n if (localhostAddr) {\n name = localhostAddr;\n }\n }\n\n return { host, name };\n}\n\ninterface IResolveServerUrlsOptions {\n host: string;\n isHttps?: boolean;\n rawBase?: string;\n}\n\n/**\n * Resolve server urls\n * @see https://github.com/vitejs/vite/blob/main/packages/vite/src/node/utils.ts#L956\n * vite not export this function\n */\nasync function resolveServerUrls(\n server: Server,\n options: IResolveServerUrlsOptions,\n): Promise<ResolvedServerUrls> {\n const address = server.address();\n\n const isAddressInfo = (x: AddressInfo | null | string): x is AddressInfo =>\n (typeof x === 'object' && Boolean(x?.address)) || false;\n\n if (!isAddressInfo(address)) {\n return { local: [], network: [] };\n }\n\n const { host, isHttps, rawBase } = options;\n\n const local: string[] = [];\n const network: string[] = [];\n const hostname = await resolveHostname(host);\n const protocol = isHttps ? 'https' : 'http';\n const { port } = address;\n const base = rawBase === './' || rawBase === '' || !rawBase ? '/' : rawBase;\n\n if (hostname.host !== undefined && !wildcardHosts.has(hostname.host)) {\n let hostnameName = hostname.name;\n\n // ipv6 host\n if (hostnameName.includes(':')) {\n hostnameName = `[${hostnameName}]`;\n }\n\n const addressUrl = `${protocol}://${hostnameName}:${port}${base}`;\n\n if (loopbackHosts.has(hostname.host)) {\n local.push(addressUrl);\n } else {\n network.push(addressUrl);\n }\n } else {\n Object.values(os.networkInterfaces())\n .flatMap((nInterface) => nInterface ?? [])\n .filter(\n (detail) =>\n detail &&\n detail.address &&\n (detail.family === 'IPv4' ||\n // @ts-expect-error Node 18.0 - 18.3 returns number\n detail.family === 4),\n )\n .forEach((detail) => {\n let resultHost = detail.address.replace('127.0.0.1', hostname.name);\n\n // ipv6 host\n if (resultHost.includes(':')) {\n resultHost = `[${resultHost}]`;\n }\n\n const url = `${protocol}://${resultHost}:${port}${base}`;\n\n if (detail.address.includes('127.0.0.1')) {\n local.push(url);\n } else {\n network.push(url);\n }\n });\n }\n\n return { local, network };\n}\n\nexport default resolveServerUrls;\n"],"names":["loopbackHosts","Set","wildcardHosts","async","resolveHostname","optionsHost","host","undefined","name","has","localhostAddr","nodeResult","dnsResult","Promise","all","dns","lookup","verbatim","family","address","getLocalhostAddressIfDiffersFromDNS","resolveServerUrls","server","options","x","Boolean","local","network","isHttps","rawBase","hostname","protocol","port","base","Object","values","os","networkInterfaces","flatMap","nInterface","filter","detail","forEach","resultHost","replace","includes","url","push","hostnameName","addressUrl"],"mappings":"2DAUA,MAAMA,EAAgB,IAAIC,IAAI,CAC5B,YACA,YACA,MACA,4CAGIC,EAAgB,IAAID,IAAI,CAAC,UAAW,KAAM,4CAoBhDE,eAAeC,EAAgBC,GAC7B,IAAIC,EAIFA,OAFkBC,IAAhBF,IAA6C,IAAhBA,EAExB,aACkB,IAAhBA,OAEFE,EAEAF,EAIT,IAAIG,OAAgBD,IAATD,GAAsBJ,EAAcO,IAAIH,GAAQ,YAAcA,EAEzE,GAAa,cAATA,EAAsB,CAExB,MAAMI,QAjCVP,iBACE,MAAOQ,EAAYC,SAAmBC,QAAQC,IAAI,CAChDC,EAAIC,OAAO,aACXD,EAAIC,OAAO,YAAa,CAAEC,UAAU,MAItC,OAFeN,EAAWO,SAAWN,EAAUM,QAAUP,EAAWQ,UAAYP,EAAUO,aAE1EZ,EAAYI,EAAWQ,OACzC,CAyBgCC,GAExBV,IACFF,EAAOE,GAIX,MAAO,CAAEJ,OAAME,OACjB,CAaAL,eAAekB,EACbC,EACAC,GAEA,MAAMJ,EAAUG,EAAOH,UAKvB,GAFgB,iBADOK,EAGJL,KAFSM,QAAQD,GAAGL,SAGrC,MAAO,CAAEO,MAAO,GAAIC,QAAS,IAJT,IAACH,EAOvB,MAAMlB,KAAEA,EAAIsB,QAAEA,EAAOC,QAAEA,GAAYN,EAE7BG,EAAkB,GAClBC,EAAoB,GACpBG,QAAiB1B,EAAgBE,GACjCyB,EAAWH,EAAU,QAAU,QAC/BI,KAAEA,GAASb,EACXc,EAAmB,OAAZJ,GAAgC,KAAZA,GAAmBA,EAAgBA,EAAN,IAE9D,QAAsBtB,IAAlBuB,EAASxB,MAAuBJ,EAAcO,IAAIqB,EAASxB,MAgB7D4B,OAAOC,OAAOC,EAAGC,qBACdC,SAASC,GAAeA,GAAc,KACtCC,QACEC,GACCA,GACAA,EAAOtB,UACY,SAAlBsB,EAAOvB,QAEY,IAAlBuB,EAAOvB,UAEZwB,SAASD,IACR,IAAIE,EAAaF,EAAOtB,QAAQyB,QAAQ,YAAad,EAAStB,MAG1DmC,EAAWE,SAAS,OACtBF,EAAa,IAAIA,MAGnB,MAAMG,EAAM,GAAGf,OAAcY,KAAcX,IAAOC,IAE9CQ,EAAOtB,QAAQ0B,SAAS,aAC1BnB,EAAMqB,KAAKD,GAEXnB,EAAQoB,KAAKD,UAvCiD,CACpE,IAAIE,EAAelB,EAAStB,KAGxBwC,EAAaH,SAAS,OACxBG,EAAe,IAAIA,MAGrB,MAAMC,EAAa,GAAGlB,OAAciB,KAAgBhB,IAAOC,IAEvDjC,EAAcS,IAAIqB,EAASxB,MAC7BoB,EAAMqB,KAAKE,GAEXtB,EAAQoB,KAAKE,GA+BjB,MAAO,CAAEvB,QAAOC,UAClB"}
@@ -1 +1 @@
1
- {"version":3,"file":"serialize-errors.js","sources":["../../src/helpers/serialize-errors.ts"],"sourcesContent":["import { isRouteErrorResponse } from 'react-router';\nimport type { StaticHandlerContext } from 'react-router';\n\n/**\n * Serialize react router errors\n * @see https://github.com/remix-run/react-router/blob/main/packages/react-router-dom/server.tsx#LL166C1-L188C2\n * https://github.com/remix-run/react-router/blob/main/LICENSE.md\n */\nfunction serializeErrors(errors: StaticHandlerContext['errors']): StaticHandlerContext['errors'] {\n if (!errors) {\n return null;\n }\n\n const entries = Object.entries(errors);\n const serialized: StaticHandlerContext['errors'] = {};\n for (const [key, val] of entries) {\n // Hey you! If you change this, please change the corresponding logic in\n // deserializeErrors in react-router-dom/index.tsx :)\n if (isRouteErrorResponse(val)) {\n serialized[key] = { ...val, __type: 'RouteErrorResponse' };\n } else if (val instanceof Error) {\n // Do not serialize stack traces from SSR for security reasons\n serialized[key] = {\n message: val.message,\n __type: 'Error',\n };\n } else {\n serialized[key] = val as unknown;\n }\n }\n\n return serialized;\n}\n\nexport default serializeErrors;\n"],"names":["serializeErrors","errors","entries","Object","serialized","key","val","isRouteErrorResponse","__type","Error","message"],"mappings":"oDAQA,SAASA,EAAgBC,GACvB,IAAKA,EACH,OAAO,KAGT,MAAMC,EAAUC,OAAOD,QAAQD,GACzBG,EAA6C,CAAA,EACnD,IAAK,MAAOC,EAAKC,KAAQJ,EAGnBK,EAAqBD,GACvBF,EAAWC,GAAO,IAAKC,EAAKE,OAAQ,sBAC3BF,aAAeG,MAExBL,EAAWC,GAAO,CAChBK,QAASJ,EAAII,QACbF,OAAQ,SAGVJ,EAAWC,GAAOC,EAItB,OAAOF,CACT"}
1
+ {"version":3,"file":"serialize-errors.js","sources":["../../src/helpers/serialize-errors.ts"],"sourcesContent":["import { isRouteErrorResponse } from 'react-router';\nimport type { StaticHandlerContext } from 'react-router';\n\n/**\n * Serialize react router errors\n * @see https://github.com/remix-run/react-router/blob/main/packages/react-router-dom/server.tsx#LL166C1-L188C2\n * https://github.com/remix-run/react-router/blob/main/LICENSE.md\n */\nfunction serializeErrors(errors: StaticHandlerContext['errors']): StaticHandlerContext['errors'] {\n if (!errors) {\n return null;\n }\n\n const entries = Object.entries(errors);\n const serialized: StaticHandlerContext['errors'] = {};\n for (const [key, val] of entries) {\n // Hey you! If you change this, please change the corresponding logic in\n // deserializeErrors in react-router-dom/index.tsx :)\n if (isRouteErrorResponse(val)) {\n serialized[key] = { ...val, __type: 'RouteErrorResponse' };\n } else if (val instanceof Error) {\n // Do not serialize stack traces from SSR for security reasons\n serialized[key] = {\n message: val.message,\n __type: 'Error',\n };\n } else {\n serialized[key] = val as unknown;\n }\n }\n\n return serialized;\n}\n\nexport default serializeErrors;\n"],"names":["serializeErrors","errors","entries","Object","serialized","key","val","isRouteErrorResponse","__type","Error","message"],"mappings":"oDAQA,SAASA,EAAgBC,GACvB,IAAKA,EACH,OAAO,KAGT,MAAMC,EAAUC,OAAOD,QAAQD,GACzBG,EAA6C,CAAE,EACrD,IAAK,MAAOC,EAAKC,KAAQJ,EAGnBK,EAAqBD,GACvBF,EAAWC,GAAO,IAAKC,EAAKE,OAAQ,sBAC3BF,aAAeG,MAExBL,EAAWC,GAAO,CAChBK,QAASJ,EAAII,QACbF,OAAQ,SAGVJ,EAAWC,GAAOC,EAItB,OAAOF,CACT"}
@@ -1 +1 @@
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"}
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,WACxD,MAAOI,IAIT,MAAO,CAAE,CAAA,EAMLC,EAAcd,IAClB,IACEK,EAAGU,WAAWhB,EAAgBC,IAC9B,MAAOa"}
@@ -1 +1 @@
1
- {"version":3,"file":"render.js","sources":["../../src/node/render.tsx"],"sourcesContent":["import chalk from 'chalk';\nimport type { Request, Response as ExpressResponse } from 'express';\nimport React from 'react';\nimport { renderToPipeableStream } from 'react-dom/server';\nimport type { StaticHandlerContext, StaticHandler } from 'react-router';\nimport { createStaticRouter, StaticRouterProvider } from 'react-router';\nimport StreamError from '@constants/stream-error';\nimport type { IServerContext } from '@context/server';\nimport { ServerProvider } from '@context/server';\nimport handleResponse from '@helpers/handle-response';\nimport type { IObtainStreamErrorOut } from '@helpers/obtain-stream-error';\nimport obtainStreamError from '@helpers/obtain-stream-error';\nimport createFetchRequest from '@node/create-fetch-request';\nimport type { TApp } from '@node/entry';\nimport writeResponse from '@node/write-response';\nimport type ServerConfig from '@services/server-config';\nimport SsrManifest from '@services/ssr-manifest';\n\nexport interface IRequestContext<TAppProps = Record<any, any>> {\n req: Request;\n res: ExpressResponse;\n appProps: NonNullable<TAppProps>;\n html: { header: string; footer: string };\n routerContext?: StaticHandlerContext;\n serverContext?: IServerContext;\n isStream?: boolean;\n hasEarlyHints?: boolean;\n didError?: StreamError;\n}\n\nexport type TRender<TAppProps = Record<any, any>> = (\n config: ServerConfig,\n context: IRequestContext<TAppProps>,\n options: IRenderOptions,\n) => Promise<void>;\n\nexport interface IRenderParams<TAppProps = Record<string, any>> {\n App: TApp<TAppProps>;\n handler: StaticHandler;\n}\n\nexport interface IRenderOptions<TAppProps = Record<string, any>> {\n abortDelay?: number;\n onRouterReady?: (params: {\n context: IRequestContext<TAppProps>;\n }) => Promise<IRouterReadyOut> | IRouterReadyOut;\n onShellReady?: (params: { context: IRequestContext<TAppProps> }) => IShellReadyOut;\n onShellError?: (params: {\n context: IRequestContext<TAppProps>;\n error: Error;\n }) => string | undefined | void; // return html or undefined\n onError?: (params: { context: IRequestContext<TAppProps>; error: IObtainStreamErrorOut }) => void;\n onResponse?: (params: {\n context: IRequestContext<TAppProps>;\n html: string;\n }) => string | undefined | void;\n getState?: (params: {\n context: IRequestContext<TAppProps>;\n }) => Record<string, Record<string, any>> | undefined | void;\n}\n\nexport interface IRouterReadyOut {\n isStream?: boolean;\n}\n\nexport interface IShellReadyOut {\n header?: string;\n footer?: string;\n}\n\n/**\n * Render application\n */\nasync function render(\n { App, handler }: IRenderParams, // @see entry (bind)\n config: ServerConfig,\n context: IRequestContext,\n {\n onRouterReady,\n onShellReady,\n onResponse,\n onShellError,\n onError,\n getState,\n abortDelay = 15000,\n }: IRenderOptions,\n): Promise<void> {\n const { req, res } = context;\n const fetchRequest = createFetchRequest(req);\n\n context.routerContext = (await handler.query(fetchRequest, {\n requestContext: context,\n })) as StaticHandlerContext;\n\n /**\n * Handle response from page loader, router context can be Response\n */\n const statusCode = handleResponse(res, context.routerContext);\n\n if (!statusCode) {\n return;\n }\n\n SsrManifest.get(config).injectAssets(context);\n\n const { isStream = true } = (await onRouterReady?.({ context })) ?? {};\n\n context.isStream = isStream;\n context.serverContext = {\n response: null,\n isServer: true,\n basename: context.routerContext?.basename,\n };\n\n const router = createStaticRouter(handler.dataRoutes, context.routerContext);\n const write = res.write.bind(res) as ExpressResponse['write'];\n const Logger = config.getLogger();\n let abortTimer: NodeJS.Timer | undefined = undefined;\n\n /**\n * Listen response and stream to add possibility modify html on fly\n * E.g. listen stream and append some data\n */\n res.write = (data: string | Uint8Array, ...args): boolean => {\n const isString = typeof data === 'string';\n const html = isString ? data : Buffer.from(data).toString();\n const modifiedHtml = onResponse?.({ context, html });\n\n if (modifiedHtml) {\n // @ts-ignore\n return write(isString ? modifiedHtml : Buffer.from(modifiedHtml), ...args) as boolean;\n }\n\n // @ts-ignore\n return write(data, ...args) as boolean;\n };\n\n const { serverContext, routerContext, appProps } = context;\n\n const { pipe, abort } = renderToPipeableStream(\n <ServerProvider context={serverContext}>\n <App server={{ ...appProps, req }}>\n <StaticRouterProvider router={router} context={routerContext} hydrate={false} />\n </App>\n </ServerProvider>,\n {\n onShellReady(): void {\n if (!isStream) {\n return;\n }\n\n writeResponse(context, {\n pipe,\n statusCode,\n onShellReady,\n getState,\n });\n },\n onAllReady(): void {\n clearTimeout(abortTimer);\n\n if (isStream) {\n return;\n }\n\n writeResponse(context, {\n pipe,\n statusCode,\n onShellReady,\n getState,\n });\n },\n onShellError(e: Error): void {\n const htmlError =\n onShellError?.({ context, error: e }) ||\n `<!doctype html><p>Something went wrong: ${e.message}</p>`;\n\n res.status(500);\n res.setHeader('content-type', 'text/html');\n res.send(htmlError);\n },\n onError(err): void {\n clearTimeout(abortTimer);\n\n const error = obtainStreamError(err);\n const { code, message } = error;\n const { didError } = context;\n\n context.didError = didError ?? code;\n\n onError?.({ context, error });\n Logger.info(chalk.red(`Stream error. Code: ${code}`));\n\n if (\n [StreamError.RenderAborted, StreamError.RenderTimeout, StreamError.RenderCancel].includes(\n code,\n )\n ) {\n Logger.info(chalk.dim(message));\n\n return;\n }\n\n Logger.error(err as string);\n },\n },\n );\n\n // Abandon and switch to client rendering if enough time passes.\n abortTimer = setTimeout(() => {\n context.didError = StreamError.RenderTimeout;\n abort();\n }, abortDelay);\n\n // Detect cancel request\n req.on('close', () => {\n context.didError = StreamError.RenderCancel;\n abort();\n });\n}\n\nexport default render;\n"],"names":["async","render","App","handler","config","context","onRouterReady","onShellReady","onResponse","onShellError","onError","getState","abortDelay","req","res","fetchRequest","createFetchRequest","routerContext","query","requestContext","statusCode","handleResponse","SsrManifest","get","injectAssets","isStream","serverContext","response","isServer","basename","router","createStaticRouter","dataRoutes","write","bind","Logger","getLogger","abortTimer","data","args","isString","html","Buffer","from","toString","modifiedHtml","appProps","pipe","abort","renderToPipeableStream","React","createElement","ServerProvider","server","StaticRouterProvider","hydrate","writeResponse","onAllReady","clearTimeout","e","htmlError","error","message","status","setHeader","send","err","obtainStreamError","code","didError","info","chalk","red","StreamError","RenderAborted","RenderTimeout","RenderCancel","includes","dim","setTimeout","on"],"mappings":"ueAyEAA,eAAeC,GACbC,IAAEA,EAAGC,QAAEA,GACPC,EACAC,GACAC,cACEA,EAAaC,aACbA,EAAYC,WACZA,EAAUC,aACVA,EAAYC,QACZA,EAAOC,SACPA,EAAQC,WACRA,EAAa,OAGf,MAAMC,IAAEA,EAAGC,IAAEA,GAAQT,EACfU,EAAeC,EAAmBH,GAExCR,EAAQY,oBAAuBd,EAAQe,MAAMH,EAAc,CACzDI,eAAgBd,IAMlB,MAAMe,EAAaC,EAAeP,EAAKT,EAAQY,eAE/C,IAAKG,EACH,OAGFE,EAAYC,IAAInB,GAAQoB,aAAanB,GAErC,MAAMoB,SAAEA,GAAW,SAAgBnB,IAAgB,CAAED,cAAe,GAEpEA,EAAQoB,SAAWA,EACnBpB,EAAQqB,cAAgB,CACtBC,SAAU,KACVC,UAAU,EACVC,SAAUxB,EAAQY,eAAeY,UAGnC,MAAMC,EAASC,EAAmB5B,EAAQ6B,WAAY3B,EAAQY,eACxDgB,EAAQnB,EAAImB,MAAMC,KAAKpB,GACvBqB,EAAS/B,EAAOgC,YACtB,IAAIC,EAMJvB,EAAImB,MAAQ,CAACK,KAA8BC,KACzC,MAAMC,EAA2B,iBAATF,EAClBG,EAAOD,EAAWF,EAAOI,OAAOC,KAAKL,GAAMM,WAC3CC,EAAerC,IAAa,CAAEH,UAASoC,SAE7C,OAAII,EAEKZ,EAAMO,EAAWK,EAAeH,OAAOC,KAAKE,MAAkBN,GAIhEN,EAAMK,KAASC,EAAgB,EAGxC,MAAMb,cAAEA,EAAaT,cAAEA,EAAa6B,SAAEA,GAAazC,GAE7C0C,KAAEA,EAAIC,MAAEA,GAAUC,EACtBC,EAACC,cAAAC,EAAe,CAAA/C,QAASqB,GACvBwB,EAACC,cAAAjD,GAAImD,OAAQ,IAAKP,EAAUjC,QAC1BqC,EAAAC,cAACG,EAAqB,CAAAxB,OAAQA,EAAQzB,QAASY,EAAesC,SAAS,MAG3E,CACEhD,eACOkB,GAIL+B,EAAcnD,EAAS,CACrB0C,OACA3B,aACAb,eACAI,YAEH,EACD8C,aACEC,aAAarB,GAETZ,GAIJ+B,EAAcnD,EAAS,CACrB0C,OACA3B,aACAb,eACAI,YAEH,EACDF,aAAakD,GACX,MAAMC,EACJnD,IAAe,CAAEJ,UAASwD,MAAOF,KACjC,2CAA2CA,EAAEG,cAE/ChD,EAAIiD,OAAO,KACXjD,EAAIkD,UAAU,eAAgB,aAC9BlD,EAAImD,KAAKL,EACV,EACDlD,QAAQwD,GACNR,aAAarB,GAEb,MAAMwB,EAAQM,EAAkBD,IAC1BE,KAAEA,EAAIN,QAAEA,GAAYD,GACpBQ,SAAEA,GAAahE,EAErBA,EAAQgE,SAAWA,GAAYD,EAE/B1D,IAAU,CAAEL,UAASwD,UACrB1B,EAAOmC,KAAKC,EAAMC,IAAI,uBAAuBJ,MAG3C,CAACK,EAAYC,cAAeD,EAAYE,cAAeF,EAAYG,cAAcC,SAC/ET,GAGFjC,EAAOmC,KAAKC,EAAMO,IAAIhB,IAKxB3B,EAAO0B,MAAMK,EACd,IAKL7B,EAAa0C,YAAW,KACtB1E,EAAQgE,SAAWI,EAAYE,cAC/B3B,GAAO,GACNpC,GAGHC,EAAImE,GAAG,SAAS,KACd3E,EAAQgE,SAAWI,EAAYG,aAC/B5B,GAAO,GAEX"}
1
+ {"version":3,"file":"render.js","sources":["../../src/node/render.tsx"],"sourcesContent":["import chalk from 'chalk';\nimport type { Request, Response as ExpressResponse } from 'express';\nimport React from 'react';\nimport { renderToPipeableStream } from 'react-dom/server';\nimport type { StaticHandlerContext, StaticHandler } from 'react-router';\nimport { createStaticRouter, StaticRouterProvider } from 'react-router';\nimport StreamError from '@constants/stream-error';\nimport type { IServerContext } from '@context/server';\nimport { ServerProvider } from '@context/server';\nimport handleResponse from '@helpers/handle-response';\nimport type { IObtainStreamErrorOut } from '@helpers/obtain-stream-error';\nimport obtainStreamError from '@helpers/obtain-stream-error';\nimport createFetchRequest from '@node/create-fetch-request';\nimport type { TApp } from '@node/entry';\nimport writeResponse from '@node/write-response';\nimport type ServerConfig from '@services/server-config';\nimport SsrManifest from '@services/ssr-manifest';\n\nexport interface IRequestContext<TAppProps = Record<any, any>> {\n req: Request;\n res: ExpressResponse;\n appProps: NonNullable<TAppProps>;\n html: { header: string; footer: string };\n routerContext?: StaticHandlerContext;\n serverContext?: IServerContext;\n isStream?: boolean;\n hasEarlyHints?: boolean;\n didError?: StreamError;\n}\n\nexport type TRender<TAppProps = Record<any, any>> = (\n config: ServerConfig,\n context: IRequestContext<TAppProps>,\n options: IRenderOptions,\n) => Promise<void>;\n\nexport interface IRenderParams<TAppProps = Record<string, any>> {\n App: TApp<TAppProps>;\n handler: StaticHandler;\n}\n\nexport interface IRenderOptions<TAppProps = Record<string, any>> {\n abortDelay?: number;\n onRouterReady?: (params: {\n context: IRequestContext<TAppProps>;\n }) => Promise<IRouterReadyOut> | IRouterReadyOut;\n onShellReady?: (params: { context: IRequestContext<TAppProps> }) => IShellReadyOut;\n onShellError?: (params: {\n context: IRequestContext<TAppProps>;\n error: Error;\n }) => string | undefined | void; // return html or undefined\n onError?: (params: { context: IRequestContext<TAppProps>; error: IObtainStreamErrorOut }) => void;\n onResponse?: (params: {\n context: IRequestContext<TAppProps>;\n html: string;\n }) => string | undefined | void;\n getState?: (params: {\n context: IRequestContext<TAppProps>;\n }) => Record<string, Record<string, any>> | undefined | void;\n}\n\nexport interface IRouterReadyOut {\n isStream?: boolean;\n}\n\nexport interface IShellReadyOut {\n header?: string;\n footer?: string;\n}\n\n/**\n * Render application\n */\nasync function render(\n { App, handler }: IRenderParams, // @see entry (bind)\n config: ServerConfig,\n context: IRequestContext,\n {\n onRouterReady,\n onShellReady,\n onResponse,\n onShellError,\n onError,\n getState,\n abortDelay = 15000,\n }: IRenderOptions,\n): Promise<void> {\n const { req, res } = context;\n const fetchRequest = createFetchRequest(req);\n\n context.routerContext = (await handler.query(fetchRequest, {\n requestContext: context,\n })) as StaticHandlerContext;\n\n /**\n * Handle response from page loader, router context can be Response\n */\n const statusCode = handleResponse(res, context.routerContext);\n\n if (!statusCode) {\n return;\n }\n\n SsrManifest.get(config).injectAssets(context);\n\n const { isStream = true } = (await onRouterReady?.({ context })) ?? {};\n\n context.isStream = isStream;\n context.serverContext = {\n response: null,\n isServer: true,\n basename: context.routerContext?.basename,\n };\n\n const router = createStaticRouter(handler.dataRoutes, context.routerContext);\n const write = res.write.bind(res) as ExpressResponse['write'];\n const Logger = config.getLogger();\n let abortTimer: NodeJS.Timer | undefined = undefined;\n\n /**\n * Listen response and stream to add possibility modify html on fly\n * E.g. listen stream and append some data\n */\n res.write = (data: string | Uint8Array, ...args): boolean => {\n const isString = typeof data === 'string';\n const html = isString ? data : Buffer.from(data).toString();\n const modifiedHtml = onResponse?.({ context, html });\n\n if (modifiedHtml) {\n // @ts-ignore\n return write(isString ? modifiedHtml : Buffer.from(modifiedHtml), ...args) as boolean;\n }\n\n // @ts-ignore\n return write(data, ...args) as boolean;\n };\n\n const { serverContext, routerContext, appProps } = context;\n\n const { pipe, abort } = renderToPipeableStream(\n <ServerProvider context={serverContext}>\n <App server={{ ...appProps, req }}>\n <StaticRouterProvider router={router} context={routerContext} hydrate={false} />\n </App>\n </ServerProvider>,\n {\n onShellReady(): void {\n if (!isStream) {\n return;\n }\n\n writeResponse(context, {\n pipe,\n statusCode,\n onShellReady,\n getState,\n });\n },\n onAllReady(): void {\n clearTimeout(abortTimer);\n\n if (isStream) {\n return;\n }\n\n writeResponse(context, {\n pipe,\n statusCode,\n onShellReady,\n getState,\n });\n },\n onShellError(e: Error): void {\n const htmlError =\n onShellError?.({ context, error: e }) ||\n `<!doctype html><p>Something went wrong: ${e.message}</p>`;\n\n res.status(500);\n res.setHeader('content-type', 'text/html');\n res.send(htmlError);\n },\n onError(err): void {\n clearTimeout(abortTimer);\n\n const error = obtainStreamError(err);\n const { code, message } = error;\n const { didError } = context;\n\n context.didError = didError ?? code;\n\n onError?.({ context, error });\n Logger.info(chalk.red(`Stream error. Code: ${code}`));\n\n if (\n [StreamError.RenderAborted, StreamError.RenderTimeout, StreamError.RenderCancel].includes(\n code,\n )\n ) {\n Logger.info(chalk.dim(message));\n\n return;\n }\n\n Logger.error(err as string);\n },\n },\n );\n\n // Abandon and switch to client rendering if enough time passes.\n abortTimer = setTimeout(() => {\n context.didError = StreamError.RenderTimeout;\n abort();\n }, abortDelay);\n\n // Detect cancel request\n req.on('close', () => {\n context.didError = StreamError.RenderCancel;\n abort();\n });\n}\n\nexport default render;\n"],"names":["async","render","App","handler","config","context","onRouterReady","onShellReady","onResponse","onShellError","onError","getState","abortDelay","req","res","fetchRequest","createFetchRequest","routerContext","query","requestContext","statusCode","handleResponse","SsrManifest","get","injectAssets","isStream","serverContext","response","isServer","basename","router","createStaticRouter","dataRoutes","write","bind","Logger","getLogger","abortTimer","data","args","isString","html","Buffer","from","toString","modifiedHtml","appProps","pipe","abort","renderToPipeableStream","React","createElement","ServerProvider","server","StaticRouterProvider","hydrate","writeResponse","onAllReady","clearTimeout","e","htmlError","error","message","status","setHeader","send","err","obtainStreamError","code","didError","info","chalk","red","StreamError","RenderAborted","RenderTimeout","RenderCancel","includes","dim","setTimeout","on"],"mappings":"ueAyEAA,eAAeC,GACbC,IAAEA,EAAGC,QAAEA,GACPC,EACAC,GACAC,cACEA,EAAaC,aACbA,EAAYC,WACZA,EAAUC,aACVA,EAAYC,QACZA,EAAOC,SACPA,EAAQC,WACRA,EAAa,OAGf,MAAMC,IAAEA,EAAGC,IAAEA,GAAQT,EACfU,EAAeC,EAAmBH,GAExCR,EAAQY,oBAAuBd,EAAQe,MAAMH,EAAc,CACzDI,eAAgBd,IAMlB,MAAMe,EAAaC,EAAeP,EAAKT,EAAQY,eAE/C,IAAKG,EACH,OAGFE,EAAYC,IAAInB,GAAQoB,aAAanB,GAErC,MAAMoB,SAAEA,GAAW,SAAgBnB,IAAgB,CAAED,cAAe,CAAE,EAEtEA,EAAQoB,SAAWA,EACnBpB,EAAQqB,cAAgB,CACtBC,SAAU,KACVC,UAAU,EACVC,SAAUxB,EAAQY,eAAeY,UAGnC,MAAMC,EAASC,EAAmB5B,EAAQ6B,WAAY3B,EAAQY,eACxDgB,EAAQnB,EAAImB,MAAMC,KAAKpB,GACvBqB,EAAS/B,EAAOgC,YACtB,IAAIC,EAMJvB,EAAImB,MAAQ,CAACK,KAA8BC,KACzC,MAAMC,EAA2B,iBAATF,EAClBG,EAAOD,EAAWF,EAAOI,OAAOC,KAAKL,GAAMM,WAC3CC,EAAerC,IAAa,CAAEH,UAASoC,SAE7C,OAAII,EAEKZ,EAAMO,EAAWK,EAAeH,OAAOC,KAAKE,MAAkBN,GAIhEN,EAAMK,KAASC,EAAgB,EAGxC,MAAMb,cAAEA,EAAaT,cAAEA,EAAa6B,SAAEA,GAAazC,GAE7C0C,KAAEA,EAAIC,MAAEA,GAAUC,EACtBC,EAACC,cAAAC,EAAe,CAAA/C,QAASqB,GACvBwB,EAACC,cAAAjD,GAAImD,OAAQ,IAAKP,EAAUjC,QAC1BqC,EAAAC,cAACG,EAAqB,CAAAxB,OAAQA,EAAQzB,QAASY,EAAesC,SAAS,MAG3E,CACEhD,eACOkB,GAIL+B,EAAcnD,EAAS,CACrB0C,OACA3B,aACAb,eACAI,YAEH,EACD8C,aACEC,aAAarB,GAETZ,GAIJ+B,EAAcnD,EAAS,CACrB0C,OACA3B,aACAb,eACAI,YAEH,EACDF,aAAakD,GACX,MAAMC,EACJnD,IAAe,CAAEJ,UAASwD,MAAOF,KACjC,2CAA2CA,EAAEG,cAE/ChD,EAAIiD,OAAO,KACXjD,EAAIkD,UAAU,eAAgB,aAC9BlD,EAAImD,KAAKL,EACV,EACDlD,QAAQwD,GACNR,aAAarB,GAEb,MAAMwB,EAAQM,EAAkBD,IAC1BE,KAAEA,EAAIN,QAAEA,GAAYD,GACpBQ,SAAEA,GAAahE,EAErBA,EAAQgE,SAAWA,GAAYD,EAE/B1D,IAAU,CAAEL,UAASwD,UACrB1B,EAAOmC,KAAKC,EAAMC,IAAI,uBAAuBJ,MAG3C,CAACK,EAAYC,cAAeD,EAAYE,cAAeF,EAAYG,cAAcC,SAC/ET,GAGFjC,EAAOmC,KAAKC,EAAMO,IAAIhB,IAKxB3B,EAAO0B,MAAMK,EACd,IAKL7B,EAAa0C,YAAW,KACtB1E,EAAQgE,SAAWI,EAAYE,cAC/B3B,GAAO,GACNpC,GAGHC,EAAImE,GAAG,SAAS,KACd3E,EAAQgE,SAAWI,EAAYG,aAC/B5B,GAAO,GAEX"}
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","sources":["../../src/node/server.ts"],"sourcesContent":["import http from 'node:http';\nimport https from 'node:https';\nimport type { Server } from 'node:net';\nimport path from 'path';\nimport compression from 'compression';\nimport type { Express } from 'express';\nimport express from 'express';\nimport printServerInfo from '@helpers/print-server-info';\nimport type { IRequestContext } from '@node/render';\nimport PrepareServer from '@services/prepare-server';\nimport ServerApi from '@services/server-api';\nimport type ServerConfig from '@services/server-config';\n\nexport interface ICreateServerOut {\n run: (options?: { version?: string; isPrintInfo?: boolean }) => Server;\n app: Express;\n}\n\n/**\n * Create SSR server\n */\nasync function createServer(config: ServerConfig): Promise<ICreateServerOut> {\n const app = express().disable('x-powered-by');\n const serverApi = new ServerApi();\n\n config.setApp(app);\n\n const prepareServer = PrepareServer.init(config, serverApi);\n\n if (!config.isProd) {\n // Create Vite server in middleware mode and configure the app type as\n // 'custom', disabling Vite's own HTML serving logic so parent server\n // can take control\n const vite = await (\n await import('vite')\n ).createServer({\n server: {\n middlewareMode: true,\n watch: {\n // During tests, we edit the files too fast and sometimes chokidar\n // misses change events, so enforce polling for consistency\n usePolling: true,\n interval: 100,\n },\n },\n appType: 'custom',\n mode: config.mode,\n });\n\n // Use vite's connect instance as middleware\n app.use(vite.middlewares);\n\n config.setVite(vite);\n }\n\n const { isSPA } = config.getParams();\n\n if (!isSPA) {\n await prepareServer.onAppCreated();\n }\n\n if (config.isProd) {\n const { root, publicDir } = config.getParams();\n const { compression: compressionConfig, expressStatic } = prepareServer.getMiddlewaresConfig();\n\n if (compressionConfig) {\n app.use(compression(compressionConfig));\n }\n\n if (!isSPA) {\n // ignore index.html file in SSR mode\n app.use((req, _, next) => {\n if (req.url === '/index.html' && !serverApi.hasAccessIndexHtml()) {\n req.url = '/index-not-found.html';\n }\n\n next();\n });\n }\n\n if (expressStatic) {\n const { basename, ...expressStaticOpts } = expressStatic;\n\n app.use(\n basename!,\n express.static(path.resolve(`${root}/${publicDir}`), {\n ...expressStaticOpts,\n index: isSPA ? undefined : false,\n }),\n );\n }\n }\n\n // SSR mode\n if (!isSPA) {\n app.use('*', (req, res, next) => {\n void (async () => {\n try {\n const [{ render, onRequest, ...renderParams }, clientHtml] = await Promise.all([\n prepareServer.loadEntrypoint(),\n prepareServer.loadHtml(req),\n ]);\n const { appProps, hasEarlyHints, shouldSkip } = (await onRequest?.(req, res)) ?? {};\n const [header, footer] = clientHtml;\n\n if (shouldSkip) {\n return next();\n }\n\n const context: IRequestContext = {\n req,\n res,\n hasEarlyHints,\n appProps: appProps ?? {},\n html: { header, footer },\n };\n\n await render(config, context, renderParams);\n } catch (e) {\n config\n .getLogger()\n .error(`Failed to handle request: ${(e as Error)?.message}`, { error: e as Error });\n next();\n }\n })();\n });\n } else {\n // SPA mode, redirect any request to index.html\n app.use('*', (req, res, next) => {\n void (async () => {\n try {\n const html = (await prepareServer.loadHtml(req)).join('');\n\n res.send(html);\n } catch (e) {\n config\n .getLogger()\n .error(`Failed to handle request: ${(e as Error)?.message}`, { error: e as Error });\n next();\n }\n })();\n });\n }\n\n return {\n run: ({ version, isPrintInfo = true } = {}): Server => {\n const { port, host } = config.getParams();\n const isHTTPS = Boolean(config.getVite()?.config?.server?.https);\n\n // update resolved host for print network link\n if (config.isHost && !config.isProd) {\n config.getVite()!.config.server.host = host;\n }\n\n const server = (\n isHTTPS\n ? https.createServer(config.getVite()!.config.server.https!, app)\n : http.createServer(app)\n ).listen(port, host, () => {\n void prepareServer.onServerStarted?.(app, serverApi, server);\n\n if (!isPrintInfo) {\n return;\n }\n\n void printServerInfo(config, { version, server });\n });\n\n return server;\n },\n app,\n };\n}\n\nexport default createServer;\n"],"names":["async","createServer","config","app","express","disable","serverApi","ServerApi","setApp","prepareServer","PrepareServer","init","isProd","vite","import","server","middlewareMode","watch","usePolling","interval","appType","mode","use","middlewares","setVite","isSPA","getParams","onAppCreated","root","publicDir","compression","compressionConfig","expressStatic","getMiddlewaresConfig","req","_","next","url","hasAccessIndexHtml","basename","expressStaticOpts","static","path","resolve","index","undefined","res","html","loadHtml","join","send","e","getLogger","error","message","render","onRequest","renderParams","clientHtml","Promise","all","loadEntrypoint","appProps","hasEarlyHints","shouldSkip","header","footer","context","run","version","isPrintInfo","port","host","isHTTPS","Boolean","getVite","https","isHost","http","listen","onServerStarted","printServerInfo"],"mappings":"8PAqBAA,eAAeC,EAAaC,GAC1B,MAAMC,EAAMC,IAAUC,QAAQ,gBACxBC,EAAY,IAAIC,EAEtBL,EAAOM,OAAOL,GAEd,MAAMM,EAAgBC,EAAcC,KAAKT,EAAQI,GAEjD,IAAKJ,EAAOU,OAAQ,CAIlB,MAAMC,cACEC,OAAO,SACbb,aAAa,CACbc,OAAQ,CACNC,gBAAgB,EAChBC,MAAO,CAGLC,YAAY,EACZC,SAAU,MAGdC,QAAS,SACTC,KAAMnB,EAAOmB,OAIflB,EAAImB,IAAIT,EAAKU,aAEbrB,EAAOsB,QAAQX,EAChB,CAED,MAAMY,MAAEA,GAAUvB,EAAOwB,YAMzB,GAJKD,SACGhB,EAAckB,eAGlBzB,EAAOU,OAAQ,CACjB,MAAMgB,KAAEA,EAAIC,UAAEA,GAAc3B,EAAOwB,aAC3BI,YAAaC,EAAiBC,cAAEA,GAAkBvB,EAAcwB,uBAiBxE,GAfIF,GACF5B,EAAImB,IAAIQ,EAAYC,IAGjBN,GAEHtB,EAAImB,KAAI,CAACY,EAAKC,EAAGC,KACC,gBAAZF,EAAIG,KAA0B/B,EAAUgC,uBAC1CJ,EAAIG,IAAM,yBAGZD,GAAM,IAINJ,EAAe,CACjB,MAAMO,SAAEA,KAAaC,GAAsBR,EAE3C7B,EAAImB,IACFiB,EACAnC,EAAQqC,OAAOC,EAAKC,QAAQ,GAAGf,KAAQC,KAAc,IAChDW,EACHI,QAAOnB,QAAQoB,IAGpB,CACF,CAqDD,OAlDKpB,EAkCHtB,EAAImB,IAAI,KAAK,CAACY,EAAKY,EAAKV,KACjB,WACH,IACE,MAAMW,SAActC,EAAcuC,SAASd,IAAMe,KAAK,IAEtDH,EAAII,KAAKH,EACV,CAAC,MAAOI,GACPjD,EACGkD,YACAC,MAAM,6BAA8BF,GAAaG,UAAW,CAAED,MAAOF,IACxEf,GACD,CACF,EAXI,EAWD,IA7CNjC,EAAImB,IAAI,KAAK,CAACY,EAAKY,EAAKV,KACjB,WACH,IACE,OAAOmB,OAAEA,EAAMC,UAAEA,KAAcC,GAAgBC,SAAoBC,QAAQC,IAAI,CAC7EnD,EAAcoD,iBACdpD,EAAcuC,SAASd,MAEnB4B,SAAEA,EAAQC,cAAEA,EAAaC,WAAEA,SAAsBR,IAAYtB,EAAKY,KAAS,IAC1EmB,EAAQC,GAAUR,EAEzB,GAAIM,EACF,OAAO5B,IAGT,MAAM+B,EAA2B,CAC/BjC,MACAY,MACAiB,gBACAD,SAAUA,GAAY,CAAE,EACxBf,KAAM,CAAEkB,SAAQC,iBAGZX,EAAOrD,EAAQiE,EAASV,EAC/B,CAAC,MAAON,GACPjD,EACGkD,YACAC,MAAM,6BAA8BF,GAAaG,UAAW,CAAED,MAAOF,IACxEf,GACD,CACF,EA5BI,EA4BD,IAoBD,CACLgC,IAAK,EAAGC,UAASC,eAAc,GAAS,CAAA,KACtC,MAAMC,KAAEA,EAAIC,KAAEA,GAAStE,EAAOwB,YACxB+C,EAAUC,QAAQxE,EAAOyE,WAAWzE,QAAQa,QAAQ6D,OAGtD1E,EAAO2E,SAAW3E,EAAOU,SAC3BV,EAAOyE,UAAWzE,OAAOa,OAAOyD,KAAOA,GAGzC,MAAMzD,GACJ0D,EACIG,EAAM3E,aAAaC,EAAOyE,UAAWzE,OAAOa,OAAO6D,MAAQzE,GAC3D2E,EAAK7E,aAAaE,IACtB4E,OAAOR,EAAMC,GAAM,KACd/D,EAAcuE,kBAAkB7E,EAAKG,EAAWS,GAEhDuD,GAIAW,EAAgB/E,EAAQ,CAAEmE,UAAStD,UAAS,IAGnD,OAAOA,CAAM,EAEfZ,MAEJ"}
1
+ {"version":3,"file":"server.js","sources":["../../src/node/server.ts"],"sourcesContent":["import http from 'node:http';\nimport https from 'node:https';\nimport type { Server } from 'node:net';\nimport path from 'path';\nimport compression from 'compression';\nimport type { Express } from 'express';\nimport express from 'express';\nimport printServerInfo from '@helpers/print-server-info';\nimport type { IRequestContext } from '@node/render';\nimport PrepareServer from '@services/prepare-server';\nimport ServerApi from '@services/server-api';\nimport type ServerConfig from '@services/server-config';\n\nexport interface ICreateServerOut {\n run: (options?: { version?: string; isPrintInfo?: boolean }) => Server;\n app: Express;\n}\n\n/**\n * Create SSR server\n */\nasync function createServer(config: ServerConfig): Promise<ICreateServerOut> {\n const app = express().disable('x-powered-by');\n const serverApi = new ServerApi();\n\n config.setApp(app);\n\n const prepareServer = PrepareServer.init(config, serverApi);\n\n if (!config.isProd) {\n // Create Vite server in middleware mode and configure the app type as\n // 'custom', disabling Vite's own HTML serving logic so parent server\n // can take control\n const vite = await (\n await import('vite')\n ).createServer({\n server: {\n middlewareMode: true,\n watch: {\n // During tests, we edit the files too fast and sometimes chokidar\n // misses change events, so enforce polling for consistency\n usePolling: true,\n interval: 100,\n },\n },\n appType: 'custom',\n mode: config.mode,\n });\n\n // Use vite's connect instance as middleware\n app.use(vite.middlewares);\n\n config.setVite(vite);\n }\n\n const { isSPA } = config.getParams();\n\n if (!isSPA) {\n await prepareServer.onAppCreated();\n }\n\n if (config.isProd) {\n const { root, publicDir } = config.getParams();\n const { compression: compressionConfig, expressStatic } = prepareServer.getMiddlewaresConfig();\n\n if (compressionConfig) {\n app.use(compression(compressionConfig));\n }\n\n if (!isSPA) {\n // ignore index.html file in SSR mode\n app.use((req, _, next) => {\n if (req.url === '/index.html' && !serverApi.hasAccessIndexHtml()) {\n req.url = '/index-not-found.html';\n }\n\n next();\n });\n }\n\n if (expressStatic) {\n const { basename, ...expressStaticOpts } = expressStatic;\n\n app.use(\n basename!,\n express.static(path.resolve(`${root}/${publicDir}`), {\n ...expressStaticOpts,\n index: isSPA ? undefined : false,\n }),\n );\n }\n }\n\n // SSR mode\n if (!isSPA) {\n app.use('*', (req, res, next) => {\n void (async () => {\n try {\n const [{ render, onRequest, ...renderParams }, clientHtml] = await Promise.all([\n prepareServer.loadEntrypoint(),\n prepareServer.loadHtml(req),\n ]);\n const { appProps, hasEarlyHints, shouldSkip } = (await onRequest?.(req, res)) ?? {};\n const [header, footer] = clientHtml;\n\n if (shouldSkip) {\n return next();\n }\n\n const context: IRequestContext = {\n req,\n res,\n hasEarlyHints,\n appProps: appProps ?? {},\n html: { header, footer },\n };\n\n await render(config, context, renderParams);\n } catch (e) {\n config\n .getLogger()\n .error(`Failed to handle request: ${(e as Error)?.message}`, { error: e as Error });\n next();\n }\n })();\n });\n } else {\n // SPA mode, redirect any request to index.html\n app.use('*', (req, res, next) => {\n void (async () => {\n try {\n const html = (await prepareServer.loadHtml(req)).join('');\n\n res.send(html);\n } catch (e) {\n config\n .getLogger()\n .error(`Failed to handle request: ${(e as Error)?.message}`, { error: e as Error });\n next();\n }\n })();\n });\n }\n\n return {\n run: ({ version, isPrintInfo = true } = {}): Server => {\n const { port, host } = config.getParams();\n const isHTTPS = Boolean(config.getVite()?.config?.server?.https);\n\n // update resolved host for print network link\n if (config.isHost && !config.isProd) {\n config.getVite()!.config.server.host = host;\n }\n\n const server = (\n isHTTPS\n ? https.createServer(config.getVite()!.config.server.https!, app)\n : http.createServer(app)\n ).listen(port, host, () => {\n void prepareServer.onServerStarted?.(app, serverApi, server);\n\n if (!isPrintInfo) {\n return;\n }\n\n void printServerInfo(config, { version, server });\n });\n\n return server;\n },\n app,\n };\n}\n\nexport default createServer;\n"],"names":["async","createServer","config","app","express","disable","serverApi","ServerApi","setApp","prepareServer","PrepareServer","init","isProd","vite","import","server","middlewareMode","watch","usePolling","interval","appType","mode","use","middlewares","setVite","isSPA","getParams","onAppCreated","root","publicDir","compression","compressionConfig","expressStatic","getMiddlewaresConfig","req","_","next","url","hasAccessIndexHtml","basename","expressStaticOpts","static","path","resolve","index","undefined","res","html","loadHtml","join","send","e","getLogger","error","message","render","onRequest","renderParams","clientHtml","Promise","all","loadEntrypoint","appProps","hasEarlyHints","shouldSkip","header","footer","context","run","version","isPrintInfo","port","host","isHTTPS","Boolean","getVite","https","isHost","http","listen","onServerStarted","printServerInfo"],"mappings":"8PAqBAA,eAAeC,EAAaC,GAC1B,MAAMC,EAAMC,IAAUC,QAAQ,gBACxBC,EAAY,IAAIC,EAEtBL,EAAOM,OAAOL,GAEd,MAAMM,EAAgBC,EAAcC,KAAKT,EAAQI,GAEjD,IAAKJ,EAAOU,OAAQ,CAIlB,MAAMC,cACEC,OAAO,SACbb,aAAa,CACbc,OAAQ,CACNC,gBAAgB,EAChBC,MAAO,CAGLC,YAAY,EACZC,SAAU,MAGdC,QAAS,SACTC,KAAMnB,EAAOmB,OAIflB,EAAImB,IAAIT,EAAKU,aAEbrB,EAAOsB,QAAQX,GAGjB,MAAMY,MAAEA,GAAUvB,EAAOwB,YAMzB,GAJKD,SACGhB,EAAckB,eAGlBzB,EAAOU,OAAQ,CACjB,MAAMgB,KAAEA,EAAIC,UAAEA,GAAc3B,EAAOwB,aAC3BI,YAAaC,EAAiBC,cAAEA,GAAkBvB,EAAcwB,uBAiBxE,GAfIF,GACF5B,EAAImB,IAAIQ,EAAYC,IAGjBN,GAEHtB,EAAImB,KAAI,CAACY,EAAKC,EAAGC,KACC,gBAAZF,EAAIG,KAA0B/B,EAAUgC,uBAC1CJ,EAAIG,IAAM,yBAGZD,GAAM,IAINJ,EAAe,CACjB,MAAMO,SAAEA,KAAaC,GAAsBR,EAE3C7B,EAAImB,IACFiB,EACAnC,EAAQqC,OAAOC,EAAKC,QAAQ,GAAGf,KAAQC,KAAc,IAChDW,EACHI,QAAOnB,QAAQoB,MAyDvB,OAlDKpB,EAkCHtB,EAAImB,IAAI,KAAK,CAACY,EAAKY,EAAKV,KACjB,WACH,IACE,MAAMW,SAActC,EAAcuC,SAASd,IAAMe,KAAK,IAEtDH,EAAII,KAAKH,GACT,MAAOI,GACPjD,EACGkD,YACAC,MAAM,6BAA8BF,GAAaG,UAAW,CAAED,MAAOF,IACxEf,IAEH,EAXI,EAWD,IA7CNjC,EAAImB,IAAI,KAAK,CAACY,EAAKY,EAAKV,KACjB,WACH,IACE,OAAOmB,OAAEA,EAAMC,UAAEA,KAAcC,GAAgBC,SAAoBC,QAAQC,IAAI,CAC7EnD,EAAcoD,iBACdpD,EAAcuC,SAASd,MAEnB4B,SAAEA,EAAQC,cAAEA,EAAaC,WAAEA,SAAsBR,IAAYtB,EAAKY,KAAS,CAAE,GAC5EmB,EAAQC,GAAUR,EAEzB,GAAIM,EACF,OAAO5B,IAGT,MAAM+B,EAA2B,CAC/BjC,MACAY,MACAiB,gBACAD,SAAUA,GAAY,CAAE,EACxBf,KAAM,CAAEkB,SAAQC,iBAGZX,EAAOrD,EAAQiE,EAASV,GAC9B,MAAON,GACPjD,EACGkD,YACAC,MAAM,6BAA8BF,GAAaG,UAAW,CAAED,MAAOF,IACxEf,IAEH,EA5BI,EA4BD,IAoBD,CACLgC,IAAK,EAAGC,UAASC,eAAc,GAAS,CAAA,KACtC,MAAMC,KAAEA,EAAIC,KAAEA,GAAStE,EAAOwB,YACxB+C,EAAUC,QAAQxE,EAAOyE,WAAWzE,QAAQa,QAAQ6D,OAGtD1E,EAAO2E,SAAW3E,EAAOU,SAC3BV,EAAOyE,UAAWzE,OAAOa,OAAOyD,KAAOA,GAGzC,MAAMzD,GACJ0D,EACIG,EAAM3E,aAAaC,EAAOyE,UAAWzE,OAAOa,OAAO6D,MAAQzE,GAC3D2E,EAAK7E,aAAaE,IACtB4E,OAAOR,EAAMC,GAAM,KACd/D,EAAcuE,kBAAkB7E,EAAKG,EAAWS,GAEhDuD,GAIAW,EAAgB/E,EAAQ,CAAEmE,UAAStD,UAAS,IAGnD,OAAOA,CAAM,EAEfZ,MAEJ"}
@@ -1 +1 @@
1
- {"version":3,"file":"write-response.js","sources":["../../src/node/write-response.ts"],"sourcesContent":["import type { Response as ExpressResponse } from 'express';\nimport type { PipeableStream } from 'react-dom/server';\nimport buildCustomState from '@helpers/build-custom-state';\nimport buildRouterState from '@helpers/build-router-state';\nimport handleResponse from '@helpers/handle-response';\nimport type { IRenderOptions, IRequestContext } from '@node/render';\n\ninterface IWriteResponseParams {\n pipe: PipeableStream['pipe'];\n onShellReady: IRenderOptions['onShellReady'];\n getState: IRenderOptions['getState'];\n statusCode?: number; // default status\n}\n\n/**\n * Send response to client\n */\nconst writeResponse = (context: IRequestContext, params: IWriteResponseParams): void => {\n const { res, didError, serverContext, routerContext, html } = context;\n const { pipe, onShellReady, getState } = params;\n let { statusCode } = params;\n\n // handle response from server components (navigate, status)\n statusCode = handleResponse(res, serverContext!.response, statusCode);\n\n if (!statusCode) {\n return;\n }\n\n // catch close connection from React and write footer\n if (didError) {\n const end = res.end.bind(res) as ExpressResponse['end'];\n\n res.end = (...args: unknown[]): ExpressResponse => {\n // send second part of app shell\n res.write(modifiedFooter || html.footer);\n\n // @ts-ignore\n return end(...args);\n };\n }\n\n res.status(statusCode);\n res.setHeader('content-type', 'text/html');\n\n const { header: modifiedHeader, footer: modifiedFooter } = onShellReady?.({ context }) ?? {};\n const routerState = buildRouterState(routerContext!);\n const customState = buildCustomState(getState?.({ context }));\n\n html.footer = routerState + customState + html.footer;\n\n // send first part of app shell\n res.write(modifiedHeader || html.header);\n // start streaming app\n pipe(res);\n\n if (!didError) {\n // send second part of app shell\n res.write(modifiedFooter || html.footer);\n }\n};\n\nexport default writeResponse;\n"],"names":["writeResponse","context","params","res","didError","serverContext","routerContext","html","pipe","onShellReady","getState","statusCode","handleResponse","response","end","bind","args","write","modifiedFooter","footer","status","setHeader","header","modifiedHeader","routerState","buildRouterState","customState","buildCustomState"],"mappings":"6IAiBA,MAAMA,EAAgB,CAACC,EAA0BC,KAC/C,MAAMC,IAAEA,EAAGC,SAAEA,EAAQC,cAAEA,EAAaC,cAAEA,EAAaC,KAAEA,GAASN,GACxDO,KAAEA,EAAIC,aAAEA,EAAYC,SAAEA,GAAaR,EACzC,IAAIS,WAAEA,GAAeT,EAKrB,GAFAS,EAAaC,EAAeT,EAAKE,EAAeQ,SAAUF,IAErDA,EACH,OAIF,GAAIP,EAAU,CACZ,MAAMU,EAAMX,EAAIW,IAAIC,KAAKZ,GAEzBA,EAAIW,IAAM,IAAIE,KAEZb,EAAIc,MAAMC,GAAkBX,EAAKY,QAG1BL,KAAOE,GAEjB,CAEDb,EAAIiB,OAAOT,GACXR,EAAIkB,UAAU,eAAgB,aAE9B,MAAQC,OAAQC,EAAgBJ,OAAQD,GAAmBT,IAAe,CAAER,aAAc,GACpFuB,EAAcC,EAAiBnB,GAC/BoB,EAAcC,EAAiBjB,IAAW,CAAET,aAElDM,EAAKY,OAASK,EAAcE,EAAcnB,EAAKY,OAG/ChB,EAAIc,MAAMM,GAAkBhB,EAAKe,QAEjCd,EAAKL,GAEAC,GAEHD,EAAIc,MAAMC,GAAkBX,EAAKY,OAClC"}
1
+ {"version":3,"file":"write-response.js","sources":["../../src/node/write-response.ts"],"sourcesContent":["import type { Response as ExpressResponse } from 'express';\nimport type { PipeableStream } from 'react-dom/server';\nimport buildCustomState from '@helpers/build-custom-state';\nimport buildRouterState from '@helpers/build-router-state';\nimport handleResponse from '@helpers/handle-response';\nimport type { IRenderOptions, IRequestContext } from '@node/render';\n\ninterface IWriteResponseParams {\n pipe: PipeableStream['pipe'];\n onShellReady: IRenderOptions['onShellReady'];\n getState: IRenderOptions['getState'];\n statusCode?: number; // default status\n}\n\n/**\n * Send response to client\n */\nconst writeResponse = (context: IRequestContext, params: IWriteResponseParams): void => {\n const { res, didError, serverContext, routerContext, html } = context;\n const { pipe, onShellReady, getState } = params;\n let { statusCode } = params;\n\n // handle response from server components (navigate, status)\n statusCode = handleResponse(res, serverContext!.response, statusCode);\n\n if (!statusCode) {\n return;\n }\n\n // catch close connection from React and write footer\n if (didError) {\n const end = res.end.bind(res) as ExpressResponse['end'];\n\n res.end = (...args: unknown[]): ExpressResponse => {\n // send second part of app shell\n res.write(modifiedFooter || html.footer);\n\n // @ts-ignore\n return end(...args);\n };\n }\n\n res.status(statusCode);\n res.setHeader('content-type', 'text/html');\n\n const { header: modifiedHeader, footer: modifiedFooter } = onShellReady?.({ context }) ?? {};\n const routerState = buildRouterState(routerContext!);\n const customState = buildCustomState(getState?.({ context }));\n\n html.footer = routerState + customState + html.footer;\n\n // send first part of app shell\n res.write(modifiedHeader || html.header);\n // start streaming app\n pipe(res);\n\n if (!didError) {\n // send second part of app shell\n res.write(modifiedFooter || html.footer);\n }\n};\n\nexport default writeResponse;\n"],"names":["writeResponse","context","params","res","didError","serverContext","routerContext","html","pipe","onShellReady","getState","statusCode","handleResponse","response","end","bind","args","write","modifiedFooter","footer","status","setHeader","header","modifiedHeader","routerState","buildRouterState","customState","buildCustomState"],"mappings":"6IAiBA,MAAMA,EAAgB,CAACC,EAA0BC,KAC/C,MAAMC,IAAEA,EAAGC,SAAEA,EAAQC,cAAEA,EAAaC,cAAEA,EAAaC,KAAEA,GAASN,GACxDO,KAAEA,EAAIC,aAAEA,EAAYC,SAAEA,GAAaR,EACzC,IAAIS,WAAEA,GAAeT,EAKrB,GAFAS,EAAaC,EAAeT,EAAKE,EAAeQ,SAAUF,IAErDA,EACH,OAIF,GAAIP,EAAU,CACZ,MAAMU,EAAMX,EAAIW,IAAIC,KAAKZ,GAEzBA,EAAIW,IAAM,IAAIE,KAEZb,EAAIc,MAAMC,GAAkBX,EAAKY,QAG1BL,KAAOE,IAIlBb,EAAIiB,OAAOT,GACXR,EAAIkB,UAAU,eAAgB,aAE9B,MAAQC,OAAQC,EAAgBJ,OAAQD,GAAmBT,IAAe,CAAER,aAAc,CAAE,EACtFuB,EAAcC,EAAiBnB,GAC/BoB,EAAcC,EAAiBjB,IAAW,CAAET,aAElDM,EAAKY,OAASK,EAAcE,EAAcnB,EAAKY,OAG/ChB,EAAIc,MAAMM,GAAkBhB,EAAKe,QAEjCd,EAAKL,GAEAC,GAEHD,EAAIc,MAAMC,GAAkBX,EAAKY"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lomray/vite-ssr-boost",
3
- "version": "4.0.0",
3
+ "version": "5.0.0",
4
4
  "description": "Vite plugin for create awesome SSR or SPA applications on React.",
5
5
  "type": "module",
6
6
  "keywords": [
@@ -33,47 +33,47 @@
33
33
  "test": "vitest run"
34
34
  },
35
35
  "dependencies": {
36
- "chalk": "^5.3.0",
36
+ "chalk": "^5.4.1",
37
37
  "commander": "^12.1.0",
38
38
  "compression": "^1.7.5",
39
- "express": "^4.21.1",
39
+ "express": "^4.21.2",
40
40
  "hoist-non-react-statics": "^3.3.2",
41
41
  "json5": "^2.2.3"
42
42
  },
43
43
  "devDependencies": {
44
- "@commitlint/cli": "^19.5.0",
45
- "@commitlint/config-conventional": "^19.5.0",
44
+ "@commitlint/cli": "^19.6.1",
45
+ "@commitlint/config-conventional": "^19.6.0",
46
46
  "@lomray/eslint-config-react": "^5.0.6",
47
47
  "@lomray/prettier-config": "^2.0.1",
48
48
  "@rollup/plugin-terser": "^0.4.4",
49
- "@testing-library/react": "^15.0.7",
49
+ "@testing-library/react": "^16.1.0",
50
50
  "@types/babel__generator": "^7.6.8",
51
51
  "@types/babel__traverse": "^7.20.6",
52
- "@types/chai": "^5.0.0",
52
+ "@types/chai": "^5.0.1",
53
53
  "@types/compression": "^1.7.5",
54
- "@types/hoist-non-react-statics": "^3.3.5",
54
+ "@types/hoist-non-react-statics": "^3.3.6",
55
55
  "@types/react-dom": "^18.3.0",
56
56
  "@types/sinon": "^17.0.3",
57
57
  "@types/sinon-chai": "^4.0.0",
58
- "@vitest/coverage-v8": "^2.1.6",
58
+ "@vitest/coverage-v8": "^2.1.8",
59
59
  "@zerollup/ts-transform-paths": "^1.7.18",
60
- "chai": "^5.1.1",
60
+ "chai": "^5.1.2",
61
61
  "eslint": "^8.57.0",
62
- "husky": "^9.1.6",
63
- "jsdom": "^24.0.0",
64
- "lint-staged": "^15.2.10",
65
- "prettier": "^3.3.3",
66
- "rollup": "^4.24.0",
62
+ "husky": "^9.1.7",
63
+ "jsdom": "^26.0.0",
64
+ "lint-staged": "^15.3.0",
65
+ "prettier": "^3.4.2",
66
+ "rollup": "^4.30.1",
67
67
  "rollup-plugin-copy": "^3.5.0",
68
68
  "rollup-plugin-folder-input": "^1.0.1",
69
69
  "rollup-plugin-peer-deps-external": "^2.2.4",
70
70
  "rollup-plugin-preserve-shebangs": "^0.2.0",
71
71
  "rollup-plugin-ts": "^3.4.5",
72
- "semantic-release": "^24.1.2",
72
+ "semantic-release": "^24.2.1",
73
73
  "sinon": "^19.0.2",
74
74
  "sinon-chai": "^4.0.0",
75
75
  "typescript": "^5.3.3",
76
- "vitest": "^2.1.6"
76
+ "vitest": "^2.1.8"
77
77
  },
78
78
  "peerDependencies": {
79
79
  "@babel/generator": ">=7.23.0",
@@ -1 +1 @@
1
- {"version":3,"file":"handle-custom-entrypoint.js","sources":["../../src/plugins/handle-custom-entrypoint.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport process from 'node:process';\nimport type { Plugin } from 'vite';\nimport PLUGIN_NAME from '@constants/plugin-name';\nimport type { IBuildEntrypoint } from '@services/build';\n\nexport interface IPluginOptions {\n entrypoint: IBuildEntrypoint;\n}\n\nconst pluginName = `${PLUGIN_NAME}-handle-custom-entrypoint`;\n\n/**\n * Get current entrypoint name\n */\nconst getCurrentEntrypointName = (): string | undefined =>\n process.env.SSR_BOOST_CUSTOM_ENTRYPOINT_BUILD_NAME;\n\n/**\n * Set current entrypoint name\n */\nconst setCurrentEntrypointName = (name: string): void => {\n process.env.SSR_BOOST_CUSTOM_ENTRYPOINT_BUILD_NAME = name;\n};\n\n/**\n * Find current entrypoint by env\n */\nconst getCurrentEntrypoint = (\n entrypoint: IBuildEntrypoint[],\n currentEntrypointName = getCurrentEntrypointName(),\n): IBuildEntrypoint | null => {\n if (!entrypoint.length || !currentEntrypointName) {\n return null;\n }\n\n for (const entry of entrypoint) {\n if (entry.name === currentEntrypointName && !entry.serverFile) {\n return entry;\n }\n }\n\n return null;\n};\n\n/**\n * Replace entrypoint in html file\n */\nconst replaceEntrypoint = (code: string, originalPath: string, endpointPath: string): string => {\n const cleanOrigPath = originalPath.replace('./', '/');\n const cleanEndpointPath = endpointPath.replace('./', '/');\n\n return code.replace(cleanOrigPath, cleanEndpointPath);\n};\n\n/**\n * Return custom entrypoint instead default (index.html).\n *\n * E.g. for build multiple entrypoint\n * @constructor\n */\nfunction ViteHandleCustomEntrypointPlugin(options: IPluginOptions): Plugin {\n const { entrypoint } = options;\n let outPath = '';\n let origClientFile = '';\n\n return {\n name: pluginName,\n enforce: 'pre',\n /**\n * Apply only on build but not for SSR and only for custom entrypoint\n */\n apply(_, { isSsrBuild }): boolean {\n return !isSsrBuild && Boolean(entrypoint);\n },\n config(config) {\n const { indexFile } = entrypoint;\n const buildConfig = config.build ?? {};\n const indexFilePath = indexFile ? path.resolve(config.root ?? '', indexFile) : undefined;\n\n return {\n ...config,\n build: {\n ...buildConfig,\n rollupOptions: {\n ...(buildConfig.rollupOptions ?? {}),\n input: indexFilePath,\n },\n },\n };\n },\n configResolved(config) {\n const pluginConfig = config.plugins.find((plugin) => plugin.name === PLUGIN_NAME);\n\n outPath = path.resolve(config.root, config.build.outDir);\n // @ts-expect-error pluginOptions is custom param\n origClientFile = (pluginConfig.pluginOptions as Record<string, any>).clientFile as string;\n },\n transform(code, id) {\n if (id.endsWith('.html')) {\n const { clientFile } = entrypoint;\n\n if (clientFile) {\n return {\n code: replaceEntrypoint(code, origClientFile, clientFile),\n map: this.getCombinedSourcemap(),\n };\n }\n }\n\n return {\n code,\n map: this.getCombinedSourcemap(),\n };\n },\n /**\n * Development mode\n */\n transformIndexHtml(html, { originalUrl, server }): string {\n const { clientFile } = entrypoint;\n\n if (clientFile && server?.config.command === 'serve' && originalUrl?.endsWith('.html')) {\n return replaceEntrypoint(html, origClientFile, clientFile);\n }\n\n return html;\n },\n closeBundle() {\n const { indexFile } = entrypoint;\n\n if (!indexFile) {\n return;\n }\n\n const indexFilePath = path.resolve(outPath, path.basename(indexFile));\n\n if (fs.existsSync(indexFilePath)) {\n fs.renameSync(indexFilePath, path.resolve(outPath, 'index.html'));\n }\n },\n };\n}\n\nexport {\n ViteHandleCustomEntrypointPlugin,\n getCurrentEntrypoint,\n getCurrentEntrypointName,\n setCurrentEntrypointName,\n};\n"],"names":["pluginName","PLUGIN_NAME","getCurrentEntrypointName","process","env","SSR_BOOST_CUSTOM_ENTRYPOINT_BUILD_NAME","setCurrentEntrypointName","name","getCurrentEntrypoint","entrypoint","currentEntrypointName","length","entry","serverFile","replaceEntrypoint","code","originalPath","endpointPath","cleanOrigPath","replace","cleanEndpointPath","ViteHandleCustomEntrypointPlugin","options","outPath","origClientFile","enforce","apply","_","isSsrBuild","Boolean","config","indexFile","buildConfig","build","indexFilePath","path","resolve","root","undefined","rollupOptions","input","configResolved","pluginConfig","plugins","find","plugin","outDir","pluginOptions","clientFile","transform","id","endsWith","map","this","getCombinedSourcemap","transformIndexHtml","html","originalUrl","server","command","closeBundle","basename","fs","existsSync","renameSync"],"mappings":"uHAWA,MAAMA,EAAa,GAAGC,6BAKhBC,EAA2B,IAC/BC,EAAQC,IAAIC,uCAKRC,EAA4BC,IAChCJ,EAAQC,IAAIC,uCAAyCE,CAAI,EAMrDC,EAAuB,CAC3BC,EACAC,EAAwBR,OAExB,IAAKO,EAAWE,SAAWD,EACzB,OAAO,KAGT,IAAK,MAAME,KAASH,EAClB,GAAIG,EAAML,OAASG,IAA0BE,EAAMC,WACjD,OAAOD,EAIX,OAAO,IAAI,EAMPE,EAAoB,CAACC,EAAcC,EAAsBC,KAC7D,MAAMC,EAAgBF,EAAaG,QAAQ,KAAM,KAC3CC,EAAoBH,EAAaE,QAAQ,KAAM,KAErD,OAAOJ,EAAKI,QAAQD,EAAeE,EAAkB,EASvD,SAASC,EAAiCC,GACxC,MAAMb,WAAEA,GAAea,EACvB,IAAIC,EAAU,GACVC,EAAiB,GAErB,MAAO,CACLjB,KAAMP,EACNyB,QAAS,MAITC,MAAK,CAACC,GAAGC,WAAEA,MACDA,GAAcC,QAAQpB,GAEhCqB,OAAOA,GACL,MAAMC,UAAEA,GAActB,EAChBuB,EAAcF,EAAOG,OAAS,GAC9BC,EAAgBH,EAAYI,EAAKC,QAAQN,EAAOO,MAAQ,GAAIN,QAAaO,EAE/E,MAAO,IACFR,EACHG,MAAO,IACFD,EACHO,cAAe,IACTP,EAAYO,eAAiB,GACjCC,MAAON,IAId,EACDO,eAAeX,GACb,MAAMY,EAAeZ,EAAOa,QAAQC,MAAMC,GAAWA,EAAOtC,OAASN,IAErEsB,EAAUY,EAAKC,QAAQN,EAAOO,KAAMP,EAAOG,MAAMa,QAEjDtB,EAAkBkB,EAAaK,cAAsCC,UACtE,EACDC,UAAUlC,EAAMmC,GACd,GAAIA,EAAGC,SAAS,SAAU,CACxB,MAAMH,WAAEA,GAAevC,EAEvB,GAAIuC,EACF,MAAO,CACLjC,KAAMD,EAAkBC,EAAMS,EAAgBwB,GAC9CI,IAAKC,KAAKC,uBAGf,CAED,MAAO,CACLvC,OACAqC,IAAKC,KAAKC,uBAEb,EAIDC,mBAAmBC,GAAMC,YAAEA,EAAWC,OAAEA,IACtC,MAAMV,WAAEA,GAAevC,EAEvB,OAAIuC,GAAyC,UAA3BU,GAAQ5B,OAAO6B,SAAuBF,GAAaN,SAAS,SACrErC,EAAkB0C,EAAMhC,EAAgBwB,GAG1CQ,CACR,EACDI,cACE,MAAM7B,UAAEA,GAActB,EAEtB,IAAKsB,EACH,OAGF,MAAMG,EAAgBC,EAAKC,QAAQb,EAASY,EAAK0B,SAAS9B,IAEtD+B,EAAGC,WAAW7B,IAChB4B,EAAGE,WAAW9B,EAAeC,EAAKC,QAAQb,EAAS,cAEtD,EAEL"}
1
+ {"version":3,"file":"handle-custom-entrypoint.js","sources":["../../src/plugins/handle-custom-entrypoint.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport process from 'node:process';\nimport type { Plugin } from 'vite';\nimport PLUGIN_NAME from '@constants/plugin-name';\nimport type { IBuildEntrypoint } from '@services/build';\n\nexport interface IPluginOptions {\n entrypoint: IBuildEntrypoint;\n}\n\nconst pluginName = `${PLUGIN_NAME}-handle-custom-entrypoint`;\n\n/**\n * Get current entrypoint name\n */\nconst getCurrentEntrypointName = (): string | undefined =>\n process.env.SSR_BOOST_CUSTOM_ENTRYPOINT_BUILD_NAME;\n\n/**\n * Set current entrypoint name\n */\nconst setCurrentEntrypointName = (name: string): void => {\n process.env.SSR_BOOST_CUSTOM_ENTRYPOINT_BUILD_NAME = name;\n};\n\n/**\n * Find current entrypoint by env\n */\nconst getCurrentEntrypoint = (\n entrypoint: IBuildEntrypoint[],\n currentEntrypointName = getCurrentEntrypointName(),\n): IBuildEntrypoint | null => {\n if (!entrypoint.length || !currentEntrypointName) {\n return null;\n }\n\n for (const entry of entrypoint) {\n if (entry.name === currentEntrypointName && !entry.serverFile) {\n return entry;\n }\n }\n\n return null;\n};\n\n/**\n * Replace entrypoint in html file\n */\nconst replaceEntrypoint = (code: string, originalPath: string, endpointPath: string): string => {\n const cleanOrigPath = originalPath.replace('./', '/');\n const cleanEndpointPath = endpointPath.replace('./', '/');\n\n return code.replace(cleanOrigPath, cleanEndpointPath);\n};\n\n/**\n * Return custom entrypoint instead default (index.html).\n *\n * E.g. for build multiple entrypoint\n * @constructor\n */\nfunction ViteHandleCustomEntrypointPlugin(options: IPluginOptions): Plugin {\n const { entrypoint } = options;\n let outPath = '';\n let origClientFile = '';\n\n return {\n name: pluginName,\n enforce: 'pre',\n /**\n * Apply only on build but not for SSR and only for custom entrypoint\n */\n apply(_, { isSsrBuild }): boolean {\n return !isSsrBuild && Boolean(entrypoint);\n },\n config(config) {\n const { indexFile } = entrypoint;\n const buildConfig = config.build ?? {};\n const indexFilePath = indexFile ? path.resolve(config.root ?? '', indexFile) : undefined;\n\n return {\n ...config,\n build: {\n ...buildConfig,\n rollupOptions: {\n ...(buildConfig.rollupOptions ?? {}),\n input: indexFilePath,\n },\n },\n };\n },\n configResolved(config) {\n const pluginConfig = config.plugins.find((plugin) => plugin.name === PLUGIN_NAME);\n\n outPath = path.resolve(config.root, config.build.outDir);\n // @ts-expect-error pluginOptions is custom param\n origClientFile = (pluginConfig.pluginOptions as Record<string, any>).clientFile as string;\n },\n transform(code, id) {\n if (id.endsWith('.html')) {\n const { clientFile } = entrypoint;\n\n if (clientFile) {\n return {\n code: replaceEntrypoint(code, origClientFile, clientFile),\n map: this.getCombinedSourcemap(),\n };\n }\n }\n\n return {\n code,\n map: this.getCombinedSourcemap(),\n };\n },\n /**\n * Development mode\n */\n transformIndexHtml(html, { originalUrl, server }): string {\n const { clientFile } = entrypoint;\n\n if (clientFile && server?.config.command === 'serve' && originalUrl?.endsWith('.html')) {\n return replaceEntrypoint(html, origClientFile, clientFile);\n }\n\n return html;\n },\n closeBundle() {\n const { indexFile } = entrypoint;\n\n if (!indexFile) {\n return;\n }\n\n const indexFilePath = path.resolve(outPath, path.basename(indexFile));\n\n if (fs.existsSync(indexFilePath)) {\n fs.renameSync(indexFilePath, path.resolve(outPath, 'index.html'));\n }\n },\n };\n}\n\nexport {\n ViteHandleCustomEntrypointPlugin,\n getCurrentEntrypoint,\n getCurrentEntrypointName,\n setCurrentEntrypointName,\n};\n"],"names":["pluginName","PLUGIN_NAME","getCurrentEntrypointName","process","env","SSR_BOOST_CUSTOM_ENTRYPOINT_BUILD_NAME","setCurrentEntrypointName","name","getCurrentEntrypoint","entrypoint","currentEntrypointName","length","entry","serverFile","replaceEntrypoint","code","originalPath","endpointPath","cleanOrigPath","replace","cleanEndpointPath","ViteHandleCustomEntrypointPlugin","options","outPath","origClientFile","enforce","apply","_","isSsrBuild","Boolean","config","indexFile","buildConfig","build","indexFilePath","path","resolve","root","undefined","rollupOptions","input","configResolved","pluginConfig","plugins","find","plugin","outDir","pluginOptions","clientFile","transform","id","endsWith","map","this","getCombinedSourcemap","transformIndexHtml","html","originalUrl","server","command","closeBundle","basename","fs","existsSync","renameSync"],"mappings":"uHAWA,MAAMA,EAAa,GAAGC,6BAKhBC,EAA2B,IAC/BC,EAAQC,IAAIC,uCAKRC,EAA4BC,IAChCJ,EAAQC,IAAIC,uCAAyCE,CAAI,EAMrDC,EAAuB,CAC3BC,EACAC,EAAwBR,OAExB,IAAKO,EAAWE,SAAWD,EACzB,OAAO,KAGT,IAAK,MAAME,KAASH,EAClB,GAAIG,EAAML,OAASG,IAA0BE,EAAMC,WACjD,OAAOD,EAIX,OAAO,IAAI,EAMPE,EAAoB,CAACC,EAAcC,EAAsBC,KAC7D,MAAMC,EAAgBF,EAAaG,QAAQ,KAAM,KAC3CC,EAAoBH,EAAaE,QAAQ,KAAM,KAErD,OAAOJ,EAAKI,QAAQD,EAAeE,EAAkB,EASvD,SAASC,EAAiCC,GACxC,MAAMb,WAAEA,GAAea,EACvB,IAAIC,EAAU,GACVC,EAAiB,GAErB,MAAO,CACLjB,KAAMP,EACNyB,QAAS,MAITC,MAAK,CAACC,GAAGC,WAAEA,MACDA,GAAcC,QAAQpB,GAEhCqB,OAAOA,GACL,MAAMC,UAAEA,GAActB,EAChBuB,EAAcF,EAAOG,OAAS,CAAE,EAChCC,EAAgBH,EAAYI,EAAKC,QAAQN,EAAOO,MAAQ,GAAIN,QAAaO,EAE/E,MAAO,IACFR,EACHG,MAAO,IACFD,EACHO,cAAe,IACTP,EAAYO,eAAiB,GACjCC,MAAON,IAId,EACDO,eAAeX,GACb,MAAMY,EAAeZ,EAAOa,QAAQC,MAAMC,GAAWA,EAAOtC,OAASN,IAErEsB,EAAUY,EAAKC,QAAQN,EAAOO,KAAMP,EAAOG,MAAMa,QAEjDtB,EAAkBkB,EAAaK,cAAsCC,UACtE,EACDC,UAAUlC,EAAMmC,GACd,GAAIA,EAAGC,SAAS,SAAU,CACxB,MAAMH,WAAEA,GAAevC,EAEvB,GAAIuC,EACF,MAAO,CACLjC,KAAMD,EAAkBC,EAAMS,EAAgBwB,GAC9CI,IAAKC,KAAKC,wBAKhB,MAAO,CACLvC,OACAqC,IAAKC,KAAKC,uBAEb,EAIDC,mBAAmBC,GAAMC,YAAEA,EAAWC,OAAEA,IACtC,MAAMV,WAAEA,GAAevC,EAEvB,OAAIuC,GAAyC,UAA3BU,GAAQ5B,OAAO6B,SAAuBF,GAAaN,SAAS,SACrErC,EAAkB0C,EAAMhC,EAAgBwB,GAG1CQ,CACR,EACDI,cACE,MAAM7B,UAAEA,GAActB,EAEtB,IAAKsB,EACH,OAGF,MAAMG,EAAgBC,EAAKC,QAAQb,EAASY,EAAK0B,SAAS9B,IAEtD+B,EAAGC,WAAW7B,IAChB4B,EAAGE,WAAW9B,EAAeC,EAAKC,QAAQb,EAAS,cAEtD,EAEL"}
@@ -1 +1 @@
1
- {"version":3,"file":"make-aliases.js","sources":["../../src/plugins/make-aliases.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport process from 'node:process';\nimport JSON5 from 'json5';\nimport type { Plugin } from 'vite';\n// import without aliases for use in vitest.config.ts\nimport PLUGIN_NAME from '../constants/plugin-name';\nimport ViteAliases from '../helpers/vite-aliases';\n\nexport interface IPluginOptions {\n root?: string; // default: cwd()\n tsconfig?: string; // default: tsconfig.json\n}\n\nconst pluginName = `${PLUGIN_NAME}-make-aliases`;\nconst cleanupAlias = (str: string): string => str.replace('/*', '');\n\n/**\n * Read tsconfig file and set vite aliases\n * @see PathNormalize.getAliases\n * @constructor\n */\nfunction ViteMakeAliasesPlugin(options: IPluginOptions = {}): Plugin {\n const { root, tsconfig } = options;\n const projectRoot = root ?? process.cwd();\n const tsconfigPath = path.resolve(projectRoot, tsconfig ?? 'tsconfig.json');\n const aliases: [string, string][] = [];\n\n if (!fs.existsSync(tsconfigPath)) {\n console.error(`${pluginName}: tsconfig not exist in \"${tsconfigPath}\"`);\n } else {\n const tsJson = JSON5.parse<{ compilerOptions?: { paths: Record<string, string[]> } }>(\n fs.readFileSync(tsconfigPath, { encoding: 'utf-8' }),\n );\n const paths = tsJson?.compilerOptions?.paths ?? {};\n\n Object.entries(paths).forEach(([alias, aliasPaths]) => {\n aliases.push([cleanupAlias(alias), cleanupAlias(aliasPaths[0])]);\n });\n }\n\n return {\n name: pluginName,\n config(config) {\n if (aliases.length) {\n const resolveConfig = config.resolve ?? {};\n const defaultAliases = resolveConfig.alias ?? [];\n const normalizedAliases = Array.isArray(defaultAliases)\n ? defaultAliases\n : Object.entries(defaultAliases).map(([find, val]) => ({\n find,\n replacement: val as string,\n }));\n\n normalizedAliases.push(...ViteAliases(aliases, `${projectRoot}/${config?.root ?? ''}`));\n\n config.resolve = {\n ...resolveConfig,\n alias: normalizedAliases,\n };\n }\n\n return config;\n },\n };\n}\n\nexport default ViteMakeAliasesPlugin;\n"],"names":["pluginName","PLUGIN_NAME","cleanupAlias","str","replace","ViteMakeAliasesPlugin","options","root","tsconfig","projectRoot","process","cwd","tsconfigPath","path","resolve","aliases","fs","existsSync","tsJson","JSON5","parse","readFileSync","encoding","paths","compilerOptions","Object","entries","forEach","alias","aliasPaths","push","console","error","name","config","length","resolveConfig","defaultAliases","normalizedAliases","Array","isArray","map","find","val","replacement","ViteAliases"],"mappings":"sLAcA,MAAMA,EAAa,GAAGC,iBAChBC,EAAgBC,GAAwBA,EAAIC,QAAQ,KAAM,IAOhE,SAASC,EAAsBC,EAA0B,IACvD,MAAMC,KAAEA,EAAIC,SAAEA,GAAaF,EACrBG,EAAcF,GAAQG,EAAQC,MAC9BC,EAAeC,EAAKC,QAAQL,EAAaD,GAAY,iBACrDO,EAA8B,GAEpC,GAAKC,EAAGC,WAAWL,GAEZ,CACL,MAAMM,EAASC,EAAMC,MACnBJ,EAAGK,aAAaT,EAAc,CAAEU,SAAU,WAEtCC,EAAQL,GAAQM,iBAAiBD,OAAS,CAAA,EAEhDE,OAAOC,QAAQH,GAAOI,SAAQ,EAAEC,EAAOC,MACrCd,EAAQe,KAAK,CAAC5B,EAAa0B,GAAQ1B,EAAa2B,EAAW,KAAK,GAEnE,MAVCE,QAAQC,MAAM,GAAGhC,6BAAsCY,MAYzD,MAAO,CACLqB,KAAMjC,EACNkC,OAAOA,GACL,GAAInB,EAAQoB,OAAQ,CAClB,MAAMC,EAAgBF,EAAOpB,SAAW,GAClCuB,EAAiBD,EAAcR,OAAS,GACxCU,EAAoBC,MAAMC,QAAQH,GACpCA,EACAZ,OAAOC,QAAQW,GAAgBI,KAAI,EAAEC,EAAMC,MAAU,CACnDD,OACAE,YAAaD,MAGnBL,EAAkBR,QAAQe,EAAY9B,EAAS,GAAGN,KAAeyB,GAAQ3B,MAAQ,OAEjF2B,EAAOpB,QAAU,IACZsB,EACHR,MAAOU,EAEV,CAED,OAAOJ,CACR,EAEL"}
1
+ {"version":3,"file":"make-aliases.js","sources":["../../src/plugins/make-aliases.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport process from 'node:process';\nimport JSON5 from 'json5';\nimport type { Plugin } from 'vite';\n// import without aliases for use in vitest.config.ts\nimport PLUGIN_NAME from '../constants/plugin-name';\nimport ViteAliases from '../helpers/vite-aliases';\n\nexport interface IPluginOptions {\n root?: string; // default: cwd()\n tsconfig?: string; // default: tsconfig.json\n}\n\nconst pluginName = `${PLUGIN_NAME}-make-aliases`;\nconst cleanupAlias = (str: string): string => str.replace('/*', '');\n\n/**\n * Read tsconfig file and set vite aliases\n * @see PathNormalize.getAliases\n * @constructor\n */\nfunction ViteMakeAliasesPlugin(options: IPluginOptions = {}): Plugin {\n const { root, tsconfig } = options;\n const projectRoot = root ?? process.cwd();\n const tsconfigPath = path.resolve(projectRoot, tsconfig ?? 'tsconfig.json');\n const aliases: [string, string][] = [];\n\n if (!fs.existsSync(tsconfigPath)) {\n console.error(`${pluginName}: tsconfig not exist in \"${tsconfigPath}\"`);\n } else {\n const tsJson = JSON5.parse<{ compilerOptions?: { paths: Record<string, string[]> } }>(\n fs.readFileSync(tsconfigPath, { encoding: 'utf-8' }),\n );\n const paths = tsJson?.compilerOptions?.paths ?? {};\n\n Object.entries(paths).forEach(([alias, aliasPaths]) => {\n aliases.push([cleanupAlias(alias), cleanupAlias(aliasPaths[0])]);\n });\n }\n\n return {\n name: pluginName,\n config(config) {\n if (aliases.length) {\n const resolveConfig = config.resolve ?? {};\n const defaultAliases = resolveConfig.alias ?? [];\n const normalizedAliases = Array.isArray(defaultAliases)\n ? defaultAliases\n : Object.entries(defaultAliases).map(([find, val]) => ({\n find,\n replacement: val as string,\n }));\n\n normalizedAliases.push(...ViteAliases(aliases, `${projectRoot}/${config?.root ?? ''}`));\n\n config.resolve = {\n ...resolveConfig,\n alias: normalizedAliases,\n };\n }\n\n return config;\n },\n };\n}\n\nexport default ViteMakeAliasesPlugin;\n"],"names":["pluginName","PLUGIN_NAME","cleanupAlias","str","replace","ViteMakeAliasesPlugin","options","root","tsconfig","projectRoot","process","cwd","tsconfigPath","path","resolve","aliases","fs","existsSync","tsJson","JSON5","parse","readFileSync","encoding","paths","compilerOptions","Object","entries","forEach","alias","aliasPaths","push","console","error","name","config","length","resolveConfig","defaultAliases","normalizedAliases","Array","isArray","map","find","val","replacement","ViteAliases"],"mappings":"sLAcA,MAAMA,EAAa,GAAGC,iBAChBC,EAAgBC,GAAwBA,EAAIC,QAAQ,KAAM,IAOhE,SAASC,EAAsBC,EAA0B,IACvD,MAAMC,KAAEA,EAAIC,SAAEA,GAAaF,EACrBG,EAAcF,GAAQG,EAAQC,MAC9BC,EAAeC,EAAKC,QAAQL,EAAaD,GAAY,iBACrDO,EAA8B,GAEpC,GAAKC,EAAGC,WAAWL,GAEZ,CACL,MAAMM,EAASC,EAAMC,MACnBJ,EAAGK,aAAaT,EAAc,CAAEU,SAAU,WAEtCC,EAAQL,GAAQM,iBAAiBD,OAAS,CAAE,EAElDE,OAAOC,QAAQH,GAAOI,SAAQ,EAAEC,EAAOC,MACrCd,EAAQe,KAAK,CAAC5B,EAAa0B,GAAQ1B,EAAa2B,EAAW,KAAK,SARlEE,QAAQC,MAAM,GAAGhC,6BAAsCY,MAYzD,MAAO,CACLqB,KAAMjC,EACNkC,OAAOA,GACL,GAAInB,EAAQoB,OAAQ,CAClB,MAAMC,EAAgBF,EAAOpB,SAAW,CAAE,EACpCuB,EAAiBD,EAAcR,OAAS,GACxCU,EAAoBC,MAAMC,QAAQH,GACpCA,EACAZ,OAAOC,QAAQW,GAAgBI,KAAI,EAAEC,EAAMC,MAAU,CACnDD,OACAE,YAAaD,MAGnBL,EAAkBR,QAAQe,EAAY9B,EAAS,GAAGN,KAAeyB,GAAQ3B,MAAQ,OAEjF2B,EAAOpB,QAAU,IACZsB,EACHR,MAAOU,GAIX,OAAOJ,CACR,EAEL"}
@@ -1 +1 @@
1
- {"version":3,"file":"normalize-route.js","sources":["../../src/plugins/normalize-route.ts"],"sourcesContent":["import { extname, resolve } from 'node:path';\nimport type { Plugin } from 'vite';\nimport PLUGIN_NAME from '@constants/plugin-name';\nimport isRoutesFile from '@helpers/is-route-file';\nimport { writeMeta } from '@helpers/ssr-meta';\nimport ParseRoutes from '@services/parse-routes';\n\nexport interface IPluginOptions {\n isSSR?: boolean;\n isBuild?: boolean;\n routesPath?: string;\n isNodeParsing?: boolean;\n}\n\n/**\n * Add pathId to route (where pathId - import string)\n * NOTE: only for dev mode\n */\nconst normalizeSyncRoutes = (code: string, isBuild = false): string => {\n if (isBuild) {\n return code;\n }\n\n return ParseRoutes.injectPathId(code);\n};\n\n/**\n * Add normalize wrapper to lazy imports for client build\n */\nconst normalizeAsyncRoutes = (code: string, hasPathId: boolean): string => {\n const modifiedCode = code.replace(\n /(lazy)(:\\s*)(\\(\\)\\s*=>\\s*import\\(([^)]+)\\))/gs,\n hasPathId ? 'lazy$2n($3,$4)' : 'lazy$2n($3)',\n );\n\n if (code !== modifiedCode) {\n return `import n from '${PLUGIN_NAME}/helpers/import-route';${modifiedCode}`;\n }\n\n return code;\n};\n\n/**\n * Add possibility to export route components like FCRoute or FCCRoute\n * Add route path for generating manifest\n * USAGE: { path: '/', lazy: () => import('./pages/home') }\n * @see FCRoute\n * @see FCCRoute\n * @see SsrManifest.getAsyncRoutesIds\n * @see importRoute\n * @constructor\n */\nfunction ViteNormalizeRouterPlugin(options: IPluginOptions = {}): Plugin {\n const { routesPath, isNodeParsing = false, isSSR = false, isBuild = false } = options;\n const routeFiles = new Map<string, string>();\n const cfg = { root: '', buildDir: '' };\n\n return {\n name: `${PLUGIN_NAME}-normalize-route`,\n enforce: 'pre',\n transform(code, id) {\n const [extName] = extname(id).split('?');\n const isRoutesPath = !routesPath || id.includes(routesPath);\n\n if (\n id.includes('node_modules') ||\n !['.js', '.mjs', '.ts', '.tsx'].includes(extName) ||\n !isRoutesPath ||\n !isRoutesFile(code)\n ) {\n return;\n }\n\n routeFiles.set(id, '');\n\n return {\n code: normalizeAsyncRoutes(\n // always add pathId to sync routes for development\n normalizeSyncRoutes(code, isBuild),\n // always add pathId to async routes for development or if it's node parsing mode\n isSSR && (isNodeParsing || !isBuild),\n ),\n map: { mappings: '' },\n };\n },\n ...(isNodeParsing\n ? {\n /**\n * Get build path\n */\n config(config, { isSsrBuild }): void {\n if (isSsrBuild) {\n return;\n }\n\n cfg.root = config.root!;\n cfg.buildDir = config.build!.outDir!;\n },\n /**\n * Get transformed route files\n */\n generateBundle(_, bundle) {\n for (const [fileName, chunk] of Object.entries(bundle)) {\n if (chunk.type === 'chunk') {\n Object.entries(chunk.modules).forEach(([modulePath]) => {\n if (routeFiles.has(modulePath)) {\n routeFiles.set(modulePath, fileName);\n }\n });\n }\n }\n },\n /**\n * Save metadata on for client build\n * @see config hook\n */\n writeBundle(): void {\n if (!cfg.root) {\n return;\n }\n\n const [buildDir] = resolve(cfg.root, cfg.buildDir).split('/client');\n\n writeMeta(buildDir, { routeFiles: Object.fromEntries(routeFiles) });\n },\n }\n : {}),\n };\n}\n\nexport default ViteNormalizeRouterPlugin;\n"],"names":["normalizeSyncRoutes","code","isBuild","ParseRoutes","injectPathId","normalizeAsyncRoutes","hasPathId","modifiedCode","replace","PLUGIN_NAME","ViteNormalizeRouterPlugin","options","routesPath","isNodeParsing","isSSR","routeFiles","Map","cfg","root","buildDir","name","enforce","transform","id","extName","extname","split","isRoutesPath","includes","isRoutesFile","set","map","mappings","config","isSsrBuild","build","outDir","generateBundle","_","bundle","fileName","chunk","Object","entries","type","modules","forEach","modulePath","has","writeBundle","resolve","writeMeta","fromEntries"],"mappings":"qOAkBA,MAAMA,EAAsB,CAACC,EAAcC,GAAU,IAC/CA,EACKD,EAGFE,EAAYC,aAAaH,GAM5BI,EAAuB,CAACJ,EAAcK,KAC1C,MAAMC,EAAeN,EAAKO,QACxB,gDACAF,EAAY,iBAAmB,eAGjC,OAAIL,IAASM,EACJ,kBAAkBE,2BAAqCF,IAGzDN,CAAI,EAab,SAASS,EAA0BC,EAA0B,IAC3D,MAAMC,WAAEA,EAAUC,cAAEA,GAAgB,EAAKC,MAAEA,GAAQ,EAAKZ,QAAEA,GAAU,GAAUS,EACxEI,EAAa,IAAIC,IACjBC,EAAM,CAAEC,KAAM,GAAIC,SAAU,IAElC,MAAO,CACLC,KAAM,GAAGX,oBACTY,QAAS,MACTC,UAAUrB,EAAMsB,GACd,MAAOC,GAAWC,EAAQF,GAAIG,MAAM,KAC9BC,GAAgBf,GAAcW,EAAGK,SAAShB,GAEhD,IACEW,EAAGK,SAAS,iBACX,CAAC,MAAO,OAAQ,MAAO,QAAQA,SAASJ,IACxCG,GACAE,EAAa5B,GAOhB,OAFAc,EAAWe,IAAIP,EAAI,IAEZ,CACLtB,KAAMI,EAEJL,EAAoBC,EAAMC,GAE1BY,IAAUD,IAAkBX,IAE9B6B,IAAK,CAAEC,SAAU,IAEpB,KACGnB,EACA,CAIEoB,OAAOA,GAAQC,WAAEA,IACXA,IAIJjB,EAAIC,KAAOe,EAAOf,KAClBD,EAAIE,SAAWc,EAAOE,MAAOC,OAC9B,EAIDC,eAAeC,EAAGC,GAChB,IAAK,MAAOC,EAAUC,KAAUC,OAAOC,QAAQJ,GAC1B,UAAfE,EAAMG,MACRF,OAAOC,QAAQF,EAAMI,SAASC,SAAQ,EAAEC,MAClChC,EAAWiC,IAAID,IACjBhC,EAAWe,IAAIiB,EAAYP,EAC5B,GAIR,EAKDS,cACE,IAAKhC,EAAIC,KACP,OAGF,MAAOC,GAAY+B,EAAQjC,EAAIC,KAAMD,EAAIE,UAAUO,MAAM,WAEzDyB,EAAUhC,EAAU,CAAEJ,WAAY2B,OAAOU,YAAYrC,IACtD,GAEH,GAER"}
1
+ {"version":3,"file":"normalize-route.js","sources":["../../src/plugins/normalize-route.ts"],"sourcesContent":["import { extname, resolve } from 'node:path';\nimport type { Plugin } from 'vite';\nimport PLUGIN_NAME from '@constants/plugin-name';\nimport isRoutesFile from '@helpers/is-route-file';\nimport { writeMeta } from '@helpers/ssr-meta';\nimport ParseRoutes from '@services/parse-routes';\n\nexport interface IPluginOptions {\n isSSR?: boolean;\n isBuild?: boolean;\n routesPath?: string;\n isNodeParsing?: boolean;\n}\n\n/**\n * Add pathId to route (where pathId - import string)\n * NOTE: only for dev mode\n */\nconst normalizeSyncRoutes = (code: string, isBuild = false): string => {\n if (isBuild) {\n return code;\n }\n\n return ParseRoutes.injectPathId(code);\n};\n\n/**\n * Add normalize wrapper to lazy imports for client build\n */\nconst normalizeAsyncRoutes = (code: string, hasPathId: boolean): string => {\n const modifiedCode = code.replace(\n /(lazy)(:\\s*)(\\(\\)\\s*=>\\s*import\\(([^)]+)\\))/gs,\n hasPathId ? 'lazy$2n($3,$4)' : 'lazy$2n($3)',\n );\n\n if (code !== modifiedCode) {\n return `import n from '${PLUGIN_NAME}/helpers/import-route';${modifiedCode}`;\n }\n\n return code;\n};\n\n/**\n * Add possibility to export route components like FCRoute or FCCRoute\n * Add route path for generating manifest\n * USAGE: { path: '/', lazy: () => import('./pages/home') }\n * @see FCRoute\n * @see FCCRoute\n * @see SsrManifest.getAsyncRoutesIds\n * @see importRoute\n * @constructor\n */\nfunction ViteNormalizeRouterPlugin(options: IPluginOptions = {}): Plugin {\n const { routesPath, isNodeParsing = false, isSSR = false, isBuild = false } = options;\n const routeFiles = new Map<string, string>();\n const cfg = { root: '', buildDir: '' };\n\n return {\n name: `${PLUGIN_NAME}-normalize-route`,\n enforce: 'pre',\n transform(code, id) {\n const [extName] = extname(id).split('?');\n const isRoutesPath = !routesPath || id.includes(routesPath);\n\n if (\n id.includes('node_modules') ||\n !['.js', '.mjs', '.ts', '.tsx'].includes(extName) ||\n !isRoutesPath ||\n !isRoutesFile(code)\n ) {\n return;\n }\n\n routeFiles.set(id, '');\n\n return {\n code: normalizeAsyncRoutes(\n // always add pathId to sync routes for development\n normalizeSyncRoutes(code, isBuild),\n // always add pathId to async routes for development or if it's node parsing mode\n isSSR && (isNodeParsing || !isBuild),\n ),\n map: { mappings: '' },\n };\n },\n ...(isNodeParsing\n ? {\n /**\n * Get build path\n */\n config(config, { isSsrBuild }): void {\n if (isSsrBuild) {\n return;\n }\n\n cfg.root = config.root!;\n cfg.buildDir = config.build!.outDir!;\n },\n /**\n * Get transformed route files\n */\n generateBundle(_, bundle) {\n for (const [fileName, chunk] of Object.entries(bundle)) {\n if (chunk.type === 'chunk') {\n Object.entries(chunk.modules).forEach(([modulePath]) => {\n if (routeFiles.has(modulePath)) {\n routeFiles.set(modulePath, fileName);\n }\n });\n }\n }\n },\n /**\n * Save metadata on for client build\n * @see config hook\n */\n writeBundle(): void {\n if (!cfg.root) {\n return;\n }\n\n const [buildDir] = resolve(cfg.root, cfg.buildDir).split('/client');\n\n writeMeta(buildDir, { routeFiles: Object.fromEntries(routeFiles) });\n },\n }\n : {}),\n };\n}\n\nexport default ViteNormalizeRouterPlugin;\n"],"names":["normalizeSyncRoutes","code","isBuild","ParseRoutes","injectPathId","normalizeAsyncRoutes","hasPathId","modifiedCode","replace","PLUGIN_NAME","ViteNormalizeRouterPlugin","options","routesPath","isNodeParsing","isSSR","routeFiles","Map","cfg","root","buildDir","name","enforce","transform","id","extName","extname","split","isRoutesPath","includes","isRoutesFile","set","map","mappings","config","isSsrBuild","build","outDir","generateBundle","_","bundle","fileName","chunk","Object","entries","type","modules","forEach","modulePath","has","writeBundle","resolve","writeMeta","fromEntries"],"mappings":"qOAkBA,MAAMA,EAAsB,CAACC,EAAcC,GAAU,IAC/CA,EACKD,EAGFE,EAAYC,aAAaH,GAM5BI,EAAuB,CAACJ,EAAcK,KAC1C,MAAMC,EAAeN,EAAKO,QACxB,gDACAF,EAAY,iBAAmB,eAGjC,OAAIL,IAASM,EACJ,kBAAkBE,2BAAqCF,IAGzDN,CAAI,EAab,SAASS,EAA0BC,EAA0B,IAC3D,MAAMC,WAAEA,EAAUC,cAAEA,GAAgB,EAAKC,MAAEA,GAAQ,EAAKZ,QAAEA,GAAU,GAAUS,EACxEI,EAAa,IAAIC,IACjBC,EAAM,CAAEC,KAAM,GAAIC,SAAU,IAElC,MAAO,CACLC,KAAM,GAAGX,oBACTY,QAAS,MACTC,UAAUrB,EAAMsB,GACd,MAAOC,GAAWC,EAAQF,GAAIG,MAAM,KAC9BC,GAAgBf,GAAcW,EAAGK,SAAShB,GAEhD,IACEW,EAAGK,SAAS,iBACX,CAAC,MAAO,OAAQ,MAAO,QAAQA,SAASJ,IACxCG,GACAE,EAAa5B,GAOhB,OAFAc,EAAWe,IAAIP,EAAI,IAEZ,CACLtB,KAAMI,EAEJL,EAAoBC,EAAMC,GAE1BY,IAAUD,IAAkBX,IAE9B6B,IAAK,CAAEC,SAAU,IAEpB,KACGnB,EACA,CAIEoB,OAAOA,GAAQC,WAAEA,IACXA,IAIJjB,EAAIC,KAAOe,EAAOf,KAClBD,EAAIE,SAAWc,EAAOE,MAAOC,OAC9B,EAIDC,eAAeC,EAAGC,GAChB,IAAK,MAAOC,EAAUC,KAAUC,OAAOC,QAAQJ,GAC1B,UAAfE,EAAMG,MACRF,OAAOC,QAAQF,EAAMI,SAASC,SAAQ,EAAEC,MAClChC,EAAWiC,IAAID,IACjBhC,EAAWe,IAAIiB,EAAYP,KAKpC,EAKDS,cACE,IAAKhC,EAAIC,KACP,OAGF,MAAOC,GAAY+B,EAAQjC,EAAIC,KAAMD,EAAIE,UAAUO,MAAM,WAEzDyB,EAAUhC,EAAU,CAAEJ,WAAY2B,OAAOU,YAAYrC,IACtD,GAEH,GAER"}
@@ -1 +1 @@
1
- {"version":3,"file":"build.js","sources":["../../src/services/build.ts"],"sourcesContent":["import 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 viteResetCache from '@cli/helpers/vite-reset-cache';\nimport createFocusOnly from '@helpers/create-focus-only';\nimport { createDevMarker } from '@helpers/dev-marker';\nimport type { IPluginConfig } from '@helpers/plugin-config';\nimport getPluginConfig from '@helpers/plugin-config';\nimport processStop from '@helpers/process-stop';\nimport { readMeta, removeMeta } from '@helpers/ssr-meta';\nimport ServerConfig from '@services/server-config';\nimport SsrManifest from '@services/ssr-manifest';\n\nexport interface IBuildParams {\n mode: string;\n onFinish?: () => void;\n clientOptions?: string;\n serverOptions?: string;\n focusOnly?: 'all' | 'app' | 'client' | 'server' | 'entrypoint';\n isWatch?: boolean;\n isUnlockRobots?: boolean;\n isEject?: boolean;\n isServerless?: boolean;\n isNoWarnings?: boolean;\n}\n\ninterface IBuildProcess {\n promise: Promise<number | null | string>;\n command: childProcess.ChildProcess;\n}\n\ninterface ISpawnBuildParams {\n shouldWait?: boolean;\n focusOnly?: IBuildParams['focusOnly'];\n env?: Record<string, string>;\n}\n\nexport interface IBuildEntrypoint {\n // entrypoint name\n name: string;\n type: 'spa' | 'ssr';\n // custom index file, default: indexFile from plugin config\n indexFile?: string;\n // custom entry file for replace in indexFile, default: undefined (do nothing)\n clientFile?: string;\n // custom server file, indexFile and clientFile will be ignored\n serverFile?: string;\n // additional options for vite build command\n buildOptions?: string;\n}\n\n/**\n * Build service\n */\nclass Build {\n /**\n * Is production build\n */\n protected isProd: boolean;\n\n /**\n * Node environment\n */\n protected nodeEnv: string;\n\n /**\n * Build folder\n */\n protected buildDir: string;\n\n /**\n * Vite config\n */\n protected viteConfig: ResolvedConfig;\n\n /**\n * Plugin config\n */\n protected pluginConfig: IPluginConfig;\n\n /**\n * Build params\n */\n protected params: IBuildParams = {\n mode: '',\n clientOptions: '',\n serverOptions: '',\n focusOnly: 'app',\n isWatch: false,\n isUnlockRobots: false,\n isEject: false,\n isServerless: false,\n isNoWarnings: false,\n };\n\n /**\n * Abort controller for builds\n */\n protected abortController: AbortController | null = null;\n\n /**\n * Running builds\n */\n protected runningBuild: { name: string; buildProcess: IBuildProcess }[] = [];\n\n /**\n * Listener for preview has attached\n */\n protected hasPreviewModeExitListener = false;\n\n /**\n * @constructor\n */\n public constructor(params: IBuildParams) {\n this.params = { ...this.params, ...params };\n }\n\n /**\n * Make config\n */\n protected 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.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 * Return is prod indicator value\n */\n public getIsProd(): boolean {\n return this.isProd;\n }\n\n /**\n * Return node env value\n */\n public getNodeEnv(): string {\n return this.nodeEnv;\n }\n\n /**\n * Return build names\n */\n public getRunningBuildNames(): string[] {\n return this.runningBuild.map(({ name }) => name);\n }\n\n /**\n * Promisify spawn process\n */\n protected promisifyProcess(\n command: childProcess.ChildProcess,\n isRejectWarnings = false,\n ): IBuildProcess {\n const promise = new Promise<number | null | string>((resolve, reject): void => {\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 protected async buildManifest(): Promise<void> {\n console.info(chalk.blue(`Building routes manifest file: ${this.pluginConfig.routesParsing}`));\n\n const isNodeParsing = this.pluginConfig.routesParsing === 'node';\n const serverConfig = ServerConfig.init(\n { isProd: this.isProd, mode: this.params.mode },\n { root: this.viteConfig.root, clientFile: this.pluginConfig.clientFile },\n );\n\n await SsrManifest.get(serverConfig, {\n buildDir: this.viteConfig.build.outDir,\n viteAliases: this.viteConfig.resolve.alias,\n basename: this.viteConfig.base,\n }).buildRoutesManifest(isNodeParsing);\n\n if (isNodeParsing) {\n this.cleanupClientRoutes();\n }\n }\n\n /**\n * Remove pathId from client route files\n */\n private cleanupClientRoutes(): void {\n const { routeFiles } = readMeta(this.buildDir);\n const files = new Set(Object.values(routeFiles ?? []));\n\n if (!files.size) {\n return;\n }\n\n files.forEach((file) => {\n const filepath = `${this.buildDir}/client/${file}`;\n\n try {\n const result = fs\n .readFileSync(filepath, { encoding: 'utf-8' })\n .replace(/(lazy:.*?\\((.*?)\\)),\\s?\".*?\"\\)/g, '$1)');\n\n fs.writeFileSync(filepath, result);\n } catch (e) {\n console.log(`Failed cleanup client route ${filepath}:`, e);\n }\n });\n }\n\n /**\n * Change general directive Disallow to Allow in robots.txt.\n */\n protected 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 protected 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 /**\n * Create serverless entrypoint\n */\n protected createServerless(): void {\n const entrypoint = `${this.buildDir}/server/serverless.js`;\n const script =\n \"import runServerless from '@lomray/vite-ssr-boost/cli/run-serverless.js';\\n\\n\" +\n `export default await runServerless({ version: process.env.VERSION || \"1.0.0\" });\\n`;\n\n fs.writeFileSync(entrypoint, script, {\n encoding: 'utf-8',\n });\n }\n\n /**\n * Build specified entrypoint\n */\n protected async spawnBuild(\n name: string,\n buildOptions: string,\n params: ISpawnBuildParams = {},\n ): Promise<void> {\n const { mode, isNoWarnings } = this.params;\n const { focusOnly = this.params.focusOnly, shouldWait = false, env = {} } = params;\n const modeOpt = mode && !buildOptions.includes('--mode') ? `--mode ${mode}` : '';\n\n const buildProcess = this.promisifyProcess(\n childProcess.spawn(`vite build ${buildOptions} ${modeOpt} --emptyOutDir`, {\n signal: this.abortController!.signal,\n stdio: [process.stdin, 'pipe', 'pipe'],\n shell: true,\n env: {\n ...process.env,\n ...env,\n FORCE_COLOR: '2',\n SSR_BOOST_IS_SSR: createFocusOnly(focusOnly).isOnlyClient() ? '0' : '1',\n SSR_BOOST_ACTION: global.viteBoostAction,\n },\n }),\n isNoWarnings,\n );\n\n this.runningBuild.push({ name, buildProcess });\n\n if (!shouldWait) {\n return;\n }\n\n await this.waitLastBuild();\n }\n\n /**\n * Wait latest build and stop process in case error\n */\n protected async waitLastBuild(): Promise<void> {\n const latestProcess = this.runningBuild.at(-1);\n\n if (!latestProcess) {\n return;\n }\n\n const exitCode = await latestProcess.buildProcess.promise;\n\n processStop(exitCode, true);\n }\n\n /**\n * Run preview mode\n */\n protected runPreviewMode(): void {\n if (!this.hasPreviewModeExitListener) {\n process.on('exit', () => {\n this.abortController!.abort();\n });\n\n this.hasPreviewModeExitListener = true;\n }\n\n const { onFinish } = this.params;\n let buildCount = this.runningBuild.length;\n\n /**\n * Detect finished builds for process\n */\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 this.runningBuild.forEach(({ buildProcess }) => {\n buildProcess.command.stdout?.removeListener('data', listener);\n });\n createDevMarker(this.isProd, this.viteConfig);\n onFinish?.();\n }\n }\n };\n\n /**\n * Listen output for call onFinish\n */\n this.runningBuild.forEach(({ buildProcess }) => {\n buildProcess.command.stdout?.on('data', listener);\n });\n }\n\n /**\n * Run app build\n */\n public async build(): Promise<void> {\n await this.makeConfig();\n // this is required step - build with different env may cause problems\n await viteResetCache();\n this.clearBuildFolder();\n\n const {\n clientOptions,\n serverOptions,\n onFinish,\n isWatch,\n focusOnly,\n isEject,\n isServerless,\n isUnlockRobots,\n } = this.params;\n const { outDir } = this.viteConfig.build;\n const focus = createFocusOnly(focusOnly);\n\n this.abortController = new AbortController();\n this.runningBuild = [];\n\n if (focus.isClient()) {\n /**\n * Build client\n */\n await this.spawnBuild('client', `${clientOptions} --outDir ${outDir}/client`, {\n shouldWait: !isWatch,\n });\n }\n\n /**\n * Build server\n */\n if (focus.isServer()) {\n await this.spawnBuild(\n 'server',\n `${serverOptions} --outDir ${outDir}/server --ssr ${this.pluginConfig.serverFile}`,\n {\n shouldWait: !isWatch,\n },\n );\n\n if (!isWatch) {\n await this.buildManifest();\n\n if (isEject) {\n this.eject();\n }\n\n if (isServerless) {\n this.createServerless();\n }\n }\n }\n\n /**\n * Build additional entrypoint\n */\n const { entrypoint } = this.pluginConfig;\n\n if (entrypoint?.length && focus.isEntrypoint()) {\n for (const { name, type, serverFile, buildOptions = '' } of entrypoint) {\n const cliOptions = serverFile && type === 'ssr' ? `--ssr ${serverFile}` : '';\n\n await this.spawnBuild(name, `${buildOptions} ${cliOptions} --outDir ${outDir}/${name}`, {\n shouldWait: !isWatch,\n focusOnly: type === 'ssr' ? 'server' : 'client',\n env: {\n SSR_BOOST_CUSTOM_ENTRYPOINT_BUILD_NAME: name,\n },\n });\n }\n }\n\n /**\n * Preview mode\n */\n if (isWatch) {\n this.runPreviewMode();\n\n return;\n }\n\n if (isUnlockRobots) {\n this.unlockRobots();\n }\n\n createDevMarker(this.isProd, this.viteConfig);\n removeMeta(this.buildDir);\n onFinish?.();\n }\n}\n\nexport default Build;\n"],"names":["Build","isProd","nodeEnv","buildDir","viteConfig","pluginConfig","params","mode","clientOptions","serverOptions","focusOnly","isWatch","isUnlockRobots","isEject","isServerless","isNoWarnings","abortController","runningBuild","hasPreviewModeExitListener","constructor","this","async","resolveConfig","getPluginConfig","path","resolve","root","build","outDir","process","env","NODE_ENV","clearBuildFolder","fs","existsSync","rmSync","recursive","getIsProd","getNodeEnv","getRunningBuildNames","map","name","promisifyProcess","command","isRejectWarnings","promise","Promise","reject","on","code","message","stderr","buff","msg","Buffer","from","toString","includes","stdout","pipe","console","info","chalk","blue","routesParsing","isNodeParsing","serverConfig","ServerConfig","init","clientFile","SsrManifest","get","viteAliases","alias","basename","base","buildRoutesManifest","cleanupClientRoutes","routeFiles","readMeta","files","Set","Object","values","size","forEach","file","filepath","result","readFileSync","encoding","replace","writeFileSync","e","log","unlockRobots","robotsFile","warn","data","eject","entrypoint","createServerless","buildOptions","shouldWait","modeOpt","buildProcess","childProcess","spawn","signal","stdio","stdin","shell","FORCE_COLOR","SSR_BOOST_IS_SSR","createFocusOnly","isOnlyClient","SSR_BOOST_ACTION","global","viteBoostAction","push","waitLastBuild","latestProcess","at","exitCode","processStop","runPreviewMode","abort","onFinish","buildCount","length","listener","removeListener","createDevMarker","makeConfig","viteResetCache","focus","AbortController","isClient","spawnBuild","isServer","serverFile","buildManifest","isEntrypoint","type","cliOptions","SSR_BOOST_CUSTOM_ENTRYPOINT_BUILD_NAME","removeMeta"],"mappings":"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"}
1
+ {"version":3,"file":"build.js","sources":["../../src/services/build.ts"],"sourcesContent":["import 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 viteResetCache from '@cli/helpers/vite-reset-cache';\nimport createFocusOnly from '@helpers/create-focus-only';\nimport { createDevMarker } from '@helpers/dev-marker';\nimport type { IPluginConfig } from '@helpers/plugin-config';\nimport getPluginConfig from '@helpers/plugin-config';\nimport processStop from '@helpers/process-stop';\nimport { readMeta, removeMeta } from '@helpers/ssr-meta';\nimport ServerConfig from '@services/server-config';\nimport SsrManifest from '@services/ssr-manifest';\n\nexport interface IBuildParams {\n mode: string;\n onFinish?: () => void;\n clientOptions?: string;\n serverOptions?: string;\n focusOnly?: 'all' | 'app' | 'client' | 'server' | 'entrypoint';\n isWatch?: boolean;\n isUnlockRobots?: boolean;\n isEject?: boolean;\n isServerless?: boolean;\n isNoWarnings?: boolean;\n}\n\ninterface IBuildProcess {\n promise: Promise<number | null | string>;\n command: childProcess.ChildProcess;\n}\n\ninterface ISpawnBuildParams {\n shouldWait?: boolean;\n focusOnly?: IBuildParams['focusOnly'];\n env?: Record<string, string>;\n}\n\nexport interface IBuildEntrypoint {\n // entrypoint name\n name: string;\n type: 'spa' | 'ssr';\n // custom index file, default: indexFile from plugin config\n indexFile?: string;\n // custom entry file for replace in indexFile, default: undefined (do nothing)\n clientFile?: string;\n // custom server file, indexFile and clientFile will be ignored\n serverFile?: string;\n // additional options for vite build command\n buildOptions?: string;\n}\n\n/**\n * Build service\n */\nclass Build {\n /**\n * Is production build\n */\n protected isProd: boolean;\n\n /**\n * Node environment\n */\n protected nodeEnv: string;\n\n /**\n * Build folder\n */\n protected buildDir: string;\n\n /**\n * Vite config\n */\n protected viteConfig: ResolvedConfig;\n\n /**\n * Plugin config\n */\n protected pluginConfig: IPluginConfig;\n\n /**\n * Build params\n */\n protected params: IBuildParams = {\n mode: '',\n clientOptions: '',\n serverOptions: '',\n focusOnly: 'app',\n isWatch: false,\n isUnlockRobots: false,\n isEject: false,\n isServerless: false,\n isNoWarnings: false,\n };\n\n /**\n * Abort controller for builds\n */\n protected abortController: AbortController | null = null;\n\n /**\n * Running builds\n */\n protected runningBuild: { name: string; buildProcess: IBuildProcess }[] = [];\n\n /**\n * Listener for preview has attached\n */\n protected hasPreviewModeExitListener = false;\n\n /**\n * @constructor\n */\n public constructor(params: IBuildParams) {\n this.params = { ...this.params, ...params };\n }\n\n /**\n * Make config\n */\n protected 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.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 * Return is prod indicator value\n */\n public getIsProd(): boolean {\n return this.isProd;\n }\n\n /**\n * Return node env value\n */\n public getNodeEnv(): string {\n return this.nodeEnv;\n }\n\n /**\n * Return build names\n */\n public getRunningBuildNames(): string[] {\n return this.runningBuild.map(({ name }) => name);\n }\n\n /**\n * Promisify spawn process\n */\n protected promisifyProcess(\n command: childProcess.ChildProcess,\n isRejectWarnings = false,\n ): IBuildProcess {\n const promise = new Promise<number | null | string>((resolve, reject): void => {\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 protected async buildManifest(): Promise<void> {\n console.info(chalk.blue(`Building routes manifest file: ${this.pluginConfig.routesParsing}`));\n\n const isNodeParsing = this.pluginConfig.routesParsing === 'node';\n const serverConfig = ServerConfig.init(\n { isProd: this.isProd, mode: this.params.mode },\n { root: this.viteConfig.root, clientFile: this.pluginConfig.clientFile },\n );\n\n await SsrManifest.get(serverConfig, {\n buildDir: this.viteConfig.build.outDir,\n viteAliases: this.viteConfig.resolve.alias,\n basename: this.viteConfig.base,\n }).buildRoutesManifest(isNodeParsing);\n\n if (isNodeParsing) {\n this.cleanupClientRoutes();\n }\n }\n\n /**\n * Remove pathId from client route files\n */\n private cleanupClientRoutes(): void {\n const { routeFiles } = readMeta(this.buildDir);\n const files = new Set(Object.values(routeFiles ?? []));\n\n if (!files.size) {\n return;\n }\n\n files.forEach((file) => {\n const filepath = `${this.buildDir}/client/${file}`;\n\n try {\n const result = fs\n .readFileSync(filepath, { encoding: 'utf-8' })\n .replace(/(lazy:.*?\\((.*?)\\)),\\s?\".*?\"\\)/g, '$1)');\n\n fs.writeFileSync(filepath, result);\n } catch (e) {\n console.log(`Failed cleanup client route ${filepath}:`, e);\n }\n });\n }\n\n /**\n * Change general directive Disallow to Allow in robots.txt.\n */\n protected 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 protected 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 /**\n * Create serverless entrypoint\n */\n protected createServerless(): void {\n const entrypoint = `${this.buildDir}/server/serverless.js`;\n const script =\n \"import runServerless from '@lomray/vite-ssr-boost/cli/run-serverless.js';\\n\\n\" +\n `export default await runServerless({ version: process.env.VERSION || \"1.0.0\" });\\n`;\n\n fs.writeFileSync(entrypoint, script, {\n encoding: 'utf-8',\n });\n }\n\n /**\n * Build specified entrypoint\n */\n protected async spawnBuild(\n name: string,\n buildOptions: string,\n params: ISpawnBuildParams = {},\n ): Promise<void> {\n const { mode, isNoWarnings } = this.params;\n const { focusOnly = this.params.focusOnly, shouldWait = false, env = {} } = params;\n const modeOpt = mode && !buildOptions.includes('--mode') ? `--mode ${mode}` : '';\n\n const buildProcess = this.promisifyProcess(\n childProcess.spawn(`vite build ${buildOptions} ${modeOpt} --emptyOutDir`, {\n signal: this.abortController!.signal,\n stdio: [process.stdin, 'pipe', 'pipe'],\n shell: true,\n env: {\n ...process.env,\n ...env,\n FORCE_COLOR: '2',\n SSR_BOOST_IS_SSR: createFocusOnly(focusOnly).isOnlyClient() ? '0' : '1',\n SSR_BOOST_ACTION: global.viteBoostAction,\n },\n }),\n isNoWarnings,\n );\n\n this.runningBuild.push({ name, buildProcess });\n\n if (!shouldWait) {\n return;\n }\n\n await this.waitLastBuild();\n }\n\n /**\n * Wait latest build and stop process in case error\n */\n protected async waitLastBuild(): Promise<void> {\n const latestProcess = this.runningBuild.at(-1);\n\n if (!latestProcess) {\n return;\n }\n\n const exitCode = await latestProcess.buildProcess.promise;\n\n processStop(exitCode, true);\n }\n\n /**\n * Run preview mode\n */\n protected runPreviewMode(): void {\n if (!this.hasPreviewModeExitListener) {\n process.on('exit', () => {\n this.abortController!.abort();\n });\n\n this.hasPreviewModeExitListener = true;\n }\n\n const { onFinish } = this.params;\n let buildCount = this.runningBuild.length;\n\n /**\n * Detect finished builds for process\n */\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 this.runningBuild.forEach(({ buildProcess }) => {\n buildProcess.command.stdout?.removeListener('data', listener);\n });\n createDevMarker(this.isProd, this.viteConfig);\n onFinish?.();\n }\n }\n };\n\n /**\n * Listen output for call onFinish\n */\n this.runningBuild.forEach(({ buildProcess }) => {\n buildProcess.command.stdout?.on('data', listener);\n });\n }\n\n /**\n * Run app build\n */\n public async build(): Promise<void> {\n await this.makeConfig();\n // this is required step - build with different env may cause problems\n await viteResetCache();\n this.clearBuildFolder();\n\n const {\n clientOptions,\n serverOptions,\n onFinish,\n isWatch,\n focusOnly,\n isEject,\n isServerless,\n isUnlockRobots,\n } = this.params;\n const { outDir } = this.viteConfig.build;\n const focus = createFocusOnly(focusOnly);\n\n this.abortController = new AbortController();\n this.runningBuild = [];\n\n if (focus.isClient()) {\n /**\n * Build client\n */\n await this.spawnBuild('client', `${clientOptions} --outDir ${outDir}/client`, {\n shouldWait: !isWatch,\n });\n }\n\n /**\n * Build server\n */\n if (focus.isServer()) {\n await this.spawnBuild(\n 'server',\n `${serverOptions} --outDir ${outDir}/server --ssr ${this.pluginConfig.serverFile}`,\n {\n shouldWait: !isWatch,\n },\n );\n\n if (!isWatch) {\n await this.buildManifest();\n\n if (isEject) {\n this.eject();\n }\n\n if (isServerless) {\n this.createServerless();\n }\n }\n }\n\n /**\n * Build additional entrypoint\n */\n const { entrypoint } = this.pluginConfig;\n\n if (entrypoint?.length && focus.isEntrypoint()) {\n for (const { name, type, serverFile, buildOptions = '' } of entrypoint) {\n const cliOptions = serverFile && type === 'ssr' ? `--ssr ${serverFile}` : '';\n\n await this.spawnBuild(name, `${buildOptions} ${cliOptions} --outDir ${outDir}/${name}`, {\n shouldWait: !isWatch,\n focusOnly: type === 'ssr' ? 'server' : 'client',\n env: {\n SSR_BOOST_CUSTOM_ENTRYPOINT_BUILD_NAME: name,\n },\n });\n }\n }\n\n /**\n * Preview mode\n */\n if (isWatch) {\n this.runPreviewMode();\n\n return;\n }\n\n if (isUnlockRobots) {\n this.unlockRobots();\n }\n\n createDevMarker(this.isProd, this.viteConfig);\n removeMeta(this.buildDir);\n onFinish?.();\n }\n}\n\nexport default Build;\n"],"names":["Build","isProd","nodeEnv","buildDir","viteConfig","pluginConfig","params","mode","clientOptions","serverOptions","focusOnly","isWatch","isUnlockRobots","isEject","isServerless","isNoWarnings","abortController","runningBuild","hasPreviewModeExitListener","constructor","this","async","resolveConfig","getPluginConfig","path","resolve","root","build","outDir","process","env","NODE_ENV","clearBuildFolder","fs","existsSync","rmSync","recursive","getIsProd","getNodeEnv","getRunningBuildNames","map","name","promisifyProcess","command","isRejectWarnings","promise","Promise","reject","on","code","message","stderr","buff","msg","Buffer","from","toString","includes","stdout","pipe","console","info","chalk","blue","routesParsing","isNodeParsing","serverConfig","ServerConfig","init","clientFile","SsrManifest","get","viteAliases","alias","basename","base","buildRoutesManifest","cleanupClientRoutes","routeFiles","readMeta","files","Set","Object","values","size","forEach","file","filepath","result","readFileSync","encoding","replace","writeFileSync","e","log","unlockRobots","robotsFile","warn","data","eject","entrypoint","createServerless","buildOptions","shouldWait","modeOpt","buildProcess","childProcess","spawn","signal","stdio","stdin","shell","FORCE_COLOR","SSR_BOOST_IS_SSR","createFocusOnly","isOnlyClient","SSR_BOOST_ACTION","global","viteBoostAction","push","waitLastBuild","latestProcess","at","exitCode","processStop","runPreviewMode","abort","onFinish","buildCount","length","listener","removeListener","createDevMarker","makeConfig","viteResetCache","focus","AbortController","isClient","spawnBuild","isServer","serverFile","buildManifest","isEntrypoint","type","cliOptions","SSR_BOOST_CUSTOM_ENTRYPOINT_BUILD_NAME","removeMeta"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"logger.js","sources":["../../src/services/logger.ts"],"sourcesContent":["import type { LogErrorOptions, Logger as ViteLogger, LogOptions } from 'vite';\n\nconst LogLevels = {\n error: 1,\n warn: 2,\n info: 3,\n};\n\ninterface ILoggerOptions {\n logLevel?: number;\n logFilter?: (params: ILogParams) => boolean;\n}\n\ninterface ILogParams {\n level: keyof typeof LogLevels;\n msg?: string;\n options?: LogErrorOptions;\n}\n\n/**\n * Default production logger\n */\nclass Logger implements ViteLogger {\n /**\n * @inheritDoc\n */\n public hasWarned: boolean;\n\n /**\n * Current log level\n */\n public loglevel: number;\n\n /**\n * Custom log filter\n * Return 'true' to skip output\n */\n public logFilter: ILoggerOptions['logFilter'] | undefined;\n\n /**\n * @constructor\n */\n public constructor({ logFilter, logLevel = 3 }: ILoggerOptions = {}) {\n this.loglevel = logLevel;\n this.logFilter = logFilter;\n }\n\n /**\n * @inheritDoc\n */\n public clearScreen(): void {\n //\n }\n\n /**\n * Should we skip current log depends on current log level\n */\n protected shouldSkipLog(level: number): boolean {\n return level > this.loglevel;\n }\n\n /**\n * Common log\n */\n protected log(params: ILogParams): void {\n const { level, msg, options } = params;\n\n if (this.shouldSkipLog(LogLevels[level]) || this.logFilter?.(params)) {\n return;\n }\n\n const args = [msg, options?.error].filter(Boolean);\n\n console[level](...args);\n }\n\n /**\n * @inheritDoc\n */\n public error(msg: string, options?: LogErrorOptions): void {\n this.log({ msg, options, level: 'error' });\n }\n\n /**\n * @inheritDoc\n */\n public hasErrorLogged(): boolean {\n return false;\n }\n\n /**\n * @inheritDoc\n */\n public info(msg: string, options: LogOptions): void {\n this.log({ msg, options, level: 'info' });\n }\n\n /**\n * @inheritDoc\n */\n public warn(msg: string, options: LogOptions): void {\n this.log({ msg, options, level: 'warn' });\n }\n\n /**\n * @inheritDoc\n */\n public warnOnce(msg: string, options: LogOptions): void {\n this.warn(msg, options);\n }\n}\n\nexport default Logger;\n"],"names":["LogLevels","error","warn","info","Logger","hasWarned","loglevel","logFilter","constructor","logLevel","this","clearScreen","shouldSkipLog","level","log","params","msg","options","args","filter","Boolean","console","hasErrorLogged","warnOnce"],"mappings":"AAEA,MAAMA,EAAY,CAChBC,MAAO,EACPC,KAAM,EACNC,KAAM,GAiBR,MAAMC,EAIGC,UAKAC,SAMAC,UAKPC,aAAmBD,UAAEA,EAASE,SAAEA,EAAW,GAAsB,CAAA,GAC/DC,KAAKJ,SAAWG,EAChBC,KAAKH,UAAYA,CAClB,CAKMI,cAEN,CAKSC,cAAcC,GACtB,OAAOA,EAAQH,KAAKJ,QACrB,CAKSQ,IAAIC,GACZ,MAAMF,MAAEA,EAAKG,IAAEA,EAAGC,QAAEA,GAAYF,EAEhC,GAAIL,KAAKE,cAAcZ,EAAUa,KAAWH,KAAKH,YAAYQ,GAC3D,OAGF,MAAMG,EAAO,CAACF,EAAKC,GAAShB,OAAOkB,OAAOC,SAE1CC,QAAQR,MAAUK,EACnB,CAKMjB,MAAMe,EAAaC,GACxBP,KAAKI,IAAI,CAAEE,MAAKC,UAASJ,MAAO,SACjC,CAKMS,iBACL,OAAO,CACR,CAKMnB,KAAKa,EAAaC,GACvBP,KAAKI,IAAI,CAAEE,MAAKC,UAASJ,MAAO,QACjC,CAKMX,KAAKc,EAAaC,GACvBP,KAAKI,IAAI,CAAEE,MAAKC,UAASJ,MAAO,QACjC,CAKMU,SAASP,EAAaC,GAC3BP,KAAKR,KAAKc,EAAKC,EAChB"}
1
+ {"version":3,"file":"logger.js","sources":["../../src/services/logger.ts"],"sourcesContent":["import type { LogErrorOptions, Logger as ViteLogger, LogOptions } from 'vite';\n\nconst LogLevels = {\n error: 1,\n warn: 2,\n info: 3,\n};\n\ninterface ILoggerOptions {\n logLevel?: number;\n logFilter?: (params: ILogParams) => boolean;\n}\n\ninterface ILogParams {\n level: keyof typeof LogLevels;\n msg?: string;\n options?: LogErrorOptions;\n}\n\n/**\n * Default production logger\n */\nclass Logger implements ViteLogger {\n /**\n * @inheritDoc\n */\n public hasWarned: boolean;\n\n /**\n * Current log level\n */\n public loglevel: number;\n\n /**\n * Custom log filter\n * Return 'true' to skip output\n */\n public logFilter: ILoggerOptions['logFilter'] | undefined;\n\n /**\n * @constructor\n */\n public constructor({ logFilter, logLevel = 3 }: ILoggerOptions = {}) {\n this.loglevel = logLevel;\n this.logFilter = logFilter;\n }\n\n /**\n * @inheritDoc\n */\n public clearScreen(): void {\n //\n }\n\n /**\n * Should we skip current log depends on current log level\n */\n protected shouldSkipLog(level: number): boolean {\n return level > this.loglevel;\n }\n\n /**\n * Common log\n */\n protected log(params: ILogParams): void {\n const { level, msg, options } = params;\n\n if (this.shouldSkipLog(LogLevels[level]) || this.logFilter?.(params)) {\n return;\n }\n\n const args = [msg, options?.error].filter(Boolean);\n\n console[level](...args);\n }\n\n /**\n * @inheritDoc\n */\n public error(msg: string, options?: LogErrorOptions): void {\n this.log({ msg, options, level: 'error' });\n }\n\n /**\n * @inheritDoc\n */\n public hasErrorLogged(): boolean {\n return false;\n }\n\n /**\n * @inheritDoc\n */\n public info(msg: string, options: LogOptions): void {\n this.log({ msg, options, level: 'info' });\n }\n\n /**\n * @inheritDoc\n */\n public warn(msg: string, options: LogOptions): void {\n this.log({ msg, options, level: 'warn' });\n }\n\n /**\n * @inheritDoc\n */\n public warnOnce(msg: string, options: LogOptions): void {\n this.warn(msg, options);\n }\n}\n\nexport default Logger;\n"],"names":["LogLevels","error","warn","info","Logger","hasWarned","loglevel","logFilter","constructor","logLevel","this","clearScreen","shouldSkipLog","level","log","params","msg","options","args","filter","Boolean","console","hasErrorLogged","warnOnce"],"mappings":"AAEA,MAAMA,EAAY,CAChBC,MAAO,EACPC,KAAM,EACNC,KAAM,GAiBR,MAAMC,EAIGC,UAKAC,SAMAC,UAKPC,aAAmBD,UAAEA,EAASE,SAAEA,EAAW,GAAsB,CAAA,GAC/DC,KAAKJ,SAAWG,EAChBC,KAAKH,UAAYA,EAMZI,eAOGC,cAAcC,GACtB,OAAOA,EAAQH,KAAKJ,SAMZQ,IAAIC,GACZ,MAAMF,MAAEA,EAAKG,IAAEA,EAAGC,QAAEA,GAAYF,EAEhC,GAAIL,KAAKE,cAAcZ,EAAUa,KAAWH,KAAKH,YAAYQ,GAC3D,OAGF,MAAMG,EAAO,CAACF,EAAKC,GAAShB,OAAOkB,OAAOC,SAE1CC,QAAQR,MAAUK,GAMbjB,MAAMe,EAAaC,GACxBP,KAAKI,IAAI,CAAEE,MAAKC,UAASJ,MAAO,UAM3BS,iBACL,OAAO,EAMFnB,KAAKa,EAAaC,GACvBP,KAAKI,IAAI,CAAEE,MAAKC,UAASJ,MAAO,SAM3BX,KAAKc,EAAaC,GACvBP,KAAKI,IAAI,CAAEE,MAAKC,UAASJ,MAAO,SAM3BU,SAASP,EAAaC,GAC3BP,KAAKR,KAAKc,EAAKC"}
@@ -1 +1 @@
1
- {"version":3,"file":"parse-routes.js","sources":["../../src/services/parse-routes.ts"],"sourcesContent":["import fs from 'fs';\nimport { resolve } from 'node:path';\nimport path from 'path';\nimport babelGenerate from '@babel/generator';\nimport type * as GenerateTypes from '@babel/generator';\nimport * as parser from '@babel/parser';\nimport type { ParseResult } from '@babel/parser';\nimport babelTraverse from '@babel/traverse';\nimport type * as TraverseTypes from '@babel/traverse';\nimport type {\n CallExpression,\n File as BabelFile,\n VariableDeclaration,\n ObjectExpression,\n} from '@babel/types';\nimport {\n isObjectProperty,\n isIdentifier,\n identifier,\n stringLiteral,\n objectProperty,\n isArrayExpression,\n isJSXElement,\n isJSXIdentifier,\n isObjectExpression,\n} from '@babel/types';\nimport type { Alias } from 'vite';\nimport PathNormalize from '@services/path-normalize';\nimport type ServerConfig from '@services/server-config';\n//\n// @ts-expect-error known import problem\nconst generate = (babelGenerate.default ?? babelGenerate) as (typeof GenerateTypes)['default'];\n// @ts-expect-error known import problem\nconst traverse = (babelTraverse.default ?? babelTraverse) as (typeof TraverseTypes)['default'];\n\ninterface IPathImport {\n routesPath: string | null;\n exportName: string | null;\n}\n\ninterface IMapImports {\n [name: string]: {\n path: string;\n isDefault: boolean; // is default import?\n };\n}\n\nexport type TRoutesTree = {\n index: number;\n import: string;\n children: TRoutesTree[];\n};\n\n/**\n * Parse react router routes array\n */\nclass ParseRoutes {\n /**\n * Path normalize service\n */\n protected readonly pathNormalize: PathNormalize;\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.pathNormalize = new PathNormalize(config, viteAliases);\n }\n\n /**\n * Parse routes\n */\n public parse(): TRoutesTree[] {\n const { clientFile, root } = this.config.getParams();\n\n const clientEntrypoint = resolve(root, clientFile);\n const routesEntrypoint = this.findRoutesEntrypoint(clientEntrypoint);\n\n if (!routesEntrypoint?.routesPath) {\n throw new Error(`Unable to find routes file import in ${clientFile}`);\n }\n\n const { routesPath, exportName } = routesEntrypoint;\n const routeFilepath = this.resolveFilename(routesPath, clientEntrypoint);\n\n return this.recursiveBuildRoutesTree(routeFilepath, exportName);\n }\n\n /**\n * Parse file and return ast\n */\n private parseFile(filename: string): ParseResult<BabelFile> | null {\n try {\n const code = fs.readFileSync(filename, 'utf-8');\n\n return parser.parse(code, {\n sourceType: 'module',\n plugins: ['typescript', 'jsx'],\n });\n } catch (e) {\n return null;\n }\n }\n\n /**\n * Find route import filepath\n */\n private getImportPath(\n ast: ParseResult<BabelFile>,\n importName: string | null,\n ): IPathImport | null {\n let routesPath: string | null = null;\n let exportName: string | null = null;\n\n traverse(ast, {\n ImportDeclaration(nodePath) {\n const importNode = nodePath.node;\n\n importNode.specifiers.forEach((specifier) => {\n if (specifier.local.name === importName) {\n exportName = specifier.type === 'ImportDefaultSpecifier' ? null : importName;\n routesPath = importNode.source.value;\n }\n });\n },\n });\n\n return {\n routesPath,\n exportName,\n };\n }\n\n /**\n * Find routes array inside code\n */\n private findRoutesDefinition(\n ast: ParseResult<BabelFile>,\n exportName: string | null,\n ): null | VariableDeclaration {\n let exportNameResolved = exportName;\n\n // noinspection JSUnusedGlobalSymbols\n traverse(ast, {\n ExportNamedDeclaration({ node }) {\n if (!node.declaration && node.specifiers.length > 0) {\n node.specifiers.forEach((specifier) => {\n // @ts-expect-error missing in types\n const exportedName = specifier.exported.name as string;\n\n if (exportName === null && specifier.type === 'ExportSpecifier') {\n if (specifier.local.name === 'default') {\n exportNameResolved = exportedName;\n }\n } else if (exportedName === exportName) {\n // @ts-expect-error missing in types\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n exportNameResolved = specifier.local.name as string;\n }\n });\n }\n },\n ExportDefaultDeclaration({ node }) {\n if (exportName === null) {\n if (node.declaration.type === 'Identifier') {\n exportNameResolved = node.declaration.name;\n // @ts-expect-error missing in types\n } else if (node.declaration.type === 'VariableDeclaration') {\n // @ts-expect-error missing in types\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n exportNameResolved = node.declaration.declarations[0].id.name as string;\n }\n }\n },\n });\n\n if (exportNameResolved) {\n let variableNode: VariableDeclaration | null = null;\n\n traverse(ast, {\n VariableDeclaration({ node }) {\n node.declarations.forEach((declaration) => {\n // @ts-expect-error missing in types\n if (declaration.id.name === exportNameResolved) {\n variableNode = node;\n }\n });\n },\n });\n\n return variableNode;\n }\n\n return null;\n }\n\n /**\n * Entrypoint routes file\n */\n private findRoutesEntrypoint(clientEntrypoint: string): IPathImport | null {\n const ast = this.parseFile(clientEntrypoint);\n\n let routesVariable: string | null = null;\n\n if (!ast) {\n return routesVariable;\n }\n\n traverse(ast, {\n CallExpression({ node }) {\n if (\n // @ts-expect-error missing in types\n node.callee.name === 'entryClient' &&\n node.arguments.length >= 2 &&\n node.arguments[1].type === 'Identifier'\n ) {\n routesVariable = node.arguments[1].name;\n }\n },\n });\n\n return this.getImportPath(ast, routesVariable);\n }\n\n /**\n * Resolve route filename import\n */\n private resolveFilename(filename: string, relativeFile?: string): string | null {\n let resolvedFilename = filename;\n\n if ((filename.startsWith('./') || filename.startsWith('../')) && relativeFile) {\n resolvedFilename = path.resolve(path.dirname(relativeFile), filename);\n }\n\n const filepath = this.pathNormalize.getAppPath(resolvedFilename, true);\n\n return this.pathNormalize.findAppFile(filepath!);\n }\n\n /**\n * Parse ast array routes objects\n */\n private parseRoutesArray(\n elements: TraverseTypes.Node[],\n importsMap: IMapImports,\n relativeFile: string,\n ): TRoutesTree[] {\n const results: TRoutesTree[] = [];\n\n elements.forEach((node, index) => {\n if (node.type === 'ObjectExpression') {\n const routeInfo: TRoutesTree = { index, import: '', children: [] };\n\n node.properties.forEach((prop) => {\n const objectProp = prop as {\n key: { name: string };\n value: { type: string; elements: TraverseTypes.Node[] };\n };\n\n if (objectProp.key.name === 'children' && objectProp.value.type === 'ArrayExpression') {\n routeInfo.children = this.parseRoutesArray(\n objectProp.value.elements,\n importsMap,\n relativeFile,\n );\n }\n\n // async routes\n if (\n objectProp.key.name === 'lazy' &&\n objectProp.value.type === 'ArrowFunctionExpression'\n ) {\n // @ts-expect-error incorrect types\n const importCall = objectProp.value.body as CallExpression;\n\n if (importCall.type === 'CallExpression' && importCall.callee.type === 'Import') {\n const [importArg] = importCall.arguments;\n\n if (importArg.type === 'StringLiteral') {\n routeInfo.import = importArg.value;\n }\n }\n }\n\n // static routes: Component\n if (objectProp.key.name === 'Component' && objectProp.value.type === 'Identifier') {\n // @ts-expect-error incorrect types\n const importName = objectProp.value.name as string;\n const { path: importPath } = importsMap[importName] ?? {};\n\n if (importPath) {\n routeInfo.import = importPath;\n }\n }\n\n // static routes: element\n if (objectProp.key.name === 'element' && objectProp.value.type === 'JSXElement') {\n // @ts-expect-error incorrect types\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n const importName = objectProp.value?.openingElement?.name?.name as string;\n const { path: importPath } = importsMap[importName] ?? {};\n\n if (importPath) {\n routeInfo.import = importPath;\n }\n }\n\n if (objectProp.key.name === 'children' && objectProp.value.type === 'Identifier') {\n // @ts-expect-error incorrect types\n const importName = objectProp.value.name as string;\n const { path: importPath, isDefault } = importsMap[importName] ?? {};\n\n if (importPath) {\n const childrenFilePath = this.resolveFilename(importPath, relativeFile);\n\n if (childrenFilePath) {\n routeInfo.children = this.recursiveBuildRoutesTree(\n childrenFilePath,\n isDefault ? null : importName,\n );\n }\n }\n }\n });\n\n if (routeInfo.import || routeInfo.children.length > 0) {\n results.push(routeInfo);\n }\n }\n });\n\n return results;\n }\n\n /**\n * Parse imports map from ast\n */\n private static parseImportsMap(ast: ParseResult<BabelFile>): IMapImports {\n const importsMap: IMapImports = {};\n\n traverse(ast, {\n ImportDeclaration(nodePath) {\n const importNode = nodePath.node;\n\n importNode.specifiers.forEach((specifier) => {\n importsMap[specifier.local.name] = {\n path: importNode.source.value,\n isDefault: specifier.type === 'ImportDefaultSpecifier',\n };\n });\n },\n });\n\n return importsMap;\n }\n\n /**\n * Recursive build routes tree with dynamic imports\n */\n private recursiveBuildRoutesTree(\n filename: string | null,\n exportName: string | null = null,\n ): TRoutesTree[] {\n if (!filename) {\n return [];\n }\n\n const ast = this.parseFile(filename);\n\n if (!ast) {\n return [];\n }\n\n const routesNode = this.findRoutesDefinition(ast, exportName);\n const results: TRoutesTree[] = [];\n\n if (!routesNode) {\n return results;\n }\n\n const importsMap = ParseRoutes.parseImportsMap(ast);\n\n // @ts-expect-error missing types\n const elements = routesNode.declarations[0].init?.elements as TraverseTypes.Node[];\n\n results.push(...this.parseRoutesArray(elements, importsMap, filename));\n\n return results;\n }\n\n /**\n * Add pathId to static routes\n */\n private static processRouteFileCode(\n nodePath: TraverseTypes.NodePath<ObjectExpression>,\n importsMap: IMapImports,\n ): void {\n nodePath.node.properties.forEach((property) => {\n if (isObjectProperty(property) && isIdentifier(property.key)) {\n if (property.key.name === 'element' || property.key.name === 'Component') {\n let componentName = '';\n\n if (isJSXElement(property.value) && isJSXIdentifier(property.value.openingElement.name)) {\n componentName = property.value.openingElement.name.name;\n } else if (isIdentifier(property.value)) {\n componentName = property.value.name;\n }\n\n const parent = nodePath.findParent((p) => isArrayExpression(p.node));\n const importName = importsMap[componentName]?.path;\n\n if (parent && importName) {\n const pathIdProperty = objectProperty(identifier('pathId'), stringLiteral(importName));\n\n // Insert the pathId property right after the element property\n nodePath.node.properties.splice(\n nodePath.node.properties.indexOf(property) + 1,\n 0,\n pathIdProperty,\n );\n }\n }\n\n if (property.key.name === 'children' && isArrayExpression(property.value)) {\n // Process each object in the children array recursively\n property.value.elements.forEach((element) => {\n if (isObjectExpression(element)) {\n ParseRoutes.processRouteFileCode(\n { node: element } as TraverseTypes.NodePath<ObjectExpression>,\n importsMap,\n );\n }\n });\n }\n }\n });\n }\n\n /**\n * Inject pathId to sync routes\n */\n public static injectPathId(code: string): string {\n if (!code) {\n return code;\n }\n\n const ast = parser.parse(code, {\n sourceType: 'module',\n plugins: ['typescript', 'jsx'],\n });\n\n if (!ast) {\n return code;\n }\n\n const importsMap = ParseRoutes.parseImportsMap(ast);\n\n traverse(ast, {\n ObjectExpression(nodePath) {\n ParseRoutes.processRouteFileCode(nodePath, importsMap);\n },\n });\n\n return generate(ast, {\n retainLines: true,\n }).code;\n }\n}\n\nexport default ParseRoutes;\n"],"names":["generate","babelGenerate","default","traverse","babelTraverse","ParseRoutes","pathNormalize","config","constructor","viteAliases","this","PathNormalize","parse","clientFile","root","getParams","clientEntrypoint","resolve","routesEntrypoint","findRoutesEntrypoint","routesPath","Error","exportName","routeFilepath","resolveFilename","recursiveBuildRoutesTree","parseFile","filename","code","fs","readFileSync","parser","sourceType","plugins","e","getImportPath","ast","importName","ImportDeclaration","nodePath","importNode","node","specifiers","forEach","specifier","local","name","type","source","value","findRoutesDefinition","exportNameResolved","ExportNamedDeclaration","declaration","length","exportedName","exported","ExportDefaultDeclaration","declarations","id","variableNode","VariableDeclaration","routesVariable","CallExpression","callee","arguments","relativeFile","resolvedFilename","startsWith","path","dirname","filepath","getAppPath","findAppFile","parseRoutesArray","elements","importsMap","results","index","routeInfo","import","children","properties","prop","objectProp","key","importCall","body","importArg","importPath","openingElement","isDefault","childrenFilePath","push","static","routesNode","parseImportsMap","init","property","isObjectProperty","isIdentifier","componentName","isJSXElement","isJSXIdentifier","parent","findParent","p","isArrayExpression","pathIdProperty","objectProperty","identifier","stringLiteral","splice","indexOf","element","isObjectExpression","processRouteFileCode","ObjectExpression","retainLines"],"mappings":"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"}
1
+ {"version":3,"file":"parse-routes.js","sources":["../../src/services/parse-routes.ts"],"sourcesContent":["import fs from 'fs';\nimport { resolve } from 'node:path';\nimport path from 'path';\nimport babelGenerate from '@babel/generator';\nimport type * as GenerateTypes from '@babel/generator';\nimport * as parser from '@babel/parser';\nimport type { ParseResult } from '@babel/parser';\nimport babelTraverse from '@babel/traverse';\nimport type * as TraverseTypes from '@babel/traverse';\nimport type {\n CallExpression,\n File as BabelFile,\n VariableDeclaration,\n ObjectExpression,\n} from '@babel/types';\nimport {\n isObjectProperty,\n isIdentifier,\n identifier,\n stringLiteral,\n objectProperty,\n isArrayExpression,\n isJSXElement,\n isJSXIdentifier,\n isObjectExpression,\n} from '@babel/types';\nimport type { Alias } from 'vite';\nimport PathNormalize from '@services/path-normalize';\nimport type ServerConfig from '@services/server-config';\n//\n// @ts-expect-error known import problem\nconst generate = (babelGenerate.default ?? babelGenerate) as (typeof GenerateTypes)['default'];\n// @ts-expect-error known import problem\nconst traverse = (babelTraverse.default ?? babelTraverse) as (typeof TraverseTypes)['default'];\n\ninterface IPathImport {\n routesPath: string | null;\n exportName: string | null;\n}\n\ninterface IMapImports {\n [name: string]: {\n path: string;\n isDefault: boolean; // is default import?\n };\n}\n\nexport type TRoutesTree = {\n index: number;\n import: string;\n children: TRoutesTree[];\n};\n\n/**\n * Parse react router routes array\n */\nclass ParseRoutes {\n /**\n * Path normalize service\n */\n protected readonly pathNormalize: PathNormalize;\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.pathNormalize = new PathNormalize(config, viteAliases);\n }\n\n /**\n * Parse routes\n */\n public parse(): TRoutesTree[] {\n const { clientFile, root } = this.config.getParams();\n\n const clientEntrypoint = resolve(root, clientFile);\n const routesEntrypoint = this.findRoutesEntrypoint(clientEntrypoint);\n\n if (!routesEntrypoint?.routesPath) {\n throw new Error(`Unable to find routes file import in ${clientFile}`);\n }\n\n const { routesPath, exportName } = routesEntrypoint;\n const routeFilepath = this.resolveFilename(routesPath, clientEntrypoint);\n\n return this.recursiveBuildRoutesTree(routeFilepath, exportName);\n }\n\n /**\n * Parse file and return ast\n */\n private parseFile(filename: string): ParseResult<BabelFile> | null {\n try {\n const code = fs.readFileSync(filename, 'utf-8');\n\n return parser.parse(code, {\n sourceType: 'module',\n plugins: ['typescript', 'jsx'],\n });\n } catch (e) {\n return null;\n }\n }\n\n /**\n * Find route import filepath\n */\n private getImportPath(\n ast: ParseResult<BabelFile>,\n importName: string | null,\n ): IPathImport | null {\n let routesPath: string | null = null;\n let exportName: string | null = null;\n\n traverse(ast, {\n ImportDeclaration(nodePath) {\n const importNode = nodePath.node;\n\n importNode.specifiers.forEach((specifier) => {\n if (specifier.local.name === importName) {\n exportName = specifier.type === 'ImportDefaultSpecifier' ? null : importName;\n routesPath = importNode.source.value;\n }\n });\n },\n });\n\n return {\n routesPath,\n exportName,\n };\n }\n\n /**\n * Find routes array inside code\n */\n private findRoutesDefinition(\n ast: ParseResult<BabelFile>,\n exportName: string | null,\n ): null | VariableDeclaration {\n let exportNameResolved = exportName;\n\n // noinspection JSUnusedGlobalSymbols\n traverse(ast, {\n ExportNamedDeclaration({ node }) {\n if (!node.declaration && node.specifiers.length > 0) {\n node.specifiers.forEach((specifier) => {\n // @ts-expect-error missing in types\n const exportedName = specifier.exported.name as string;\n\n if (exportName === null && specifier.type === 'ExportSpecifier') {\n if (specifier.local.name === 'default') {\n exportNameResolved = exportedName;\n }\n } else if (exportedName === exportName) {\n // @ts-expect-error missing in types\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n exportNameResolved = specifier.local.name as string;\n }\n });\n }\n },\n ExportDefaultDeclaration({ node }) {\n if (exportName === null) {\n if (node.declaration.type === 'Identifier') {\n exportNameResolved = node.declaration.name;\n // @ts-expect-error missing in types\n } else if (node.declaration.type === 'VariableDeclaration') {\n // @ts-expect-error missing in types\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n exportNameResolved = node.declaration.declarations[0].id.name as string;\n }\n }\n },\n });\n\n if (exportNameResolved) {\n let variableNode: VariableDeclaration | null = null;\n\n traverse(ast, {\n VariableDeclaration({ node }) {\n node.declarations.forEach((declaration) => {\n // @ts-expect-error missing in types\n if (declaration.id.name === exportNameResolved) {\n variableNode = node;\n }\n });\n },\n });\n\n return variableNode;\n }\n\n return null;\n }\n\n /**\n * Entrypoint routes file\n */\n private findRoutesEntrypoint(clientEntrypoint: string): IPathImport | null {\n const ast = this.parseFile(clientEntrypoint);\n\n let routesVariable: string | null = null;\n\n if (!ast) {\n return routesVariable;\n }\n\n traverse(ast, {\n CallExpression({ node }) {\n if (\n // @ts-expect-error missing in types\n node.callee.name === 'entryClient' &&\n node.arguments.length >= 2 &&\n node.arguments[1].type === 'Identifier'\n ) {\n routesVariable = node.arguments[1].name;\n }\n },\n });\n\n return this.getImportPath(ast, routesVariable);\n }\n\n /**\n * Resolve route filename import\n */\n private resolveFilename(filename: string, relativeFile?: string): string | null {\n let resolvedFilename = filename;\n\n if ((filename.startsWith('./') || filename.startsWith('../')) && relativeFile) {\n resolvedFilename = path.resolve(path.dirname(relativeFile), filename);\n }\n\n const filepath = this.pathNormalize.getAppPath(resolvedFilename, true);\n\n return this.pathNormalize.findAppFile(filepath!);\n }\n\n /**\n * Parse ast array routes objects\n */\n private parseRoutesArray(\n elements: TraverseTypes.Node[],\n importsMap: IMapImports,\n relativeFile: string,\n ): TRoutesTree[] {\n const results: TRoutesTree[] = [];\n\n elements.forEach((node, index) => {\n if (node.type === 'ObjectExpression') {\n const routeInfo: TRoutesTree = { index, import: '', children: [] };\n\n node.properties.forEach((prop) => {\n const objectProp = prop as {\n key: { name: string };\n value: { type: string; elements: TraverseTypes.Node[] };\n };\n\n if (objectProp.key.name === 'children' && objectProp.value.type === 'ArrayExpression') {\n routeInfo.children = this.parseRoutesArray(\n objectProp.value.elements,\n importsMap,\n relativeFile,\n );\n }\n\n // async routes\n if (\n objectProp.key.name === 'lazy' &&\n objectProp.value.type === 'ArrowFunctionExpression'\n ) {\n // @ts-expect-error incorrect types\n const importCall = objectProp.value.body as CallExpression;\n\n if (importCall.type === 'CallExpression' && importCall.callee.type === 'Import') {\n const [importArg] = importCall.arguments;\n\n if (importArg.type === 'StringLiteral') {\n routeInfo.import = importArg.value;\n }\n }\n }\n\n // static routes: Component\n if (objectProp.key.name === 'Component' && objectProp.value.type === 'Identifier') {\n // @ts-expect-error incorrect types\n const importName = objectProp.value.name as string;\n const { path: importPath } = importsMap[importName] ?? {};\n\n if (importPath) {\n routeInfo.import = importPath;\n }\n }\n\n // static routes: element\n if (objectProp.key.name === 'element' && objectProp.value.type === 'JSXElement') {\n // @ts-expect-error incorrect types\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n const importName = objectProp.value?.openingElement?.name?.name as string;\n const { path: importPath } = importsMap[importName] ?? {};\n\n if (importPath) {\n routeInfo.import = importPath;\n }\n }\n\n if (objectProp.key.name === 'children' && objectProp.value.type === 'Identifier') {\n // @ts-expect-error incorrect types\n const importName = objectProp.value.name as string;\n const { path: importPath, isDefault } = importsMap[importName] ?? {};\n\n if (importPath) {\n const childrenFilePath = this.resolveFilename(importPath, relativeFile);\n\n if (childrenFilePath) {\n routeInfo.children = this.recursiveBuildRoutesTree(\n childrenFilePath,\n isDefault ? null : importName,\n );\n }\n }\n }\n });\n\n if (routeInfo.import || routeInfo.children.length > 0) {\n results.push(routeInfo);\n }\n }\n });\n\n return results;\n }\n\n /**\n * Parse imports map from ast\n */\n private static parseImportsMap(ast: ParseResult<BabelFile>): IMapImports {\n const importsMap: IMapImports = {};\n\n traverse(ast, {\n ImportDeclaration(nodePath) {\n const importNode = nodePath.node;\n\n importNode.specifiers.forEach((specifier) => {\n importsMap[specifier.local.name] = {\n path: importNode.source.value,\n isDefault: specifier.type === 'ImportDefaultSpecifier',\n };\n });\n },\n });\n\n return importsMap;\n }\n\n /**\n * Recursive build routes tree with dynamic imports\n */\n private recursiveBuildRoutesTree(\n filename: string | null,\n exportName: string | null = null,\n ): TRoutesTree[] {\n if (!filename) {\n return [];\n }\n\n const ast = this.parseFile(filename);\n\n if (!ast) {\n return [];\n }\n\n const routesNode = this.findRoutesDefinition(ast, exportName);\n const results: TRoutesTree[] = [];\n\n if (!routesNode) {\n return results;\n }\n\n const importsMap = ParseRoutes.parseImportsMap(ast);\n\n // @ts-expect-error missing types\n const elements = routesNode.declarations[0].init?.elements as TraverseTypes.Node[];\n\n results.push(...this.parseRoutesArray(elements, importsMap, filename));\n\n return results;\n }\n\n /**\n * Add pathId to static routes\n */\n private static processRouteFileCode(\n nodePath: TraverseTypes.NodePath<ObjectExpression>,\n importsMap: IMapImports,\n ): void {\n nodePath.node.properties.forEach((property) => {\n if (isObjectProperty(property) && isIdentifier(property.key)) {\n if (property.key.name === 'element' || property.key.name === 'Component') {\n let componentName = '';\n\n if (isJSXElement(property.value) && isJSXIdentifier(property.value.openingElement.name)) {\n componentName = property.value.openingElement.name.name;\n } else if (isIdentifier(property.value)) {\n componentName = property.value.name;\n }\n\n const parent = nodePath.findParent((p) => isArrayExpression(p.node));\n const importName = importsMap[componentName]?.path;\n\n if (parent && importName) {\n const pathIdProperty = objectProperty(identifier('pathId'), stringLiteral(importName));\n\n // Insert the pathId property right after the element property\n nodePath.node.properties.splice(\n nodePath.node.properties.indexOf(property) + 1,\n 0,\n pathIdProperty,\n );\n }\n }\n\n if (property.key.name === 'children' && isArrayExpression(property.value)) {\n // Process each object in the children array recursively\n property.value.elements.forEach((element) => {\n if (isObjectExpression(element)) {\n ParseRoutes.processRouteFileCode(\n { node: element } as TraverseTypes.NodePath<ObjectExpression>,\n importsMap,\n );\n }\n });\n }\n }\n });\n }\n\n /**\n * Inject pathId to sync routes\n */\n public static injectPathId(code: string): string {\n if (!code) {\n return code;\n }\n\n const ast = parser.parse(code, {\n sourceType: 'module',\n plugins: ['typescript', 'jsx'],\n });\n\n if (!ast) {\n return code;\n }\n\n const importsMap = ParseRoutes.parseImportsMap(ast);\n\n traverse(ast, {\n ObjectExpression(nodePath) {\n ParseRoutes.processRouteFileCode(nodePath, importsMap);\n },\n });\n\n return generate(ast, {\n retainLines: true,\n }).code;\n }\n}\n\nexport default ParseRoutes;\n"],"names":["generate","babelGenerate","default","traverse","babelTraverse","ParseRoutes","pathNormalize","config","constructor","viteAliases","this","PathNormalize","parse","clientFile","root","getParams","clientEntrypoint","resolve","routesEntrypoint","findRoutesEntrypoint","routesPath","Error","exportName","routeFilepath","resolveFilename","recursiveBuildRoutesTree","parseFile","filename","code","fs","readFileSync","parser","sourceType","plugins","e","getImportPath","ast","importName","ImportDeclaration","nodePath","importNode","node","specifiers","forEach","specifier","local","name","type","source","value","findRoutesDefinition","exportNameResolved","ExportNamedDeclaration","declaration","length","exportedName","exported","ExportDefaultDeclaration","declarations","id","variableNode","VariableDeclaration","routesVariable","CallExpression","callee","arguments","relativeFile","resolvedFilename","startsWith","path","dirname","filepath","getAppPath","findAppFile","parseRoutesArray","elements","importsMap","results","index","routeInfo","import","children","properties","prop","objectProp","key","importCall","body","importArg","importPath","openingElement","isDefault","childrenFilePath","push","static","routesNode","parseImportsMap","init","property","isObjectProperty","isIdentifier","componentName","isJSXElement","isJSXIdentifier","parent","findParent","p","isArrayExpression","pathIdProperty","objectProperty","identifier","stringLiteral","splice","indexOf","element","isObjectExpression","processRouteFileCode","ObjectExpression","retainLines"],"mappings":"2ZA+BA,MAAMA,EAAYC,EAAcC,SAAWD,EAErCE,EAAYC,EAAcF,SAAWE,EAuB3C,MAAMC,EAIeC,cAKAC,OAKnBC,YAAYD,EAAsBE,GAChCC,KAAKH,OAASA,EACdG,KAAKJ,cAAgB,IAAIK,EAAcJ,EAAQE,GAM1CG,QACL,MAAMC,WAAEA,EAAUC,KAAEA,GAASJ,KAAKH,OAAOQ,YAEnCC,EAAmBC,EAAQH,EAAMD,GACjCK,EAAmBR,KAAKS,qBAAqBH,GAEnD,IAAKE,GAAkBE,WACrB,MAAM,IAAIC,MAAM,wCAAwCR,KAG1D,MAAMO,WAAEA,EAAUE,WAAEA,GAAeJ,EAC7BK,EAAgBb,KAAKc,gBAAgBJ,EAAYJ,GAEvD,OAAON,KAAKe,yBAAyBF,EAAeD,GAM9CI,UAAUC,GAChB,IACE,MAAMC,EAAOC,EAAGC,aAAaH,EAAU,SAEvC,OAAOI,EAAOnB,MAAMgB,EAAM,CACxBI,WAAY,SACZC,QAAS,CAAC,aAAc,SAE1B,MAAOC,GACP,OAAO,MAOHC,cACNC,EACAC,GAEA,IAAIjB,EAA4B,KAC5BE,EAA4B,KAehC,OAbAnB,EAASiC,EAAK,CACZE,kBAAkBC,GAChB,MAAMC,EAAaD,EAASE,KAE5BD,EAAWE,WAAWC,SAASC,IACzBA,EAAUC,MAAMC,OAAST,IAC3Bf,EAAgC,2BAAnBsB,EAAUG,KAAoC,KAAOV,EAClEjB,EAAaoB,EAAWQ,OAAOC,SAGpC,IAGI,CACL7B,aACAE,cAOI4B,qBACNd,EACAd,GAEA,IAAI6B,EAAqB7B,EAoCzB,GAjCAnB,EAASiC,EAAK,CACZgB,wBAAuBX,KAAEA,KAClBA,EAAKY,aAAeZ,EAAKC,WAAWY,OAAS,GAChDb,EAAKC,WAAWC,SAASC,IAEvB,MAAMW,EAAeX,EAAUY,SAASV,KAErB,OAAfxB,GAA0C,oBAAnBsB,EAAUG,KACN,YAAzBH,EAAUC,MAAMC,OAClBK,EAAqBI,GAEdA,IAAiBjC,IAG1B6B,EAAqBP,EAAUC,MAAMC,QAI5C,EACDW,0BAAyBhB,KAAEA,IACN,OAAfnB,IAC4B,eAA1BmB,EAAKY,YAAYN,KACnBI,EAAqBV,EAAKY,YAAYP,KAEH,wBAA1BL,EAAKY,YAAYN,OAG1BI,EAAqBV,EAAKY,YAAYK,aAAa,GAAGC,GAAGb,MAG9D,IAGCK,EAAoB,CACtB,IAAIS,EAA2C,KAa/C,OAXAzD,EAASiC,EAAK,CACZyB,qBAAoBpB,KAAEA,IACpBA,EAAKiB,aAAaf,SAASU,IAErBA,EAAYM,GAAGb,OAASK,IAC1BS,EAAenB,KAGpB,IAGImB,EAGT,OAAO,KAMDzC,qBAAqBH,GAC3B,MAAMoB,EAAM1B,KAAKgB,UAAUV,GAE3B,IAAI8C,EAAgC,KAEpC,OAAK1B,GAILjC,EAASiC,EAAK,CACZ2B,gBAAetB,KAAEA,IAGQ,gBAArBA,EAAKuB,OAAOlB,MACZL,EAAKwB,UAAUX,QAAU,GACE,eAA3Bb,EAAKwB,UAAU,GAAGlB,OAElBe,EAAiBrB,EAAKwB,UAAU,GAAGnB,KAEtC,IAGIpC,KAAKyB,cAAcC,EAAK0B,IAhBtBA,EAsBHtC,gBAAgBG,EAAkBuC,GACxC,IAAIC,EAAmBxC,GAElBA,EAASyC,WAAW,OAASzC,EAASyC,WAAW,SAAWF,IAC/DC,EAAmBE,EAAKpD,QAAQoD,EAAKC,QAAQJ,GAAevC,IAG9D,MAAM4C,EAAW7D,KAAKJ,cAAckE,WAAWL,GAAkB,GAEjE,OAAOzD,KAAKJ,cAAcmE,YAAYF,GAMhCG,iBACNC,EACAC,EACAV,GAEA,MAAMW,EAAyB,GAoF/B,OAlFAF,EAAShC,SAAQ,CAACF,EAAMqC,KACtB,GAAkB,qBAAdrC,EAAKM,KAA6B,CACpC,MAAMgC,EAAyB,CAAED,QAAOE,OAAQ,GAAIC,SAAU,IAE9DxC,EAAKyC,WAAWvC,SAASwC,IACvB,MAAMC,EAAaD,EAcnB,GAT4B,aAAxBC,EAAWC,IAAIvC,MAAiD,oBAA1BsC,EAAWnC,MAAMF,OACzDgC,EAAUE,SAAWvE,KAAKgE,iBACxBU,EAAWnC,MAAM0B,SACjBC,EACAV,IAMsB,SAAxBkB,EAAWC,IAAIvC,MACW,4BAA1BsC,EAAWnC,MAAMF,KACjB,CAEA,MAAMuC,EAAaF,EAAWnC,MAAMsC,KAEpC,GAAwB,mBAApBD,EAAWvC,MAAwD,WAA3BuC,EAAWtB,OAAOjB,KAAmB,CAC/E,MAAOyC,GAAaF,EAAWrB,UAER,kBAAnBuB,EAAUzC,OACZgC,EAAUC,OAASQ,EAAUvC,QAMnC,GAA4B,cAAxBmC,EAAWC,IAAIvC,MAAkD,eAA1BsC,EAAWnC,MAAMF,KAAuB,CAEjF,MAAMV,EAAa+C,EAAWnC,MAAMH,MAC5BuB,KAAMoB,GAAeb,EAAWvC,IAAe,CAAE,EAErDoD,IACFV,EAAUC,OAASS,GAKvB,GAA4B,YAAxBL,EAAWC,IAAIvC,MAAgD,eAA1BsC,EAAWnC,MAAMF,KAAuB,CAG/E,MAAMV,EAAa+C,EAAWnC,OAAOyC,gBAAgB5C,MAAMA,MACnDuB,KAAMoB,GAAeb,EAAWvC,IAAe,CAAE,EAErDoD,IACFV,EAAUC,OAASS,GAIvB,GAA4B,aAAxBL,EAAWC,IAAIvC,MAAiD,eAA1BsC,EAAWnC,MAAMF,KAAuB,CAEhF,MAAMV,EAAa+C,EAAWnC,MAAMH,MAC5BuB,KAAMoB,EAAUE,UAAEA,GAAcf,EAAWvC,IAAe,CAAE,EAEpE,GAAIoD,EAAY,CACd,MAAMG,EAAmBlF,KAAKc,gBAAgBiE,EAAYvB,GAEtD0B,IACFb,EAAUE,SAAWvE,KAAKe,yBACxBmE,EACAD,EAAY,KAAOtD,UAOzB0C,EAAUC,QAAUD,EAAUE,SAAS3B,OAAS,IAClDuB,EAAQgB,KAAKd,OAKZF,EAMDiB,uBAAuB1D,GAC7B,MAAMwC,EAA0B,CAAE,EAelC,OAbAzE,EAASiC,EAAK,CACZE,kBAAkBC,GAChB,MAAMC,EAAaD,EAASE,KAE5BD,EAAWE,WAAWC,SAASC,IAC7BgC,EAAWhC,EAAUC,MAAMC,MAAQ,CACjCuB,KAAM7B,EAAWQ,OAAOC,MACxB0C,UAA8B,2BAAnB/C,EAAUG,KACtB,GAEJ,IAGI6B,EAMDnD,yBACNE,EACAL,EAA4B,MAE5B,IAAKK,EACH,MAAO,GAGT,MAAMS,EAAM1B,KAAKgB,UAAUC,GAE3B,IAAKS,EACH,MAAO,GAGT,MAAM2D,EAAarF,KAAKwC,qBAAqBd,EAAKd,GAC5CuD,EAAyB,GAE/B,IAAKkB,EACH,OAAOlB,EAGT,MAAMD,EAAavE,EAAY2F,gBAAgB5D,GAGzCuC,EAAWoB,EAAWrC,aAAa,GAAGuC,MAAMtB,SAIlD,OAFAE,EAAQgB,QAAQnF,KAAKgE,iBAAiBC,EAAUC,EAAYjD,IAErDkD,EAMDiB,4BACNvD,EACAqC,GAEArC,EAASE,KAAKyC,WAAWvC,SAASuD,IAChC,GAAIC,EAAiBD,IAAaE,EAAaF,EAASb,KAAM,CAC5D,GAA0B,YAAtBa,EAASb,IAAIvC,MAA4C,cAAtBoD,EAASb,IAAIvC,KAAsB,CACxE,IAAIuD,EAAgB,GAEhBC,EAAaJ,EAASjD,QAAUsD,EAAgBL,EAASjD,MAAMyC,eAAe5C,MAChFuD,EAAgBH,EAASjD,MAAMyC,eAAe5C,KAAKA,KAC1CsD,EAAaF,EAASjD,SAC/BoD,EAAgBH,EAASjD,MAAMH,MAGjC,MAAM0D,EAASjE,EAASkE,YAAYC,GAAMC,EAAkBD,EAAEjE,QACxDJ,EAAauC,EAAWyB,IAAgBhC,KAE9C,GAAImC,GAAUnE,EAAY,CACxB,MAAMuE,EAAiBC,EAAeC,EAAW,UAAWC,EAAc1E,IAG1EE,EAASE,KAAKyC,WAAW8B,OACvBzE,EAASE,KAAKyC,WAAW+B,QAAQf,GAAY,EAC7C,EACAU,IAKoB,aAAtBV,EAASb,IAAIvC,MAAuB6D,EAAkBT,EAASjD,QAEjEiD,EAASjD,MAAM0B,SAAShC,SAASuE,IAC3BC,EAAmBD,IACrB7G,EAAY+G,qBACV,CAAE3E,KAAMyE,GACRtC,UAYPkB,oBAAoBlE,GACzB,IAAKA,EACH,OAAOA,EAGT,MAAMQ,EAAML,EAAOnB,MAAMgB,EAAM,CAC7BI,WAAY,SACZC,QAAS,CAAC,aAAc,SAG1B,IAAKG,EACH,OAAOR,EAGT,MAAMgD,EAAavE,EAAY2F,gBAAgB5D,GAQ/C,OANAjC,EAASiC,EAAK,CACZiF,iBAAiB9E,GACflC,EAAY+G,qBAAqB7E,EAAUqC,EAC5C,IAGI5E,EAASoC,EAAK,CACnBkF,aAAa,IACZ1F"}
@@ -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,KACrE,CAKMC,aACL,MAAMC,EAAkC,CAAA,EAUxC,OARAL,KAAKH,aAAaS,SAAQ,EAAGC,OAAMC,kBACb,iBAATD,IAIXF,EAAQE,GAAQC,EAAW,IAGtBH,CACR,CAKMI,mBACL,MAAO,CAAC,GAAI,UACTC,KAAKC,GAAW,CAAC,GAAI,MAAO,MAAO,QAAQD,KAAKE,GAAQ,GAAGD,IAASC,QACpEC,MACJ,CAKMC,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,IAElD,CAKD,OAFAH,EAAWA,EAASI,MAAMF,EAAKI,MAAMC,KAAKC,KAAKN,EAAKO,MAAMF,KAEtDV,EACKG,EAGFA,EAASK,QAAQP,EAAM,IAAIO,QAAQ,eAAgB,GAC3D,CAKMK,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,CAEV,CAED,OAAO,IACR"}
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,CACnC,CAKMC,YAAYV,EAAsBC,GACvC,OAAO,IAAIF,EAAcC,EAAQC,EAClC,CAKMU,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,OAML,CAAC,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,CACP,EAEIhB,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,CAAA,EAWT,OATAQ,KAAKN,WAAa,CAChBsC,SACAC,SACAC,gBACGK,GAELvC,KAAKL,gBAAkBA,EACvBK,KAAKJ,gBAAkBA,EAEhBI,KAAKN,UACb,CAKMS,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,KAE3C,CAED,OAAOP,EAAaU,MAAM,0BAC3B,CAKMpD,qBAIL,aAHMH,KAAKwD,uBACLxD,KAAKL,kBAAkBK,KAAKR,OAAOiE,SAAWzD,KAAKP,YAElDO,IACR,CAKM0D,uBACL,MAAMC,YAAEA,EAAWC,cAAEA,GAAkB5D,KAAKF,oBAAsB,CAAA,EAElE,MAAO,CACL6D,aACkB,IAAhBA,GACI,IACMA,GAAe,CAAA,GAG3BC,eACoB,IAAlBA,GACI,IACMA,GAAiB,CAAA,EACrBC,SAAUD,GAAeC,UAAY,KAIhD"}
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,gBACb,CAKMG,sBAAsBC,GAC3BF,KAAKF,iBAAmBI,CACzB"}
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":"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"}
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 +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 { 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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"}