@lomray/vite-ssr-boost 2.3.2 → 2.3.3-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,44 @@
1
+ interface IDevActionParams {
2
+ host?: boolean;
3
+ resetCache?: boolean;
4
+ mode?: string;
5
+ }
6
+ interface IBuildActionParams {
7
+ onlyClient?: boolean;
8
+ clientOptions?: string;
9
+ serverOptions?: string;
10
+ mode?: string;
11
+ unlockRobots?: boolean;
12
+ eject?: boolean;
13
+ serverless?: boolean;
14
+ throwWarnings?: boolean;
15
+ }
16
+ interface IStartActionParams {
17
+ host?: boolean;
18
+ port?: number;
19
+ onlyClient?: boolean;
20
+ modulePreload?: boolean;
21
+ buildDir?: string;
22
+ }
23
+ interface IPreviewActionParams extends IStartActionParams {
24
+ mode?: string;
25
+ }
26
+ interface IBuildDockerActionParams {
27
+ imageName: string;
28
+ dockerOptions?: string;
29
+ dockerFile?: string;
30
+ onlyClient?: boolean;
31
+ mode?: string;
32
+ }
33
+ interface IBuildAmplifyActionParams {
34
+ manifestFile?: string;
35
+ mode?: string;
36
+ isOptimize?: boolean;
37
+ }
38
+ interface IBuildVercelActionParams {
39
+ configFile?: string;
40
+ configVcFile?: string;
41
+ mode?: string;
42
+ isOptimize?: boolean;
43
+ }
44
+ export { IDevActionParams, IBuildActionParams, IStartActionParams, IPreviewActionParams, IBuildDockerActionParams, IBuildAmplifyActionParams, IBuildVercelActionParams };
@@ -0,0 +1,2 @@
1
+
2
+ //# sourceMappingURL=actions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"actions.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}
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 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 onlyClientOption = new Option('--only-client', 'Build/run only client side part.').default(\n false,\n);\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(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 .action(async ({ host, resetCache, mode }) => {\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({ version, isHost: host, isPrintInfo, mode });\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(onlyClientOption)\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 onlyClient,\n clientOptions,\n serverOptions,\n mode,\n unlockRobots,\n eject,\n serverless,\n throwWarnings,\n }) => {\n await runBuild({\n isOnlyClient: onlyClient,\n isUnlockRobots: unlockRobots,\n isNoWarnings: throwWarnings,\n isEject: eject,\n isServerless: serverless,\n clientOptions,\n serverOptions,\n mode,\n });\n },\n );\n\nprogram\n .command(CliActions.start)\n .description('Run production server.')\n .addOption(hostOption)\n .addOption(portOption)\n .addOption(onlyClientOption)\n .addOption(buildDirOption)\n .addOption(\n new Option('--module-preload', 'Add module preload scripts to server output.').default(false),\n )\n .action(({ host, port, onlyClient, modulePreload, buildDir }) => {\n const command = async (isPrintInfo?: boolean): Promise<void> => {\n const { server, config } = await runProd({\n version,\n isHost: host,\n isPrintInfo,\n port,\n onlyClient,\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(onlyClientOption)\n .addOption(hostOption)\n .addOption(portOption)\n .addOption(envModeOption)\n .addOption(buildDirOption)\n .action(async ({ host, port, onlyClient, mode, buildDir }) => {\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 onlyClient,\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,\n isWatch: true,\n isOnlyClient: onlyClient,\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(onlyClientOption)\n .addOption(envModeOption)\n .action(async ({ imageName, dockerOptions, dockerFile, onlyClient, mode }) => {\n await runDockerBuild({\n imageName,\n dockerOptions,\n dockerFile,\n isOnlyClient: onlyClient,\n mode,\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 }) => {\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 }) => {\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","onlyClientOption","portOption","envModeOption","env","buildDirOption","command","CliActions","dev","addOption","action","async","host","resetCache","mode","viteResetCache","isPrintInfo","console","info","chalk","cyan","server","config","runDev","isHost","cliContext","reboot","build","onlyClient","clientOptions","serverOptions","unlockRobots","eject","serverless","throwWarnings","runBuild","isOnlyClient","isUnlockRobots","isNoWarnings","isEject","isServerless","start","port","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":";6hBAoBA,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,EAAmB,IAAIF,EAAO,gBAAiB,oCAAoCC,SACvF,GAEIE,EAAa,IAAIH,EAAO,gBAAiB,gBAAgBC,QAAQ,KACjEG,EAAgB,IAAIJ,EAAO,gBAAiB,aAC/CK,IAAI,iBACJJ,QAAQ,cACLK,EAAiB,IAAIN,EAAO,yBAA0B,2BAM5DV,EACGiB,QAAQC,EAAWC,KACnBnC,YAAY,2BACZoC,UAAUX,GACVW,UAAU,IAAIV,EAAO,gBAAiB,gCAAgCC,SAAQ,IAC9ES,UAAU,IAAIV,EAAO,gBAAiB,aAAaK,IAAI,iBAAiBJ,QAAQ,gBAChFU,QAAOC,OAASC,OAAMC,aAAYC,WAC7BD,SACIE,IAGR,MAAMT,EAAUK,MAAOK,IACrBC,QAAQC,KAAKC,EAAMC,KAAK,uCAExB,MAAMC,OAAEA,EAAMC,OAAEA,SAAiBC,EAAO,CAAEjD,UAASkD,OAAQZ,EAAMI,cAAaF,SAE9EW,EAAWJ,OAASA,EACpBI,EAAWH,OAASA,CAAM,EAO5B,OAJAG,EAAWC,OAASpB,EAEpB1B,IAEO0B,GAAS,IAGpBjB,EACGiB,QAAQC,EAAWoB,OACnBtD,YAAY,4BACZoC,UAAUR,GACVQ,UAAUN,GACVM,UACC,IAAIV,EACF,oCACA,iFAECK,IAAI,6BACJJ,QAAQ,KAEZS,UACC,IAAIV,EAAO,oCAAqC,uCAC7CK,IAAI,6BACJJ,QAAQ,KAEZS,UACC,IAAIV,EACF,kBACA,4DACAC,SAAQ,IAEXS,UACC,IAAIV,EAAO,UAAW,mDAAmDC,SAAQ,IAElFS,UACC,IAAIV,EACF,eACA,gEACAC,SAAQ,IAEXS,UACC,IAAIV,EACF,mBACA,wEACAC,SAAQ,IAEXU,QACCC,OACEiB,aACAC,gBACAC,gBACAhB,OACAiB,eACAC,QACAC,aACAC,0BAEMC,EAAS,CACbC,aAAcR,EACdS,eAAgBN,EAChBO,aAAcJ,EACdK,QAASP,EACTQ,aAAcP,EACdJ,gBACAC,gBACAhB,QACA,IAIRzB,EACGiB,QAAQC,EAAWkC,OACnBpE,YAAY,0BACZoC,UAAUX,GACVW,UAAUP,GACVO,UAAUR,GACVQ,UAAUJ,GACVI,UACC,IAAIV,EAAO,mBAAoB,gDAAgDC,SAAQ,IAExFU,QAAO,EAAGE,OAAM8B,OAAMd,aAAYe,gBAAeC,eAChD,MAAMtC,EAAUK,MAAOK,IACrB,MAAMK,OAAEA,EAAMC,OAAEA,SAAiBuB,EAAQ,CACvCvE,UACAkD,OAAQZ,EACRI,cACA0B,OACAd,aACAe,gBACAC,aAGFnB,EAAWJ,OAASA,EACpBI,EAAWH,OAASA,CAAM,EAO5B,OAJAG,EAAWC,OAASpB,EAEpB1B,IAEO0B,GAAS,IAGpBjB,EACGiB,QAAQC,EAAWuC,SACnBzE,YAAY,iCACZoC,UAAUR,GACVQ,UAAUX,GACVW,UAAUP,GACVO,UAAUN,GACVM,UAAUJ,GACVK,QAAOC,OAASC,OAAM8B,OAAMd,aAAYd,OAAM8B,eAC7ChD,OAAOmD,mBAAqBC,YAAYC,MAExC,MAAM3C,EAAUK,MAAOK,IACrB,MAAMK,OAAEA,EAAMC,OAAEA,SAAiBuB,EAAQ,CACvCvE,UACAkD,OAAQZ,EACRI,cACA0B,OACAd,aACAgB,aAGFvB,EAAOpC,GAAG,aAAa,KACrBiE,YAAW,KACT5B,EAAO6B,YAAYjC,KAAKC,EAAMiC,OAAO,kCAAkC,GACtE,EAAE,IAGP3B,EAAWJ,OAASA,EACpBI,EAAWH,OAASA,CAAM,EAG5BG,EAAWC,OAASpB,EAEpB1B,UAIMuD,EAAS,CACbrB,OACAuC,SAAS,EACTjB,aAAcR,EACdC,cANmB,KAOnBC,cAPmB,KAQnBwB,SAAU,KACHhD,GAAS,GAEhB,IAGNjB,EACGiB,QAAQC,EAAWgD,aACnBlF,YAAY,8CACZmF,eAAe,4BAA6B,sBAC5C/C,UACC,IAAIV,EACF,oCACA,6DAGHU,UACC,IAAIV,EACF,8BACA,yEAGHU,UAAUR,GACVQ,UAAUN,GACVO,QAAOC,OAAS8C,YAAWC,gBAAeC,aAAY/B,aAAYd,iBAC3D8C,EAAe,CACnBH,YACAC,gBACAC,aACAvB,aAAcR,EACdd,QACA,IAGNzB,EACGiB,QAAQC,EAAWsD,cACnBxF,YAAY,wCACZoC,UACC,IAAIV,EACF,kCACA,+FAGHU,UAAU,IAAIV,EAAO,gBAAiB,iCAAiCC,SAAQ,IAC/ES,UAAUN,GACVO,QAAOC,OAASmD,eAAchD,OAAMiD,uBAC7BC,EAAgB,CACpBF,eACAhD,OACAiD,cACA,IAGN1E,EACGiB,QAAQC,EAAW0D,aACnB5F,YAAY,8CACZoC,UACC,IAAIV,EACF,8BACA,8FAGHU,UACC,IAAIV,EACF,oCACA,oGAGHU,UAAU,IAAIV,EAAO,gBAAiB,iCAAiCC,SAAQ,IAC/ES,UAAUN,GACVO,QAAOC,OAASuD,aAAYC,eAAcrD,OAAMiD,uBACzCK,EAAe,CACnBF,aACAC,eACArD,OACAiD,cACA,IAGN1E,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 onlyClientOption = new Option('--only-client', 'Build/run only client side part.').default(\n false,\n);\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(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 .action(async ({ host, resetCache, mode }: 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 mode,\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(onlyClientOption)\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 onlyClient,\n clientOptions,\n serverOptions,\n mode,\n unlockRobots,\n eject,\n serverless,\n throwWarnings,\n }: IBuildActionParams) => {\n await runBuild({\n isOnlyClient: onlyClient,\n isUnlockRobots: unlockRobots,\n isNoWarnings: throwWarnings,\n isEject: eject,\n isServerless: serverless,\n clientOptions,\n serverOptions,\n mode,\n });\n },\n );\n\nprogram\n .command(CliActions.start)\n .description('Run production server.')\n .addOption(hostOption)\n .addOption(portOption)\n .addOption(onlyClientOption)\n .addOption(buildDirOption)\n .addOption(\n new Option('--module-preload', 'Add module preload scripts to server output.').default(false),\n )\n .action(({ host, port, onlyClient, 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 onlyClient,\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(onlyClientOption)\n .addOption(hostOption)\n .addOption(portOption)\n .addOption(envModeOption)\n .addOption(buildDirOption)\n .action(async ({ host, port, onlyClient, 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 onlyClient,\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,\n isWatch: true,\n isOnlyClient: onlyClient,\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(onlyClientOption)\n .addOption(envModeOption)\n .action(\n async ({\n imageName,\n dockerOptions,\n dockerFile,\n onlyClient,\n mode,\n }: IBuildDockerActionParams) => {\n await runDockerBuild({\n imageName,\n dockerOptions,\n dockerFile,\n isOnlyClient: onlyClient,\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","onlyClientOption","portOption","envModeOption","env","buildDirOption","command","CliActions","dev","addOption","action","async","host","resetCache","mode","viteResetCache","isPrintInfo","console","info","chalk","cyan","server","config","runDev","isHost","cliContext","reboot","build","onlyClient","clientOptions","serverOptions","unlockRobots","eject","serverless","throwWarnings","runBuild","isOnlyClient","isUnlockRobots","isNoWarnings","isEject","isServerless","start","port","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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"}
@@ -5,10 +5,11 @@ interface IOnlyClient<T> {
5
5
  } | ComponentType<T>>;
6
6
  children: (Component: ComponentType<T>) => ReactNode;
7
7
  fallback?: ReactNode;
8
+ errorComponent?: ReactNode;
8
9
  }
9
10
  /**
10
11
  * Render component only on client side
11
12
  * @constructor
12
13
  */
13
- declare function OnlyClient<T>({ load, children, fallback }: IOnlyClient<T>): ReactNode;
14
+ declare function OnlyClient<T>({ load, children, fallback, errorComponent, }: IOnlyClient<T>): ReactNode;
14
15
  export { OnlyClient as default };
@@ -1,2 +1,2 @@
1
- import e,{useState as l,useEffect as t,startTransition as n,lazy as a}from"react";function o({load:o,children:c,fallback:d}){const[r,i]=l(null);return t((()=>{n((()=>{const l=a((()=>o().then((e=>({default:()=>c("default"in e?e.default:e)}))).catch((l=>(console.error("Client side component loading failed:",l),{default:()=>e.createElement("p",null,"Failed to load client side component.")})))));i(l)}))}),[]),r?e.createElement(r,null):d}export{o as default};
1
+ import e,{useState as t,useEffect as l,startTransition as n,lazy as o}from"react";const a=e.createElement("p",null,"Failed to load client side component.");function c({load:c,children:r,fallback:d,errorComponent:i=a}){const[u,f]=t(null);return l((()=>{n((()=>{const e=o((()=>c().then((e=>({default:()=>r("default"in e?e.default:e)}))).catch((e=>(console.error("Client side component loading failed:",e),{default:()=>i})))));f(e)}))}),[]),u?e.createElement(u,null):d}export{c as default};
2
2
  //# sourceMappingURL=only-client.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"only-client.js","sources":["../../src/components/only-client.tsx"],"sourcesContent":["import type { ComponentType, ReactNode } from 'react';\nimport React, { lazy, startTransition, useEffect, useState } from 'react';\n\ninterface IOnlyClient<T> {\n load: () => Promise<{ default: ComponentType<T> } | ComponentType<T>>;\n children: (Component: ComponentType<T>) => ReactNode;\n fallback?: ReactNode;\n}\n\n/**\n * Render component only on client side\n * @constructor\n */\nfunction OnlyClient<T>({ load, children, fallback }: IOnlyClient<T>): ReactNode {\n const [Component, setComponent] = useState<ComponentType<unknown> | null>(null);\n\n useEffect(() => {\n startTransition(() => {\n const LoadedComponent = lazy(() =>\n load()\n .then((Loaded) => ({\n default: () => children('default' in Loaded ? Loaded.default : Loaded),\n }))\n .catch((error: Error) => {\n console.error('Client side component loading failed:', error);\n\n return { default: () => <p>Failed to load client side component.</p> };\n }),\n );\n\n setComponent(LoadedComponent);\n });\n }, []);\n\n return Component ? <Component /> : fallback;\n}\n\nexport default OnlyClient;\n"],"names":["OnlyClient","load","children","fallback","Component","setComponent","useState","useEffect","startTransition","LoadedComponent","lazy","then","Loaded","default","catch","error","console","React","createElement"],"mappings":"kFAaA,SAASA,GAAcC,KAAEA,EAAIC,SAAEA,EAAQC,SAAEA,IACvC,MAAOC,EAAWC,GAAgBC,EAAwC,MAoB1E,OAlBAC,GAAU,KACRC,GAAgB,KACd,MAAMC,EAAkBC,GAAK,IAC3BT,IACGU,MAAMC,IAAY,CACjBC,QAAS,IAAMX,EAAS,YAAaU,EAASA,EAAOC,QAAUD,OAEhEE,OAAOC,IACNC,QAAQD,MAAM,wCAAyCA,GAEhD,CAAEF,QAAS,IAAMI,EAAAC,cAAA,IAAA,KAAA,+CAI9Bb,EAAaI,EAAgB,GAC7B,GACD,IAEIL,EAAYa,EAAAC,cAACd,EAAS,MAAMD,CACrC"}
1
+ {"version":3,"file":"only-client.js","sources":["../../src/components/only-client.tsx"],"sourcesContent":["import type { ComponentType, ReactNode } from 'react';\nimport React, { lazy, startTransition, useEffect, useState } from 'react';\n\ninterface IOnlyClient<T> {\n load: () => Promise<{ default: ComponentType<T> } | ComponentType<T>>;\n children: (Component: ComponentType<T>) => ReactNode;\n fallback?: ReactNode;\n errorComponent?: ReactNode;\n}\n\nconst defaultError = <p>Failed to load client side component.</p>;\n\n/**\n * Render component only on client side\n * @constructor\n */\nfunction OnlyClient<T>({\n load,\n children,\n fallback,\n errorComponent = defaultError,\n}: IOnlyClient<T>): ReactNode {\n const [Component, setComponent] = useState<ComponentType<unknown> | null>(null);\n\n useEffect(() => {\n startTransition(() => {\n const LoadedComponent = lazy(() =>\n load()\n .then((Loaded) => ({\n default: () => children('default' in Loaded ? Loaded.default : Loaded),\n }))\n .catch((error: Error) => {\n console.error('Client side component loading failed:', error);\n\n return { default: () => errorComponent };\n }),\n );\n\n setComponent(LoadedComponent);\n });\n }, []);\n\n return Component ? <Component /> : fallback;\n}\n\nexport default OnlyClient;\n"],"names":["defaultError","React","createElement","OnlyClient","load","children","fallback","errorComponent","Component","setComponent","useState","useEffect","startTransition","LoadedComponent","lazy","then","Loaded","default","catch","error","console"],"mappings":"kFAUA,MAAMA,EAAeC,EAAAC,cAAA,IAAA,KAAA,yCAMrB,SAASC,GAAcC,KACrBA,EAAIC,SACJA,EAAQC,SACRA,EAAQC,eACRA,EAAiBP,IAEjB,MAAOQ,EAAWC,GAAgBC,EAAwC,MAoB1E,OAlBAC,GAAU,KACRC,GAAgB,KACd,MAAMC,EAAkBC,GAAK,IAC3BV,IACGW,MAAMC,IAAY,CACjBC,QAAS,IAAMZ,EAAS,YAAaW,EAASA,EAAOC,QAAUD,OAEhEE,OAAOC,IACNC,QAAQD,MAAM,wCAAyCA,GAEhD,CAAEF,QAAS,IAAMV,QAI9BE,EAAaI,EAAgB,GAC7B,GACD,IAEIL,EAAYP,EAAAC,cAACM,EAAS,MAAMF,CACrC"}
@@ -1,2 +1,2 @@
1
- declare const IS_SSR_MODE: any;
1
+ declare const IS_SSR_MODE: boolean;
2
2
  export { IS_SSR_MODE };
@@ -1 +1 @@
1
- {"version":3,"file":"common.js","sources":["../../src/constants/common.ts"],"sourcesContent":["/* eslint-disable no-undef */\n// @ts-ignore\nconst IS_SSR_MODE = typeof __IS_SSR__ === 'undefined' ? true : __IS_SSR__; // build in SSR mode?\n\n// eslint-disable-next-line import/prefer-default-export\nexport { IS_SSR_MODE };\n"],"names":["IS_SSR_MODE","__IS_SSR__"],"mappings":"AAEA,MAAMA,EAAoC,oBAAfC,YAAoCA"}
1
+ {"version":3,"file":"common.js","sources":["../../src/constants/common.ts"],"sourcesContent":["/* eslint-disable no-undef */\n// @ts-ignore\nconst IS_SSR_MODE = (typeof __IS_SSR__ === 'undefined' ? true : __IS_SSR__) as boolean; // build in SSR mode?\n\n// eslint-disable-next-line import/prefer-default-export\nexport { IS_SSR_MODE };\n"],"names":["IS_SSR_MODE","__IS_SSR__"],"mappings":"AAEA,MAAMA,EAAqC,oBAAfC,YAAoCA"}
@@ -1 +1 @@
1
- {"version":3,"file":"build-router-state.js","sources":["../../src/helpers/build-router-state.ts"],"sourcesContent":["import type { StaticHandlerContext } from 'react-router-dom/server';\nimport serializeErrors from '@helpers/serialize-errors';\n\n/**\n * Build router state\n */\nfunction buildRouterState(context: StaticHandlerContext): string {\n const { loaderData, actionData, errors } = context as StaticHandlerContext;\n const routerState = {\n loaderData,\n actionData,\n errors: serializeErrors(errors),\n };\n const json = JSON.stringify(routerState);\n\n return `<script async>window.__staticRouterHydrationData = ${json};</script>`;\n}\n\nexport default buildRouterState;\n"],"names":["buildRouterState","context","loaderData","actionData","errors","routerState","serializeErrors","JSON","stringify"],"mappings":"qCAMA,SAASA,EAAiBC,GACxB,MAAMC,WAAEA,EAAUC,WAAEA,EAAUC,OAAEA,GAAWH,EACrCI,EAAc,CAClBH,aACAC,aACAC,OAAQE,EAAgBF,IAI1B,MAAO,sDAFMG,KAAKC,UAAUH,eAG9B"}
1
+ {"version":3,"file":"build-router-state.js","sources":["../../src/helpers/build-router-state.ts"],"sourcesContent":["import type { StaticHandlerContext } from 'react-router-dom/server';\nimport serializeErrors from '@helpers/serialize-errors';\n\n/**\n * Build router state\n */\nfunction buildRouterState(context: StaticHandlerContext): string {\n const { loaderData, actionData, errors } = context;\n const routerState = {\n loaderData,\n actionData,\n errors: serializeErrors(errors),\n };\n const json = JSON.stringify(routerState);\n\n return `<script async>window.__staticRouterHydrationData = ${json};</script>`;\n}\n\nexport default buildRouterState;\n"],"names":["buildRouterState","context","loaderData","actionData","errors","routerState","serializeErrors","JSON","stringify"],"mappings":"qCAMA,SAASA,EAAiBC,GACxB,MAAMC,WAAEA,EAAUC,WAAEA,EAAUC,OAAEA,GAAWH,EACrCI,EAAc,CAClBH,aACAC,aACAC,OAAQE,EAAgBF,IAI1B,MAAO,sDAFMG,KAAKC,UAAUH,eAG9B"}
@@ -1 +1 @@
1
- {"version":3,"file":"import-route.js","sources":["../../src/helpers/import-route.ts"],"sourcesContent":["import type { ImmutableRouteKey } from '@remix-run/router/utils';\nimport type { IndexRouteObject, NonIndexRouteObject } from 'react-router-dom';\nimport withSuspense from '@components/with-suspense';\nimport type { FCCRoute, FCRoute } from '@interfaces/fc-route';\nimport { keys } from '@interfaces/fc-route';\n\nexport type IDynamicRoute = () => Promise<{ default: FCRoute | FCCRoute<any> }>;\n\nexport type IAsyncRoute = { pathId?: string } & (\n | Omit<IndexRouteObject, ImmutableRouteKey>\n | Omit<NonIndexRouteObject, ImmutableRouteKey>\n);\n\n/**\n * Import dynamic route\n */\nconst importRoute = async (route: IDynamicRoute, id?: string): Promise<IAsyncRoute> => {\n const resolved = await route();\n\n // fallback to react router export style\n if ('Component' in resolved) {\n return { ...resolved, pathId: id } as IAsyncRoute;\n }\n\n const Component = resolved.default;\n const result: IAsyncRoute = { Component, pathId: id };\n\n keys.forEach((key) => {\n if (Component[key]) {\n result[key] = Component[key] as any;\n }\n });\n\n if (Component.Suspense) {\n result.Component = withSuspense(Component, Component.Suspense);\n }\n\n return result;\n};\n\nexport default importRoute;\n"],"names":["importRoute","async","route","id","resolved","pathId","Component","default","result","keys","forEach","key","Suspense","withSuspense"],"mappings":"+FAgBM,MAAAA,EAAcC,MAAOC,EAAsBC,KAC/C,MAAMC,QAAiBF,IAGvB,GAAI,cAAeE,EACjB,MAAO,IAAKA,EAAUC,OAAQF,GAGhC,MAAMG,EAAYF,EAASG,QACrBC,EAAsB,CAAEF,YAAWD,OAAQF,GAYjD,OAVAM,EAAKC,SAASC,IACRL,EAAUK,KACZH,EAAOG,GAAOL,EAAUK,GACzB,IAGCL,EAAUM,WACZJ,EAAOF,UAAYO,EAAaP,EAAWA,EAAUM,WAGhDJ,CAAM"}
1
+ {"version":3,"file":"import-route.js","sources":["../../src/helpers/import-route.ts"],"sourcesContent":["import type { ImmutableRouteKey } from '@remix-run/router/utils';\nimport type { IndexRouteObject, NonIndexRouteObject } from 'react-router-dom';\nimport withSuspense from '@components/with-suspense';\nimport type { FCCRoute, FCRoute } from '@interfaces/fc-route';\nimport { keys } from '@interfaces/fc-route';\n\nexport type IDynamicRoute = () => Promise<{ default: FCRoute | FCCRoute<any> }>;\n\nexport type IAsyncRoute = { pathId?: string } & (\n | Omit<IndexRouteObject, ImmutableRouteKey>\n | Omit<NonIndexRouteObject, ImmutableRouteKey>\n);\n\n/**\n * Import dynamic route\n */\nconst importRoute = async (route: IDynamicRoute, id?: string): Promise<IAsyncRoute> => {\n const resolved = await route();\n\n // fallback to react router export style\n if ('Component' in resolved) {\n return { ...resolved, pathId: id } as IAsyncRoute;\n }\n\n const Component = resolved.default;\n const result: IAsyncRoute = { Component, pathId: id };\n\n keys.forEach((key) => {\n if (Component[key]) {\n // @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\nexport default importRoute;\n"],"names":["importRoute","async","route","id","resolved","pathId","Component","default","result","keys","forEach","key","Suspense","withSuspense"],"mappings":"+FAgBM,MAAAA,EAAcC,MAAOC,EAAsBC,KAC/C,MAAMC,QAAiBF,IAGvB,GAAI,cAAeE,EACjB,MAAO,IAAKA,EAAUC,OAAQF,GAGhC,MAAMG,EAAYF,EAASG,QACrBC,EAAsB,CAAEF,YAAWD,OAAQF,GAajD,OAXAM,EAAKC,SAASC,IACRL,EAAUK,KAEZH,EAAOG,GAAOL,EAAUK,GACzB,IAGCL,EAAUM,WACZJ,EAAOF,UAAYO,EAAaP,EAAWA,EAAUM,WAGhDJ,CAAM"}
@@ -1 +1 @@
1
- {"version":3,"file":"obtain-stream-error.js","sources":["../../src/helpers/obtain-stream-error.ts"],"sourcesContent":["import StreamError from '@constants/stream-error';\n\nexport interface IObtainStreamErrorOut {\n code: StreamError;\n message: string;\n original: unknown;\n}\n\n/**\n * Get react stream error\n */\nconst obtainStreamError = (err: unknown): IObtainStreamErrorOut => {\n const message = ((err as Record<string, any>)?.message ?? 'Unknown.').replace('Error: ', '');\n\n if (message === 'The render was aborted by the server without a reason.') {\n return {\n code: StreamError.RenderAborted,\n message,\n original: err,\n };\n }\n\n return {\n code: StreamError.Unknown,\n message: message || 'Unknown error',\n original: err,\n };\n};\n\nexport default obtainStreamError;\n"],"names":["obtainStreamError","err","message","replace","code","StreamError","RenderAborted","original","Unknown"],"mappings":"4CAWA,MAAMA,EAAqBC,IACzB,MAAMC,GAAYD,GAA6BC,SAAW,YAAYC,QAAQ,UAAW,IAEzF,MAAgB,2DAAZD,EACK,CACLE,KAAMC,EAAYC,cAClBJ,UACAK,SAAUN,GAIP,CACLG,KAAMC,EAAYG,QAClBN,QAASA,GAAW,gBACpBK,SAAUN,EACX"}
1
+ {"version":3,"file":"obtain-stream-error.js","sources":["../../src/helpers/obtain-stream-error.ts"],"sourcesContent":["import StreamError from '@constants/stream-error';\n\nexport interface IObtainStreamErrorOut {\n code: StreamError;\n message: string;\n original: unknown;\n}\n\n/**\n * Get react stream error\n */\nconst obtainStreamError = (err: unknown): IObtainStreamErrorOut => {\n const message = ((err as Error)?.message ?? 'Unknown.').replace('Error: ', '');\n\n if (message === 'The render was aborted by the server without a reason.') {\n return {\n code: StreamError.RenderAborted,\n message,\n original: err,\n };\n }\n\n return {\n code: StreamError.Unknown,\n message: message || 'Unknown error',\n original: err,\n };\n};\n\nexport default obtainStreamError;\n"],"names":["obtainStreamError","err","message","replace","code","StreamError","RenderAborted","original","Unknown"],"mappings":"4CAWA,MAAMA,EAAqBC,IACzB,MAAMC,GAAYD,GAAeC,SAAW,YAAYC,QAAQ,UAAW,IAE3E,MAAgB,2DAAZD,EACK,CACLE,KAAMC,EAAYC,cAClBJ,UACAK,SAAUN,GAIP,CACLG,KAAMC,EAAYG,QAClBN,QAASA,GAAW,gBACpBK,SAAUN,EACX"}
@@ -1 +1 @@
1
- {"version":3,"file":"serialize-errors.js","sources":["../../src/helpers/serialize-errors.ts"],"sourcesContent":["import { isRouteErrorResponse } from 'react-router-dom';\nimport type { StaticHandlerContext } from 'react-router-dom/server';\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 */\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;\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":"wDAOA,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-dom';\nimport type { StaticHandlerContext } from 'react-router-dom/server';\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 */\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":"wDAOA,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 +1 @@
1
- {"version":3,"file":"create-fetch-request.js","sources":["../../src/node/create-fetch-request.ts"],"sourcesContent":["import type { Request as ExpressRequest } from 'express';\n\n/**\n * Convert the incoming Express request into a Fetch request, which is what the static handler methods operate on.\n * @see https://reactrouter.com/en/main/guides/ssr\n */\nfunction createFetchRequest(req: ExpressRequest): Request {\n const origin = `${req.protocol}://${req.get('host') as string}`;\n // Note: This had to take originalUrl into account for presumably vite's proxying\n const url = new URL(req.originalUrl || req.url, origin);\n const controller = new AbortController();\n\n req.on('close', () => controller.abort());\n\n const headers = new Headers();\n\n for (const [key, values] of Object.entries(req.headers)) {\n if (values) {\n if (Array.isArray(values)) {\n for (const value of values) {\n headers.append(key, value);\n }\n } else {\n headers.set(key, values);\n }\n }\n }\n\n const init = {\n method: req.method,\n headers,\n signal: controller.signal,\n body: undefined,\n };\n\n if (req.method !== 'GET' && req.method !== 'HEAD') {\n init.body = req.body;\n }\n\n return new Request(url.href, init);\n}\n\nexport default createFetchRequest;\n"],"names":["createFetchRequest","req","origin","protocol","get","url","URL","originalUrl","controller","AbortController","on","abort","headers","Headers","key","values","Object","entries","Array","isArray","value","append","set","init","method","signal","body","undefined","Request","href"],"mappings":"AAMA,SAASA,EAAmBC,GAC1B,MAAMC,EAAS,GAAGD,EAAIE,cAAcF,EAAIG,IAAI,UAEtCC,EAAM,IAAIC,IAAIL,EAAIM,aAAeN,EAAII,IAAKH,GAC1CM,EAAa,IAAIC,gBAEvBR,EAAIS,GAAG,SAAS,IAAMF,EAAWG,UAEjC,MAAMC,EAAU,IAAIC,QAEpB,IAAK,MAAOC,EAAKC,KAAWC,OAAOC,QAAQhB,EAAIW,SAC7C,GAAIG,EACF,GAAIG,MAAMC,QAAQJ,GAChB,IAAK,MAAMK,KAASL,EAClBH,EAAQS,OAAOP,EAAKM,QAGtBR,EAAQU,IAAIR,EAAKC,GAKvB,MAAMQ,EAAO,CACXC,OAAQvB,EAAIuB,OACZZ,UACAa,OAAQjB,EAAWiB,OACnBC,UAAMC,GAOR,MAJmB,QAAf1B,EAAIuB,QAAmC,SAAfvB,EAAIuB,SAC9BD,EAAKG,KAAOzB,EAAIyB,MAGX,IAAIE,QAAQvB,EAAIwB,KAAMN,EAC/B"}
1
+ {"version":3,"file":"create-fetch-request.js","sources":["../../src/node/create-fetch-request.ts"],"sourcesContent":["import type { Request as ExpressRequest } from 'express';\n\n/**\n * Convert the incoming Express request into a Fetch request, which is what the static handler methods operate on.\n * @see https://reactrouter.com/en/main/guides/ssr\n */\nfunction createFetchRequest(req: ExpressRequest): Request {\n const origin = `${req.protocol}://${req.get('host') as string}`;\n // Note: This had to take originalUrl into account for presumably vite's proxying\n const url = new URL(req.originalUrl || req.url, origin);\n const controller = new AbortController();\n\n req.on('close', () => controller.abort());\n\n const headers = new Headers();\n\n for (const [key, values] of Object.entries(req.headers)) {\n if (values) {\n if (Array.isArray(values)) {\n for (const value of values) {\n headers.append(key, value);\n }\n } else {\n headers.set(key, values);\n }\n }\n }\n\n const init: RequestInit = {\n method: req.method,\n headers,\n signal: controller.signal,\n body: undefined,\n };\n\n if (req.method !== 'GET' && req.method !== 'HEAD') {\n init.body = req.body as BodyInit;\n }\n\n return new Request(url.href, init);\n}\n\nexport default createFetchRequest;\n"],"names":["createFetchRequest","req","origin","protocol","get","url","URL","originalUrl","controller","AbortController","on","abort","headers","Headers","key","values","Object","entries","Array","isArray","value","append","set","init","method","signal","body","undefined","Request","href"],"mappings":"AAMA,SAASA,EAAmBC,GAC1B,MAAMC,EAAS,GAAGD,EAAIE,cAAcF,EAAIG,IAAI,UAEtCC,EAAM,IAAIC,IAAIL,EAAIM,aAAeN,EAAII,IAAKH,GAC1CM,EAAa,IAAIC,gBAEvBR,EAAIS,GAAG,SAAS,IAAMF,EAAWG,UAEjC,MAAMC,EAAU,IAAIC,QAEpB,IAAK,MAAOC,EAAKC,KAAWC,OAAOC,QAAQhB,EAAIW,SAC7C,GAAIG,EACF,GAAIG,MAAMC,QAAQJ,GAChB,IAAK,MAAMK,KAASL,EAClBH,EAAQS,OAAOP,EAAKM,QAGtBR,EAAQU,IAAIR,EAAKC,GAKvB,MAAMQ,EAAoB,CACxBC,OAAQvB,EAAIuB,OACZZ,UACAa,OAAQjB,EAAWiB,OACnBC,UAAMC,GAOR,MAJmB,QAAf1B,EAAIuB,QAAmC,SAAfvB,EAAIuB,SAC9BD,EAAKG,KAAOzB,EAAIyB,MAGX,IAAIE,QAAQvB,EAAIwB,KAAMN,EAC/B"}
@@ -1 +1 @@
1
- {"version":3,"file":"render.js","sources":["../../src/node/render.tsx"],"sourcesContent":["import type { StaticHandler } from '@remix-run/router';\nimport chalk from 'chalk';\nimport type { Request, Response as ExpressResponse } from 'express';\nimport React from 'react';\nimport { renderToPipeableStream } from 'react-dom/server';\nimport type { StaticHandlerContext } from 'react-router-dom/server';\nimport { createStaticRouter, StaticRouterProvider } from 'react-router-dom/server.mjs';\nimport StreamError from '@constants/stream-error';\nimport type { IServerContext } from '@context/server';\nimport { ServerProvider } from '@context/server';\nimport handleResponse from '@helpers/handle-response';\nimport type { IObtainStreamErrorOut } from '@helpers/obtain-stream-error';\nimport obtainStreamError from '@helpers/obtain-stream-error';\nimport createFetchRequest from '@node/create-fetch-request';\nimport type { TApp } from '@node/entry';\nimport writeResponse from '@node/write-response';\nimport type ServerConfig from '@services/server-config';\nimport SsrManifest from '@services/ssr-manifest';\n\nexport interface IRequestContext<TAppProps = Record<any, any>> {\n req: Request;\n res: ExpressResponse;\n appProps: NonNullable<TAppProps>;\n html: { header: string; footer: string };\n routerContext?: StaticHandlerContext;\n serverContext?: IServerContext;\n isStream?: boolean;\n hasEarlyHints?: boolean;\n didError?: StreamError;\n}\n\nexport type TRender<TAppProps = Record<any, any>> = (\n config: ServerConfig,\n context: IRequestContext<TAppProps>,\n options: IRenderOptions,\n) => Promise<void>;\n\nexport interface IRenderParams<TAppProps = Record<string, any>> {\n App: TApp<TAppProps>;\n handler: StaticHandler;\n}\n\nexport interface IRenderOptions<TAppProps = Record<string, any>> {\n abortDelay?: number;\n onRouterReady?: (params: {\n context: IRequestContext<TAppProps>;\n }) => Promise<IRouterReadyOut> | IRouterReadyOut;\n onShellReady?: (params: { context: IRequestContext<TAppProps> }) => IShellReadyOut;\n onShellError?: (params: {\n context: IRequestContext<TAppProps>;\n error: Error;\n }) => string | undefined | void; // return html or undefined\n onError?: (params: { context: IRequestContext<TAppProps>; error: IObtainStreamErrorOut }) => void;\n onResponse?: (params: {\n context: IRequestContext<TAppProps>;\n html: string;\n }) => string | undefined | void;\n getState?: (params: {\n context: IRequestContext<TAppProps>;\n }) => Record<string, Record<string, any>> | undefined | void;\n}\n\nexport interface IRouterReadyOut {\n isStream?: boolean;\n}\n\nexport interface IShellReadyOut {\n header?: string;\n footer?: string;\n}\n\n/**\n * Render application\n */\nasync function render(\n { App, handler }: IRenderParams, // @see entry (bind)\n config: ServerConfig,\n context: IRequestContext,\n {\n onRouterReady,\n onShellReady,\n onResponse,\n onShellError,\n onError,\n getState,\n abortDelay = 15000,\n }: IRenderOptions,\n): Promise<void> {\n const { req, res } = context;\n const fetchRequest = createFetchRequest(req);\n\n context.routerContext = (await handler.query(fetchRequest, {\n requestContext: context,\n })) as StaticHandlerContext;\n\n /**\n * Handle response from page loader, router context can be Response\n */\n const statusCode = handleResponse(res, context.routerContext);\n\n if (!statusCode) {\n return;\n }\n\n SsrManifest.get(config).injectAssets(context);\n\n const { isStream = true } = (await onRouterReady?.({ context })) ?? {};\n\n context.isStream = isStream;\n context.serverContext = { response: null, isServer: true };\n\n const router = createStaticRouter(handler.dataRoutes, context.routerContext);\n const write = res.write.bind(res);\n const Logger = config.getLogger();\n let abortTimer: NodeJS.Timer | undefined = undefined;\n\n /**\n * Listen response and stream to add possibility modify html on fly\n * E.g. listen stream and append some data\n */\n res.write = (data: string | Uint8Array, ...args): boolean => {\n const isString = typeof data === 'string';\n const html = isString ? data : Buffer.from(data).toString();\n const modifiedHtml = onResponse?.({ context, html });\n\n if (modifiedHtml) {\n return write(isString ? modifiedHtml : Buffer.from(modifiedHtml), ...args) as boolean;\n }\n\n return write(data, ...args) as boolean;\n };\n\n const { serverContext, routerContext, appProps } = context;\n\n const { pipe, abort } = renderToPipeableStream(\n <ServerProvider context={serverContext}>\n <App server={{ ...appProps, req }}>\n <StaticRouterProvider router={router} context={routerContext} hydrate={false} />\n </App>\n </ServerProvider>,\n {\n onShellReady(): void {\n if (!isStream) {\n return;\n }\n\n writeResponse(context, {\n pipe,\n statusCode,\n onShellReady,\n getState,\n });\n },\n onAllReady(): void {\n clearTimeout(abortTimer);\n\n if (isStream) {\n return;\n }\n\n writeResponse(context, {\n pipe,\n statusCode,\n onShellReady,\n getState,\n });\n },\n onShellError(e: Error): void {\n const htmlError =\n onShellError?.({ context, error: e }) ||\n `<!doctype html><p>Something went wrong: ${e.message}</p>`;\n\n res.status(500);\n res.setHeader('content-type', 'text/html');\n res.send(htmlError);\n },\n onError(err): void {\n clearTimeout(abortTimer);\n\n const error = obtainStreamError(err);\n const { code, message } = error;\n const { didError } = context;\n\n context.didError = didError ?? code;\n\n onError?.({ context, error });\n Logger.info(chalk.red(`Stream error. Code: ${code}`));\n\n if (\n [StreamError.RenderAborted, StreamError.RenderTimeout, StreamError.RenderCancel].includes(\n code,\n )\n ) {\n Logger.info(chalk.dim(message));\n\n return;\n }\n\n Logger.error(err as string);\n },\n },\n );\n\n // Abandon and switch to client rendering if enough time passes.\n abortTimer = setTimeout(() => {\n context.didError = StreamError.RenderTimeout;\n abort();\n }, abortDelay);\n\n // Detect cancel request\n req.on('close', () => {\n context.didError = StreamError.RenderCancel;\n abort();\n });\n}\n\nexport default render;\n"],"names":["async","render","App","handler","config","context","onRouterReady","onShellReady","onResponse","onShellError","onError","getState","abortDelay","req","res","fetchRequest","createFetchRequest","routerContext","query","requestContext","statusCode","handleResponse","SsrManifest","get","injectAssets","isStream","serverContext","response","isServer","router","createStaticRouter","dataRoutes","write","bind","Logger","getLogger","abortTimer","data","args","isString","html","Buffer","from","toString","modifiedHtml","appProps","pipe","abort","renderToPipeableStream","React","createElement","ServerProvider","server","StaticRouterProvider","hydrate","writeResponse","onAllReady","clearTimeout","e","htmlError","error","message","status","setHeader","send","err","obtainStreamError","code","didError","info","chalk","red","StreamError","RenderAborted","RenderTimeout","RenderCancel","includes","dim","setTimeout","on"],"mappings":"sfA0EAA,eAAeC,GACbC,IAAEA,EAAGC,QAAEA,GACPC,EACAC,GACAC,cACEA,EAAaC,aACbA,EAAYC,WACZA,EAAUC,aACVA,EAAYC,QACZA,EAAOC,SACPA,EAAQC,WACRA,EAAa,OAGf,MAAMC,IAAEA,EAAGC,IAAEA,GAAQT,EACfU,EAAeC,EAAmBH,GAExCR,EAAQY,oBAAuBd,EAAQe,MAAMH,EAAc,CACzDI,eAAgBd,IAMlB,MAAMe,EAAaC,EAAeP,EAAKT,EAAQY,eAE/C,IAAKG,EACH,OAGFE,EAAYC,IAAInB,GAAQoB,aAAanB,GAErC,MAAMoB,SAAEA,GAAW,SAAgBnB,IAAgB,CAAED,cAAe,GAEpEA,EAAQoB,SAAWA,EACnBpB,EAAQqB,cAAgB,CAAEC,SAAU,KAAMC,UAAU,GAEpD,MAAMC,EAASC,EAAmB3B,EAAQ4B,WAAY1B,EAAQY,eACxDe,EAAQlB,EAAIkB,MAAMC,KAAKnB,GACvBoB,EAAS9B,EAAO+B,YACtB,IAAIC,EAMJtB,EAAIkB,MAAQ,CAACK,KAA8BC,KACzC,MAAMC,EAA2B,iBAATF,EAClBG,EAAOD,EAAWF,EAAOI,OAAOC,KAAKL,GAAMM,WAC3CC,EAAepC,IAAa,CAAEH,UAASmC,SAE7C,OAAII,EACKZ,EAAMO,EAAWK,EAAeH,OAAOC,KAAKE,MAAkBN,GAGhEN,EAAMK,KAASC,EAAgB,EAGxC,MAAMZ,cAAEA,EAAaT,cAAEA,EAAa4B,SAAEA,GAAaxC,GAE7CyC,KAAEA,EAAIC,MAAEA,GAAUC,EACtBC,EAACC,cAAAC,EAAe,CAAA9C,QAASqB,GACvBuB,EAACC,cAAAhD,GAAIkD,OAAQ,IAAKP,EAAUhC,QAC1BoC,EAAAC,cAACG,EAAqB,CAAAxB,OAAQA,EAAQxB,QAASY,EAAeqC,SAAS,MAG3E,CACE/C,eACOkB,GAIL8B,EAAclD,EAAS,CACrByC,OACA1B,aACAb,eACAI,YAEH,EACD6C,aACEC,aAAarB,GAETX,GAIJ8B,EAAclD,EAAS,CACrByC,OACA1B,aACAb,eACAI,YAEH,EACDF,aAAaiD,GACX,MAAMC,EACJlD,IAAe,CAAEJ,UAASuD,MAAOF,KACjC,2CAA2CA,EAAEG,cAE/C/C,EAAIgD,OAAO,KACXhD,EAAIiD,UAAU,eAAgB,aAC9BjD,EAAIkD,KAAKL,EACV,EACDjD,QAAQuD,GACNR,aAAarB,GAEb,MAAMwB,EAAQM,EAAkBD,IAC1BE,KAAEA,EAAIN,QAAEA,GAAYD,GACpBQ,SAAEA,GAAa/D,EAErBA,EAAQ+D,SAAWA,GAAYD,EAE/BzD,IAAU,CAAEL,UAASuD,UACrB1B,EAAOmC,KAAKC,EAAMC,IAAI,uBAAuBJ,MAG3C,CAACK,EAAYC,cAAeD,EAAYE,cAAeF,EAAYG,cAAcC,SAC/ET,GAGFjC,EAAOmC,KAAKC,EAAMO,IAAIhB,IAKxB3B,EAAO0B,MAAMK,EACd,IAKL7B,EAAa0C,YAAW,KACtBzE,EAAQ+D,SAAWI,EAAYE,cAC/B3B,GAAO,GACNnC,GAGHC,EAAIkE,GAAG,SAAS,KACd1E,EAAQ+D,SAAWI,EAAYG,aAC/B5B,GAAO,GAEX"}
1
+ {"version":3,"file":"render.js","sources":["../../src/node/render.tsx"],"sourcesContent":["import type { StaticHandler } from '@remix-run/router';\nimport chalk from 'chalk';\nimport type { Request, Response as ExpressResponse } from 'express';\nimport React from 'react';\nimport { renderToPipeableStream } from 'react-dom/server';\nimport type { StaticHandlerContext } from 'react-router-dom/server';\nimport { createStaticRouter, StaticRouterProvider } from 'react-router-dom/server.mjs';\nimport StreamError from '@constants/stream-error';\nimport type { IServerContext } from '@context/server';\nimport { ServerProvider } from '@context/server';\nimport handleResponse from '@helpers/handle-response';\nimport type { IObtainStreamErrorOut } from '@helpers/obtain-stream-error';\nimport obtainStreamError from '@helpers/obtain-stream-error';\nimport createFetchRequest from '@node/create-fetch-request';\nimport type { TApp } from '@node/entry';\nimport writeResponse from '@node/write-response';\nimport type ServerConfig from '@services/server-config';\nimport SsrManifest from '@services/ssr-manifest';\n\nexport interface IRequestContext<TAppProps = Record<any, any>> {\n req: Request;\n res: ExpressResponse;\n appProps: NonNullable<TAppProps>;\n html: { header: string; footer: string };\n routerContext?: StaticHandlerContext;\n serverContext?: IServerContext;\n isStream?: boolean;\n hasEarlyHints?: boolean;\n didError?: StreamError;\n}\n\nexport type TRender<TAppProps = Record<any, any>> = (\n config: ServerConfig,\n context: IRequestContext<TAppProps>,\n options: IRenderOptions,\n) => Promise<void>;\n\nexport interface IRenderParams<TAppProps = Record<string, any>> {\n App: TApp<TAppProps>;\n handler: StaticHandler;\n}\n\nexport interface IRenderOptions<TAppProps = Record<string, any>> {\n abortDelay?: number;\n onRouterReady?: (params: {\n context: IRequestContext<TAppProps>;\n }) => Promise<IRouterReadyOut> | IRouterReadyOut;\n onShellReady?: (params: { context: IRequestContext<TAppProps> }) => IShellReadyOut;\n onShellError?: (params: {\n context: IRequestContext<TAppProps>;\n error: Error;\n }) => string | undefined | void; // return html or undefined\n onError?: (params: { context: IRequestContext<TAppProps>; error: IObtainStreamErrorOut }) => void;\n onResponse?: (params: {\n context: IRequestContext<TAppProps>;\n html: string;\n }) => string | undefined | void;\n getState?: (params: {\n context: IRequestContext<TAppProps>;\n }) => Record<string, Record<string, any>> | undefined | void;\n}\n\nexport interface IRouterReadyOut {\n isStream?: boolean;\n}\n\nexport interface IShellReadyOut {\n header?: string;\n footer?: string;\n}\n\n/**\n * Render application\n */\nasync function render(\n { App, handler }: IRenderParams, // @see entry (bind)\n config: ServerConfig,\n context: IRequestContext,\n {\n onRouterReady,\n onShellReady,\n onResponse,\n onShellError,\n onError,\n getState,\n abortDelay = 15000,\n }: IRenderOptions,\n): Promise<void> {\n const { req, res } = context;\n const fetchRequest = createFetchRequest(req);\n\n context.routerContext = (await handler.query(fetchRequest, {\n requestContext: context,\n })) as StaticHandlerContext;\n\n /**\n * Handle response from page loader, router context can be Response\n */\n const statusCode = handleResponse(res, context.routerContext);\n\n if (!statusCode) {\n return;\n }\n\n SsrManifest.get(config).injectAssets(context);\n\n const { isStream = true } = (await onRouterReady?.({ context })) ?? {};\n\n context.isStream = isStream;\n context.serverContext = { response: null, isServer: true };\n\n const router = createStaticRouter(handler.dataRoutes, context.routerContext);\n const write = res.write.bind(res) 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","router","createStaticRouter","dataRoutes","write","bind","Logger","getLogger","abortTimer","data","args","isString","html","Buffer","from","toString","modifiedHtml","appProps","pipe","abort","renderToPipeableStream","React","createElement","ServerProvider","server","StaticRouterProvider","hydrate","writeResponse","onAllReady","clearTimeout","e","htmlError","error","message","status","setHeader","send","err","obtainStreamError","code","didError","info","chalk","red","StreamError","RenderAborted","RenderTimeout","RenderCancel","includes","dim","setTimeout","on"],"mappings":"sfA0EAA,eAAeC,GACbC,IAAEA,EAAGC,QAAEA,GACPC,EACAC,GACAC,cACEA,EAAaC,aACbA,EAAYC,WACZA,EAAUC,aACVA,EAAYC,QACZA,EAAOC,SACPA,EAAQC,WACRA,EAAa,OAGf,MAAMC,IAAEA,EAAGC,IAAEA,GAAQT,EACfU,EAAeC,EAAmBH,GAExCR,EAAQY,oBAAuBd,EAAQe,MAAMH,EAAc,CACzDI,eAAgBd,IAMlB,MAAMe,EAAaC,EAAeP,EAAKT,EAAQY,eAE/C,IAAKG,EACH,OAGFE,EAAYC,IAAInB,GAAQoB,aAAanB,GAErC,MAAMoB,SAAEA,GAAW,SAAgBnB,IAAgB,CAAED,cAAe,GAEpEA,EAAQoB,SAAWA,EACnBpB,EAAQqB,cAAgB,CAAEC,SAAU,KAAMC,UAAU,GAEpD,MAAMC,EAASC,EAAmB3B,EAAQ4B,WAAY1B,EAAQY,eACxDe,EAAQlB,EAAIkB,MAAMC,KAAKnB,GACvBoB,EAAS9B,EAAO+B,YACtB,IAAIC,EAMJtB,EAAIkB,MAAQ,CAACK,KAA8BC,KACzC,MAAMC,EAA2B,iBAATF,EAClBG,EAAOD,EAAWF,EAAOI,OAAOC,KAAKL,GAAMM,WAC3CC,EAAepC,IAAa,CAAEH,UAASmC,SAE7C,OAAII,EAEKZ,EAAMO,EAAWK,EAAeH,OAAOC,KAAKE,MAAkBN,GAIhEN,EAAMK,KAASC,EAAgB,EAGxC,MAAMZ,cAAEA,EAAaT,cAAEA,EAAa4B,SAAEA,GAAaxC,GAE7CyC,KAAEA,EAAIC,MAAEA,GAAUC,EACtBC,EAACC,cAAAC,EAAe,CAAA9C,QAASqB,GACvBuB,EAACC,cAAAhD,GAAIkD,OAAQ,IAAKP,EAAUhC,QAC1BoC,EAAAC,cAACG,EAAqB,CAAAxB,OAAQA,EAAQxB,QAASY,EAAeqC,SAAS,MAG3E,CACE/C,eACOkB,GAIL8B,EAAclD,EAAS,CACrByC,OACA1B,aACAb,eACAI,YAEH,EACD6C,aACEC,aAAarB,GAETX,GAIJ8B,EAAclD,EAAS,CACrByC,OACA1B,aACAb,eACAI,YAEH,EACDF,aAAaiD,GACX,MAAMC,EACJlD,IAAe,CAAEJ,UAASuD,MAAOF,KACjC,2CAA2CA,EAAEG,cAE/C/C,EAAIgD,OAAO,KACXhD,EAAIiD,UAAU,eAAgB,aAC9BjD,EAAIkD,KAAKL,EACV,EACDjD,QAAQuD,GACNR,aAAarB,GAEb,MAAMwB,EAAQM,EAAkBD,IAC1BE,KAAEA,EAAIN,QAAEA,GAAYD,GACpBQ,SAAEA,GAAa/D,EAErBA,EAAQ+D,SAAWA,GAAYD,EAE/BzD,IAAU,CAAEL,UAASuD,UACrB1B,EAAOmC,KAAKC,EAAMC,IAAI,uBAAuBJ,MAG3C,CAACK,EAAYC,cAAeD,EAAYE,cAAeF,EAAYG,cAAcC,SAC/ET,GAGFjC,EAAOmC,KAAKC,EAAMO,IAAIhB,IAKxB3B,EAAO0B,MAAMK,EACd,IAKL7B,EAAa0C,YAAW,KACtBzE,EAAQ+D,SAAWI,EAAYE,cAC/B3B,GAAO,GACNnC,GAGHC,EAAIkE,GAAG,SAAS,KACd1E,EAAQ+D,SAAWI,EAAYG,aAC/B5B,GAAO,GAEX"}
@@ -1 +1 @@
1
- {"version":3,"file":"write-response.js","sources":["../../src/node/write-response.ts"],"sourcesContent":["import type { Response as ExpressResponse } from 'express';\nimport type { PipeableStream } from 'react-dom/server';\nimport buildCustomState from '@helpers/build-custom-state';\nimport buildRouterState from '@helpers/build-router-state';\nimport handleResponse from '@helpers/handle-response';\nimport type { IRenderOptions, IRequestContext } from '@node/render';\n\ninterface IWriteResponseParams {\n pipe: PipeableStream['pipe'];\n onShellReady: IRenderOptions['onShellReady'];\n getState: IRenderOptions['getState'];\n statusCode?: number; // default status\n}\n\n/**\n * Send response to client\n */\nconst writeResponse = (context: IRequestContext, params: IWriteResponseParams): void => {\n const { res, didError, serverContext, routerContext, html } = context;\n const { pipe, onShellReady, getState } = params;\n let { statusCode } = params;\n\n // handle response from server components (navigate, status)\n statusCode = handleResponse(res, serverContext!.response, statusCode);\n\n if (!statusCode) {\n return;\n }\n\n // catch close connection from React and write footer\n if (didError) {\n const end = res.end.bind(res);\n\n res.end = (...args: unknown[]): ExpressResponse => {\n // send second part of app shell\n res.write(modifiedFooter || html.footer);\n\n return end(...args) as ExpressResponse;\n };\n }\n\n res.status(statusCode);\n res.setHeader('content-type', 'text/html');\n\n const { header: modifiedHeader, footer: modifiedFooter } = onShellReady?.({ context }) ?? {};\n const routerState = buildRouterState(routerContext!);\n const customState = buildCustomState(getState?.({ context }));\n\n html.footer = routerState + customState + html.footer;\n\n // send first part of app shell\n res.write(modifiedHeader || html.header);\n // start streaming app\n pipe(res);\n\n if (!didError) {\n // send second part of app shell\n res.write(modifiedFooter || html.footer);\n }\n};\n\nexport default writeResponse;\n"],"names":["writeResponse","context","params","res","didError","serverContext","routerContext","html","pipe","onShellReady","getState","statusCode","handleResponse","response","end","bind","args","write","modifiedFooter","footer","status","setHeader","header","modifiedHeader","routerState","buildRouterState","customState","buildCustomState"],"mappings":"6IAiBA,MAAMA,EAAgB,CAACC,EAA0BC,KAC/C,MAAMC,IAAEA,EAAGC,SAAEA,EAAQC,cAAEA,EAAaC,cAAEA,EAAaC,KAAEA,GAASN,GACxDO,KAAEA,EAAIC,aAAEA,EAAYC,SAAEA,GAAaR,EACzC,IAAIS,WAAEA,GAAeT,EAKrB,GAFAS,EAAaC,EAAeT,EAAKE,EAAeQ,SAAUF,IAErDA,EACH,OAIF,GAAIP,EAAU,CACZ,MAAMU,EAAMX,EAAIW,IAAIC,KAAKZ,GAEzBA,EAAIW,IAAM,IAAIE,KAEZb,EAAIc,MAAMC,GAAkBX,EAAKY,QAE1BL,KAAOE,GAEjB,CAEDb,EAAIiB,OAAOT,GACXR,EAAIkB,UAAU,eAAgB,aAE9B,MAAQC,OAAQC,EAAgBJ,OAAQD,GAAmBT,IAAe,CAAER,aAAc,GACpFuB,EAAcC,EAAiBnB,GAC/BoB,EAAcC,EAAiBjB,IAAW,CAAET,aAElDM,EAAKY,OAASK,EAAcE,EAAcnB,EAAKY,OAG/ChB,EAAIc,MAAMM,GAAkBhB,EAAKe,QAEjCd,EAAKL,GAEAC,GAEHD,EAAIc,MAAMC,GAAkBX,EAAKY,OAClC"}
1
+ {"version":3,"file":"write-response.js","sources":["../../src/node/write-response.ts"],"sourcesContent":["import type { Response as ExpressResponse } from 'express';\nimport type { PipeableStream } from 'react-dom/server';\nimport buildCustomState from '@helpers/build-custom-state';\nimport buildRouterState from '@helpers/build-router-state';\nimport handleResponse from '@helpers/handle-response';\nimport type { IRenderOptions, IRequestContext } from '@node/render';\n\ninterface IWriteResponseParams {\n pipe: PipeableStream['pipe'];\n onShellReady: IRenderOptions['onShellReady'];\n getState: IRenderOptions['getState'];\n statusCode?: number; // default status\n}\n\n/**\n * Send response to client\n */\nconst writeResponse = (context: IRequestContext, params: IWriteResponseParams): void => {\n const { res, didError, serverContext, routerContext, html } = context;\n const { pipe, onShellReady, getState } = params;\n let { statusCode } = params;\n\n // handle response from server components (navigate, status)\n statusCode = handleResponse(res, serverContext!.response, statusCode);\n\n if (!statusCode) {\n return;\n }\n\n // catch close connection from React and write footer\n if (didError) {\n const end = res.end.bind(res) 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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lomray/vite-ssr-boost",
3
- "version": "2.3.2",
3
+ "version": "2.3.3-beta.2",
4
4
  "description": "Vite plugin for create awesome SSR or SPA applications on React.",
5
5
  "type": "module",
6
6
  "keywords": [
@@ -27,8 +27,8 @@
27
27
  "build": "rollup -c",
28
28
  "build:watch": "rollup -c -w",
29
29
  "release": "npm run build && cd lib && npm publish",
30
- "lint:check": "eslint --ext \".ts,.tsx\" \"src/**/*.{ts,tsx,*.ts,*tsx}\"",
31
- "lint:format": "eslint --fix --ext \".ts,.tsx\" \"src/**/*.{ts,tsx,*.ts,*tsx}\"",
30
+ "lint:check": "eslint \"src/**/*.{ts,tsx,*.ts,*tsx}\"",
31
+ "lint:format": "eslint --fix \"src/**/*.{ts,tsx,*.ts,*tsx}\"",
32
32
  "ts:check": "tsc --project ./tsconfig.json --skipLibCheck --noemit",
33
33
  "test": "vitest run"
34
34
  },
@@ -41,9 +41,9 @@
41
41
  "json5": "^2.2.3"
42
42
  },
43
43
  "devDependencies": {
44
- "@commitlint/cli": "^18.6.0",
45
- "@commitlint/config-conventional": "^18.6.0",
46
- "@lomray/eslint-config": "^4.0.1",
44
+ "@commitlint/cli": "^19.0.3",
45
+ "@commitlint/config-conventional": "^19.0.3",
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
49
  "@testing-library/react": "^14.2.1",
@@ -53,15 +53,10 @@
53
53
  "@types/react-dom": "^18.2.19",
54
54
  "@types/sinon": "^17.0.3",
55
55
  "@types/sinon-chai": "^3.2.12",
56
- "@typescript-eslint/eslint-plugin": "^6.21.0",
57
56
  "@vitest/coverage-v8": "^1.2.2",
58
57
  "@zerollup/ts-transform-paths": "^1.7.18",
59
58
  "chai": "^4.4.1",
60
- "eslint": "^8.56.0",
61
- "eslint-config-prettier": "^9.1.0",
62
- "eslint-plugin-import": "^2.29.1",
63
- "eslint-plugin-jsx-a11y": "^6.8.0",
64
- "eslint-plugin-prettier": "^5.1.3",
59
+ "eslint": "^8.57.0",
65
60
  "husky": "^9.0.11",
66
61
  "jsdom": "^24.0.0",
67
62
  "lint-staged": "^15.2.2",
package/plugin.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.js","sources":["../src/plugin.ts"],"sourcesContent":["import path from 'node:path';\nimport type { Plugin } from 'vite';\nimport CliActions from '@constants/cli-actions';\nimport type { ICliContext } from '@constants/cli-context';\nimport PLUGIN_NAME from '@constants/plugin-name';\nimport type { IPluginOptions as IMakeAliasesPluginOptions } from '@plugins/make-aliases';\nimport ViteMakeAliasesPlugin from '@plugins/make-aliases';\nimport ViteNormalizeRouterPlugin from '@plugins/normalize-route';\n\nexport interface IPluginOptions {\n // default: index.html\n indexFile?: string;\n // default: server.ts\n serverFile?: string;\n // default: client.ts\n clientFile?: string;\n // Path contains routes declaration files (need to detect route files). default: undefined, e.g.: /routes/\n routesPath?: string;\n // Read aliases from tsconfig\n tsconfigAliases?: boolean | IMakeAliasesPluginOptions;\n customShortcuts?: {\n key: string;\n description: string;\n action: (cliContext: ICliContext) => Promise<void> | void;\n isOnlyDev?: boolean;\n }[];\n}\n\nconst defaultOptions: IPluginOptions = {\n indexFile: 'index.html',\n serverFile: 'server.ts',\n clientFile: 'client.ts',\n tsconfigAliases: true,\n};\n\n/**\n * Init plugin\n * @constructor\n */\nfunction ViteSsrBoostPlugin(options: IPluginOptions = {}): Plugin[] {\n const dirInfo = new URL(import.meta.url);\n const action = (global.viteBoostAction || process.env.SSR_BOOST_ACTION) as CliActions;\n const mergedOptions: IPluginOptions = { ...defaultOptions, ...options };\n const isSSR = process.env.SSR_BOOST_IS_SSR === '1' || action === CliActions.dev;\n const isBuild = action === CliActions.build;\n\n const plugins: Plugin[] = [\n {\n name: PLUGIN_NAME,\n enforce: 'pre',\n // @ts-ignore save custom options\n pluginOptions: {\n ...mergedOptions,\n pluginPath: path.dirname(dirInfo.pathname),\n action,\n isDev: action === CliActions.dev,\n },\n\n config(config, { isSsrBuild }) {\n config.define = {\n ...(config.define ?? {}),\n __IS_SSR__: isSSR,\n };\n\n config.build = {\n ...(config.build ?? {}),\n };\n\n if (!isSsrBuild) {\n if (isSSR && isBuild) {\n config.build!.manifest = true;\n }\n\n return config;\n }\n\n return {\n ...config,\n ...(isBuild ? { appType: 'custom' } : {}),\n publicDir: false,\n };\n },\n },\n ];\n\n const { tsconfigAliases, routesPath } = mergedOptions;\n\n if (tsconfigAliases) {\n plugins.push(\n ViteMakeAliasesPlugin(typeof tsconfigAliases === 'boolean' ? undefined : tsconfigAliases),\n );\n }\n\n plugins.push(ViteNormalizeRouterPlugin({ isSSR, isBuild, routesPath }));\n\n return plugins;\n}\n\nexport default ViteSsrBoostPlugin;\n"],"names":["defaultOptions","indexFile","serverFile","clientFile","tsconfigAliases","ViteSsrBoostPlugin","options","dirInfo","URL","url","action","global","viteBoostAction","process","env","SSR_BOOST_ACTION","mergedOptions","isSSR","SSR_BOOST_IS_SSR","CliActions","dev","isBuild","build","plugins","name","PLUGIN_NAME","enforce","pluginOptions","pluginPath","path","dirname","pathname","isDev","config","isSsrBuild","define","__IS_SSR__","appType","publicDir","manifest","routesPath","push","ViteMakeAliasesPlugin","undefined","ViteNormalizeRouterPlugin"],"mappings":"kMA4BA,MAAMA,EAAiC,CACrCC,UAAW,aACXC,WAAY,YACZC,WAAY,YACZC,iBAAiB,GAOnB,SAASC,EAAmBC,EAA0B,IACpD,MAAMC,EAAU,IAAIC,gBAAgBC,KAC9BC,EAAUC,OAAOC,iBAAmBC,QAAQC,IAAIC,iBAChDC,EAAgC,IAAKhB,KAAmBM,GACxDW,EAAyC,MAAjCJ,QAAQC,IAAII,kBAA4BR,IAAWS,EAAWC,IACtEC,EAAUX,IAAWS,EAAWG,MAEhCC,EAAoB,CACxB,CACEC,KAAMC,EACNC,QAAS,MAETC,cAAe,IACVX,EACHY,WAAYC,EAAKC,QAAQvB,EAAQwB,UACjCrB,SACAsB,MAAOtB,IAAWS,EAAWC,KAG/Ba,OAAM,CAACA,GAAQC,WAAEA,MACfD,EAAOE,OAAS,IACVF,EAAOE,QAAU,CAAE,EACvBC,WAAYnB,GAGdgB,EAAOX,MAAQ,IACTW,EAAOX,OAAS,CAAE,GAGnBY,EAQE,IACFD,KACCZ,EAAU,CAAEgB,QAAS,UAAa,CAAE,EACxCC,WAAW,IAVPrB,GAASI,IACXY,EAAOX,MAAOiB,UAAW,GAGpBN,OAYT7B,gBAAEA,EAAeoC,WAAEA,GAAexB,EAUxC,OARIZ,GACFmB,EAAQkB,KACNC,EAAiD,kBAApBtC,OAAgCuC,EAAYvC,IAI7EmB,EAAQkB,KAAKG,EAA0B,CAAE3B,QAAOI,UAASmB,gBAElDjB,CACT"}
1
+ {"version":3,"file":"plugin.js","sources":["../src/plugin.ts"],"sourcesContent":["import path from 'node:path';\nimport type { Plugin } from 'vite';\nimport CliActions from '@constants/cli-actions';\nimport type { ICliContext } from '@constants/cli-context';\nimport PLUGIN_NAME from '@constants/plugin-name';\nimport type { IPluginOptions as IMakeAliasesPluginOptions } from '@plugins/make-aliases';\nimport ViteMakeAliasesPlugin from '@plugins/make-aliases';\nimport ViteNormalizeRouterPlugin from '@plugins/normalize-route';\n\nexport interface IPluginOptions {\n // default: index.html\n indexFile?: string;\n // default: server.ts\n serverFile?: string;\n // default: client.ts\n clientFile?: string;\n // Path contains routes declaration files (need to detect route files). default: undefined, e.g.: /routes/\n routesPath?: string;\n // Read aliases from tsconfig\n tsconfigAliases?: boolean | IMakeAliasesPluginOptions;\n customShortcuts?: {\n key: string;\n description: string;\n action: (cliContext: ICliContext) => Promise<void> | void;\n isOnlyDev?: boolean;\n }[];\n}\n\nconst defaultOptions: IPluginOptions = {\n indexFile: 'index.html',\n serverFile: 'server.ts',\n clientFile: 'client.ts',\n tsconfigAliases: true,\n};\n\n/**\n * Init plugin\n * @constructor\n */\nfunction ViteSsrBoostPlugin(options: IPluginOptions = {}): Plugin[] {\n const dirInfo = new URL(import.meta.url);\n const action = (global.viteBoostAction || process.env.SSR_BOOST_ACTION) as CliActions;\n const mergedOptions: IPluginOptions = { ...defaultOptions, ...options };\n const isSSR = process.env.SSR_BOOST_IS_SSR === '1' || action === CliActions.dev;\n const isBuild = action === CliActions.build;\n\n const plugins: Plugin[] = [\n {\n name: PLUGIN_NAME,\n enforce: 'pre',\n // @ts-ignore save custom options\n pluginOptions: {\n ...mergedOptions,\n pluginPath: path.dirname(dirInfo.pathname),\n action,\n isDev: action === CliActions.dev,\n },\n\n config(config, { isSsrBuild }) {\n config.define = {\n ...(config.define ?? {}),\n __IS_SSR__: isSSR,\n };\n\n config.build = {\n ...(config.build ?? {}),\n };\n\n if (!isSsrBuild) {\n if (isSSR && isBuild) {\n config.build.manifest = true;\n }\n\n return config;\n }\n\n return {\n ...config,\n ...(isBuild ? { appType: 'custom' } : {}),\n publicDir: false,\n };\n },\n },\n ];\n\n const { tsconfigAliases, routesPath } = mergedOptions;\n\n if (tsconfigAliases) {\n plugins.push(\n ViteMakeAliasesPlugin(typeof tsconfigAliases === 'boolean' ? undefined : tsconfigAliases),\n );\n }\n\n plugins.push(ViteNormalizeRouterPlugin({ isSSR, isBuild, routesPath }));\n\n return plugins;\n}\n\nexport default ViteSsrBoostPlugin;\n"],"names":["defaultOptions","indexFile","serverFile","clientFile","tsconfigAliases","ViteSsrBoostPlugin","options","dirInfo","URL","url","action","global","viteBoostAction","process","env","SSR_BOOST_ACTION","mergedOptions","isSSR","SSR_BOOST_IS_SSR","CliActions","dev","isBuild","build","plugins","name","PLUGIN_NAME","enforce","pluginOptions","pluginPath","path","dirname","pathname","isDev","config","isSsrBuild","define","__IS_SSR__","appType","publicDir","manifest","routesPath","push","ViteMakeAliasesPlugin","undefined","ViteNormalizeRouterPlugin"],"mappings":"kMA4BA,MAAMA,EAAiC,CACrCC,UAAW,aACXC,WAAY,YACZC,WAAY,YACZC,iBAAiB,GAOnB,SAASC,EAAmBC,EAA0B,IACpD,MAAMC,EAAU,IAAIC,gBAAgBC,KAC9BC,EAAUC,OAAOC,iBAAmBC,QAAQC,IAAIC,iBAChDC,EAAgC,IAAKhB,KAAmBM,GACxDW,EAAyC,MAAjCJ,QAAQC,IAAII,kBAA4BR,IAAWS,EAAWC,IACtEC,EAAUX,IAAWS,EAAWG,MAEhCC,EAAoB,CACxB,CACEC,KAAMC,EACNC,QAAS,MAETC,cAAe,IACVX,EACHY,WAAYC,EAAKC,QAAQvB,EAAQwB,UACjCrB,SACAsB,MAAOtB,IAAWS,EAAWC,KAG/Ba,OAAM,CAACA,GAAQC,WAAEA,MACfD,EAAOE,OAAS,IACVF,EAAOE,QAAU,CAAE,EACvBC,WAAYnB,GAGdgB,EAAOX,MAAQ,IACTW,EAAOX,OAAS,CAAE,GAGnBY,EAQE,IACFD,KACCZ,EAAU,CAAEgB,QAAS,UAAa,CAAE,EACxCC,WAAW,IAVPrB,GAASI,IACXY,EAAOX,MAAMiB,UAAW,GAGnBN,OAYT7B,gBAAEA,EAAeoC,WAAEA,GAAexB,EAUxC,OARIZ,GACFmB,EAAQkB,KACNC,EAAiD,kBAApBtC,OAAgCuC,EAAYvC,IAI7EmB,EAAQkB,KAAKG,EAA0B,CAAE3B,QAAOI,UAASmB,gBAElDjB,CACT"}
@@ -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 SsrManifest.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(fs.readFileSync(tsconfigPath, { encoding: 'utf-8' }));\n const paths: Record<string, string[]> = 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]) => ({ find, replacement: val }));\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,MAAMJ,EAAGK,aAAaT,EAAc,CAAEU,SAAU,WAC/DC,EAAkCL,GAAQM,iBAAiBD,OAAS,CAAA,EAE1EE,OAAOC,QAAQH,GAAOI,SAAQ,EAAEC,EAAOC,MACrCd,EAAQe,KAAK,CAAC5B,EAAa0B,GAAQ1B,EAAa2B,EAAW,KAAK,GAEnE,MARCE,QAAQC,MAAM,GAAGhC,6BAAsCY,MAUzD,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,CAAED,OAAME,YAAaD,MAE9EL,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 SsrManifest.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,2 +1,2 @@
1
- import{extname as e}from"node:path";import r from"../constants/plugin-name.js";import t from"../helpers/is-route-file.js";const s=(e,r=!1)=>{if(r)return e;const t=[...e.matchAll(/import\s+(\w+)\sfrom\s+['"]([^'"]+)['"]/g)].reduce(((e,[,r,t])=>({[r]:t,...e})),{});return e.replace(/(.*?(?:Component|element):[\s<]*(\w+)[^,}]*),*/gs,((e,r,s)=>{const n=t?.[s];return n?`${r},pathId: '${n}',`:e}))},n=(e,t)=>{const s=e.replace(/(lazy)(:\s*)(\(\)\s*=>\s*import\(([^)]+)\))/gs,t?"lazy$2()=>n($3,$4)":"lazy$2()=>n($3)");return e!==s?`import n from '${r}/helpers/import-route';${s}`:e};function o(o={}){const{isSSR:m=!1,isBuild:i=!1,routesPath:p}=o;return{name:`${r}-normalize-route`,enforce:"pre",transform(r,o){const l=e(o).split("?")[0],u=!p||o.includes(p);if(!o.includes("node_modules")&&[".js",".mjs",".ts",".tsx"].includes(l)&&u&&t(r))return{code:n(s(r,i),m),map:{mappings:""}}}}}export{o as default};
1
+ import{extname as e}from"node:path";import r from"../constants/plugin-name.js";import t from"../helpers/is-route-file.js";const s=(e,r=!1)=>{if(r)return e;const t=[...e.matchAll(/import\s+(\w+)\sfrom\s+['"]([^'"]+)['"]/g)].reduce(((e,[,r,t])=>({[r]:t,...e})),{});return e.replace(/(.*?(?:Component|element):[\s<]*(\w+)[^,}]*),*/gs,((e,r,s)=>{const n=t?.[s];return n?`${r},pathId: '${n}',`:e}))},n=(e,t)=>{const s=e.replace(/(lazy)(:\s*)(\(\)\s*=>\s*import\(([^)]+)\))/gs,t?"lazy$2()=>n($3,$4)":"lazy$2()=>n($3)");return e!==s?`import n from '${r}/helpers/import-route';${s}`:e};function o(o={}){const{isSSR:m=!1,isBuild:i=!1,routesPath:p}=o;return{name:`${r}-normalize-route`,enforce:"pre",transform(r,o){const[l]=e(o).split("?"),u=!p||o.includes(p);if(!o.includes("node_modules")&&[".js",".mjs",".ts",".tsx"].includes(l)&&u&&t(r))return{code:n(s(r,i),m),map:{mappings:""}}}}}export{o as default};
2
2
  //# sourceMappingURL=normalize-route.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"normalize-route.js","sources":["../../src/plugins/normalize-route.ts"],"sourcesContent":["import { extname } from 'node:path';\nimport type { Plugin } from 'vite';\nimport PLUGIN_NAME from '@constants/plugin-name';\nimport isRoutesFile from '@helpers/is-route-file';\n\nexport interface IPluginOptions {\n isSSR?: boolean;\n isBuild?: boolean;\n routesPath?: string;\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 const imports: Record<string, string> = [\n ...code.matchAll(/import\\s+(\\w+)\\sfrom\\s+['\"]([^'\"]+)['\"]/g),\n ].reduce(\n (res, [, key, value]) => ({\n [key]: value,\n ...res,\n }),\n {},\n );\n\n return code.replace(\n /(.*?(?:Component|element):[\\s<]*(\\w+)[^,}]*),*/gs,\n (fullMatch, before: string, routeName: string) => {\n const importPath = imports?.[routeName];\n\n if (!importPath) {\n return fullMatch;\n }\n\n return `${before},pathId: '${importPath}',`;\n },\n );\n};\n\n/**\n * Add normalize wrapper to lazy imports for client build\n */\nconst normalizeAsyncRoutes = (code: string, isSSR: boolean): string => {\n const modifiedCode = code.replace(\n /(lazy)(:\\s*)(\\(\\)\\s*=>\\s*import\\(([^)]+)\\))/gs,\n isSSR ? 'lazy$2()=>n($3,$4)' : 'lazy$2()=>n($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.getRoutesIds\n * @see importRoute\n * @constructor\n */\nfunction ViteNormalizeRouterPlugin(options: IPluginOptions = {}): Plugin {\n const { isSSR = false, isBuild = false, routesPath } = options;\n\n return {\n name: `${PLUGIN_NAME}-normalize-route`,\n enforce: 'pre',\n transform(code, id) {\n const extName = extname(id).split('?')[0]!;\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 return {\n code: normalizeAsyncRoutes(normalizeSyncRoutes(code, isBuild), isSSR),\n map: { mappings: '' },\n };\n },\n };\n}\n\nexport default ViteNormalizeRouterPlugin;\n"],"names":["normalizeSyncRoutes","code","isBuild","imports","matchAll","reduce","res","key","value","replace","fullMatch","before","routeName","importPath","normalizeAsyncRoutes","isSSR","modifiedCode","PLUGIN_NAME","ViteNormalizeRouterPlugin","options","routesPath","name","enforce","transform","id","extName","extname","split","isRoutesPath","includes","isRoutesFile","map","mappings"],"mappings":"0HAeA,MAAMA,EAAsB,CAACC,EAAcC,GAAU,KACnD,GAAIA,EACF,OAAOD,EAGT,MAAME,EAAkC,IACnCF,EAAKG,SAAS,6CACjBC,QACA,CAACC,GAAK,CAAGC,EAAKC,MAAY,CACxBD,CAACA,GAAMC,KACJF,KAEL,CAAE,GAGJ,OAAOL,EAAKQ,QACV,oDACA,CAACC,EAAWC,EAAgBC,KAC1B,MAAMC,EAAaV,IAAUS,GAE7B,OAAKC,EAIE,GAAGF,cAAmBE,MAHpBH,CAGkC,GAE9C,EAMGI,EAAuB,CAACb,EAAcc,KAC1C,MAAMC,EAAef,EAAKQ,QACxB,gDACAM,EAAQ,qBAAuB,mBAGjC,OAAId,IAASe,EACJ,kBAAkBC,2BAAqCD,IAGzDf,CAAI,EAab,SAASiB,EAA0BC,EAA0B,IAC3D,MAAMJ,MAAEA,GAAQ,EAAKb,QAAEA,GAAU,EAAKkB,WAAEA,GAAeD,EAEvD,MAAO,CACLE,KAAM,GAAGJ,oBACTK,QAAS,MACTC,UAAUtB,EAAMuB,GACd,MAAMC,EAAUC,EAAQF,GAAIG,MAAM,KAAK,GACjCC,GAAgBR,GAAcI,EAAGK,SAAST,GAEhD,IACEI,EAAGK,SAAS,iBACX,CAAC,MAAO,OAAQ,MAAO,QAAQA,SAASJ,IACxCG,GACAE,EAAa7B,GAKhB,MAAO,CACLA,KAAMa,EAAqBd,EAAoBC,EAAMC,GAAUa,GAC/DgB,IAAK,CAAEC,SAAU,IAEpB,EAEL"}
1
+ {"version":3,"file":"normalize-route.js","sources":["../../src/plugins/normalize-route.ts"],"sourcesContent":["import { extname } from 'node:path';\nimport type { Plugin } from 'vite';\nimport PLUGIN_NAME from '@constants/plugin-name';\nimport isRoutesFile from '@helpers/is-route-file';\n\nexport interface IPluginOptions {\n isSSR?: boolean;\n isBuild?: boolean;\n routesPath?: string;\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 const imports: Record<string, string> = [\n ...code.matchAll(/import\\s+(\\w+)\\sfrom\\s+['\"]([^'\"]+)['\"]/g),\n ].reduce(\n (res, [, key, value]) => ({\n [key]: value,\n ...res,\n }),\n {},\n );\n\n return code.replace(\n /(.*?(?:Component|element):[\\s<]*(\\w+)[^,}]*),*/gs,\n (fullMatch, before: string, routeName: string) => {\n const importPath = imports?.[routeName];\n\n if (!importPath) {\n return fullMatch;\n }\n\n return `${before},pathId: '${importPath}',`;\n },\n );\n};\n\n/**\n * Add normalize wrapper to lazy imports for client build\n */\nconst normalizeAsyncRoutes = (code: string, isSSR: boolean): string => {\n const modifiedCode = code.replace(\n /(lazy)(:\\s*)(\\(\\)\\s*=>\\s*import\\(([^)]+)\\))/gs,\n isSSR ? 'lazy$2()=>n($3,$4)' : 'lazy$2()=>n($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.getRoutesIds\n * @see importRoute\n * @constructor\n */\nfunction ViteNormalizeRouterPlugin(options: IPluginOptions = {}): Plugin {\n const { isSSR = false, isBuild = false, routesPath } = options;\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 return {\n code: normalizeAsyncRoutes(normalizeSyncRoutes(code, isBuild), isSSR),\n map: { mappings: '' },\n };\n },\n };\n}\n\nexport default ViteNormalizeRouterPlugin;\n"],"names":["normalizeSyncRoutes","code","isBuild","imports","matchAll","reduce","res","key","value","replace","fullMatch","before","routeName","importPath","normalizeAsyncRoutes","isSSR","modifiedCode","PLUGIN_NAME","ViteNormalizeRouterPlugin","options","routesPath","name","enforce","transform","id","extName","extname","split","isRoutesPath","includes","isRoutesFile","map","mappings"],"mappings":"0HAeA,MAAMA,EAAsB,CAACC,EAAcC,GAAU,KACnD,GAAIA,EACF,OAAOD,EAGT,MAAME,EAAkC,IACnCF,EAAKG,SAAS,6CACjBC,QACA,CAACC,GAAK,CAAGC,EAAKC,MAAY,CACxBD,CAACA,GAAMC,KACJF,KAEL,CAAE,GAGJ,OAAOL,EAAKQ,QACV,oDACA,CAACC,EAAWC,EAAgBC,KAC1B,MAAMC,EAAaV,IAAUS,GAE7B,OAAKC,EAIE,GAAGF,cAAmBE,MAHpBH,CAGkC,GAE9C,EAMGI,EAAuB,CAACb,EAAcc,KAC1C,MAAMC,EAAef,EAAKQ,QACxB,gDACAM,EAAQ,qBAAuB,mBAGjC,OAAId,IAASe,EACJ,kBAAkBC,2BAAqCD,IAGzDf,CAAI,EAab,SAASiB,EAA0BC,EAA0B,IAC3D,MAAMJ,MAAEA,GAAQ,EAAKb,QAAEA,GAAU,EAAKkB,WAAEA,GAAeD,EAEvD,MAAO,CACLE,KAAM,GAAGJ,oBACTK,QAAS,MACTC,UAAUtB,EAAMuB,GACd,MAAOC,GAAWC,EAAQF,GAAIG,MAAM,KAC9BC,GAAgBR,GAAcI,EAAGK,SAAST,GAEhD,IACEI,EAAGK,SAAS,iBACX,CAAC,MAAO,OAAQ,MAAO,QAAQA,SAASJ,IACxCG,GACAE,EAAa7B,GAKhB,MAAO,CACLA,KAAMa,EAAqBd,EAAoBC,EAAMC,GAAUa,GAC/DgB,IAAK,CAAEC,SAAU,IAEpB,EAEL"}
@@ -1,2 +1,2 @@
1
- import t from"fs";import e from"node:process";import{pathToFileURL as r}from"node:url";import i from"path";import o from"chalk";class s{config;entrypoint;onServerCreated;html;constructor(t){this.config=t}static init(t){return new s(t)}async loadEntrypoint(t=!0){if(this.entrypoint&&this.config.isProd)return this.entrypoint;const{root:s,isProd:n,serverFile:a}=this.config.getParams(),l=i.resolve(`${s}/${a}`);let d;try{d=n?(await import(r(l).toString())).default:(await this.config.getVite().ssrLoadModule(l,{fixStacktrace:!0})).default}catch(t){if(t.message.includes("Cannot find module")&&t.message.includes("/build/"))return this.config.getLogger().error(o.red(`Before starting the server, you need to create a build: ${o.yellow("ssr-boost build")} or provide path to build dir: ${o.yellow("ssr-boost start --build-dir build")}`)),e.exit(1);throw t}!t&&d.init&&delete d.init;const{render:c,init:h,routes:f,abortDelay:u}=d,{onServerCreated:p,...g}=await(h?.({config:this.config}))??{};return this.entrypoint={render:c,routes:f,abortDelay:u,...g},this.onServerCreated=p,this.entrypoint}async loadHtml(e){const{isProd:r,root:o,indexFile:s}=this.config.getParams();this.html&&r||(this.html=t.readFileSync(i.resolve(`${o}/${s}`),"utf-8"));let n=this.html;return r||(n=(await this.config.getVite().transformIndexHtml(e.originalUrl,this.html)).replace(/(<script.+)(>[\s\S]+injectIntoGlobalHook.+)/,"$1async$2")),n.split("\x3c!--ssr-outlet--\x3e")}async onAppCreated(){return await this.loadEntrypoint(),await(this.onServerCreated?.(this.config.getApp())),this}}export{s as default};
1
+ import t from"fs";import e from"node:process";import{pathToFileURL as r}from"node:url";import i from"path";import o from"chalk";class n{config;entrypoint;onServerCreated;html;constructor(t){this.config=t}static init(t){return new n(t)}async loadEntrypoint(t=!0){if(this.entrypoint&&this.config.isProd)return this.entrypoint;const{root:n,isProd:s,serverFile:a}=this.config.getParams(),l=i.resolve(`${n}/${a}`);let d;try{d=s?(await import(r(l).toString())).default:(await this.config.getVite().ssrLoadModule(l,{fixStacktrace:!0})).default}catch(t){if(t instanceof Error&&t.message.includes("Cannot find module")&&t.message.includes("/build/"))return this.config.getLogger().error(o.red(`Before starting the server, you need to create a build: ${o.yellow("ssr-boost build")} or provide path to build dir: ${o.yellow("ssr-boost start --build-dir build")}`)),e.exit(1);throw t}!t&&d.init&&delete d.init;const{render:c,init:h,routes:f,abortDelay:u}=d,{onServerCreated:p,...g}=await(h?.({config:this.config}))??{};return this.entrypoint={render:c,routes:f,abortDelay:u,...g},this.onServerCreated=p,this.entrypoint}async loadHtml(e){const{isProd:r,root:o,indexFile:n}=this.config.getParams();this.html&&r||(this.html=t.readFileSync(i.resolve(`${o}/${n}`),"utf-8"));let s=this.html;return r||(s=(await this.config.getVite().transformIndexHtml(e.originalUrl,this.html)).replace(/(<script.+)(>[\s\S]+injectIntoGlobalHook.+)/,"$1async$2")),s.split("\x3c!--ssr-outlet--\x3e")}async onAppCreated(){return await this.loadEntrypoint(),await(this.onServerCreated?.(this.config.getApp())),this}}export{n as default};
2
2
  //# sourceMappingURL=prepare-server.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"prepare-server.js","sources":["../../src/services/prepare-server.ts"],"sourcesContent":["import fs from 'fs';\nimport process from 'node:process';\nimport { pathToFileURL } from 'node:url';\nimport path from 'path';\nimport chalk from 'chalk';\nimport type { Request } from 'express';\nimport type { TRouteObject } from '@interfaces/route-object';\nimport type { IEntrypointOptions, IPrepareRenderOut } from '@node/entry';\nimport type { TRender } from '@node/render';\nimport type ServerConfig from '@services/server-config';\n\ninterface IPrepareServerEntrypointLoadOut<TAppProps = Record<string, any>> {\n render: TRender;\n routes: TRouteObject[];\n abortDelay?: number;\n onRequest?: IEntrypointOptions<TAppProps>['onRequest'];\n onRouterReady?: IEntrypointOptions<TAppProps>['onRouterReady'];\n onShellReady?: IEntrypointOptions<TAppProps>['onShellReady'];\n onShellError?: IEntrypointOptions<TAppProps>['onShellError'];\n onResponse?: IEntrypointOptions<TAppProps>['onResponse'];\n onError?: IEntrypointOptions<TAppProps>['onError'];\n getState?: IEntrypointOptions<TAppProps>['getState'];\n}\n\n/**\n * Load server entrypoint and template\n * DEV MODE: refresh entrypoint and template\n */\nclass PrepareServer {\n /**\n * Server configuration\n */\n protected readonly config: ServerConfig;\n\n /**\n * Entrypoint resolved params\n */\n protected entrypoint?: IPrepareServerEntrypointLoadOut;\n\n /**\n * Hook which calls after express server created\n */\n protected onServerCreated?: IEntrypointOptions['onServerCreated'];\n\n /**\n * Html shell\n */\n protected html: string;\n\n /**\n * @constructor\n */\n protected constructor(config: ServerConfig) {\n this.config = config;\n }\n\n /**\n * Init service\n */\n public static init(config: ServerConfig): PrepareServer {\n return new PrepareServer(config);\n }\n\n /**\n * Resolve and return entrypoint params\n */\n public async loadEntrypoint(shouldInit = true): Promise<IPrepareServerEntrypointLoadOut> {\n // load server entrypoint each time only in development mode (for fast refresh)\n if (this.entrypoint && this.config.isProd) {\n return this.entrypoint;\n }\n\n const { root, isProd, serverFile } = this.config.getParams();\n const entrypointPath = path.resolve(`${root}/${serverFile}`);\n\n let resolvedEntrypoint: IPrepareRenderOut;\n\n try {\n if (!isProd) {\n resolvedEntrypoint = (\n await this.config.getVite()!.ssrLoadModule(entrypointPath, {\n fixStacktrace: true,\n })\n ).default;\n } else {\n resolvedEntrypoint = (await import(pathToFileURL(entrypointPath).toString())).default;\n }\n } catch (e) {\n if (e.message.includes('Cannot find module') && e.message.includes('/build/')) {\n this.config\n .getLogger()\n .error(\n chalk.red(\n `Before starting the server, you need to create a build: ${chalk.yellow(\n 'ssr-boost build',\n )} 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 } = resolvedEntrypoint;\n const { onServerCreated, ...renderParams } =\n (await init?.({\n config: this.config,\n })) ?? {};\n\n this.entrypoint = {\n render,\n routes,\n abortDelay,\n ...renderParams,\n };\n this.onServerCreated = onServerCreated;\n\n return this.entrypoint;\n }\n\n /**\n * Load and return html shell\n */\n public async loadHtml(req: Request): Promise<[string, string]> {\n const { isProd, root, indexFile } = this.config.getParams();\n\n if (!this.html || !isProd) {\n this.html = fs.readFileSync(path.resolve(`${root}/${indexFile}`), 'utf-8');\n }\n\n let modifiedHtml = this.html;\n\n if (!isProd) {\n // Apply Vite HTML transforms. This injects the Vite HMR client,\n // and also applies HTML transforms from Vite plugins, e.g. global\n // preambles from @vitejs/plugin-react\n modifiedHtml = (await this.config.getVite()!.transformIndexHtml(req.originalUrl, this.html))\n // Make vite script 'async'\n .replace(/(<script.+)(>[\\s\\S]+injectIntoGlobalHook.+)/, '$1async$2');\n }\n\n return modifiedHtml.split('<!--ssr-outlet-->') as [string, string];\n }\n\n /**\n * Run server created hook\n */\n public async onAppCreated(): Promise<PrepareServer> {\n await this.loadEntrypoint();\n await this.onServerCreated?.(this.config.getApp()!);\n\n return this;\n }\n}\n\nexport default PrepareServer;\n"],"names":["PrepareServer","config","entrypoint","onServerCreated","html","constructor","this","static","async","shouldInit","isProd","root","serverFile","getParams","entrypointPath","path","resolve","resolvedEntrypoint","import","pathToFileURL","toString","default","getVite","ssrLoadModule","fixStacktrace","e","message","includes","getLogger","error","chalk","red","yellow","process","exit","init","render","routes","abortDelay","renderParams","req","indexFile","fs","readFileSync","modifiedHtml","transformIndexHtml","originalUrl","replace","split","loadEntrypoint","getApp"],"mappings":"gIA4BA,MAAMA,EAIeC,OAKTC,WAKAC,gBAKAC,KAKVC,YAAsBJ,GACpBK,KAAKL,OAASA,CACf,CAKMM,YAAYN,GACjB,OAAO,IAAID,EAAcC,EAC1B,CAKMO,qBAAqBC,GAAa,GAEvC,GAAIH,KAAKJ,YAAcI,KAAKL,OAAOS,OACjC,OAAOJ,KAAKJ,WAGd,MAAMS,KAAEA,EAAID,OAAEA,EAAME,WAAEA,GAAeN,KAAKL,OAAOY,YAC3CC,EAAiBC,EAAKC,QAAQ,GAAGL,KAAQC,KAE/C,IAAIK,EAEJ,IAQIA,EAPGP,SAOyBQ,OAAOC,EAAcL,GAAgBM,aAAaC,eALtEf,KAAKL,OAAOqB,UAAWC,cAAcT,EAAgB,CACzDU,eAAe,KAEjBH,OAIL,CAAC,MAAOI,GACP,GAAIA,EAAEC,QAAQC,SAAS,uBAAyBF,EAAEC,QAAQC,SAAS,WAajE,OAZArB,KAAKL,OACF2B,YACAC,MACCC,EAAMC,IACJ,2DAA2DD,EAAME,OAC/D,oDACiCF,EAAME,OACvC,yCAKDC,EAAQC,KAAK,GAGtB,MAAMT,CACP,EAEIhB,GAAcQ,EAAmBkB,aAC7BlB,EAAmBkB,KAG5B,MAAMC,OAAEA,EAAMD,KAAEA,EAAIE,OAAEA,EAAMC,WAAEA,GAAerB,GACvCd,gBAAEA,KAAoBoC,SACnBJ,IAAO,CACZlC,OAAQK,KAAKL,WACR,CAAA,EAUT,OARAK,KAAKJ,WAAa,CAChBkC,SACAC,SACAC,gBACGC,GAELjC,KAAKH,gBAAkBA,EAEhBG,KAAKJ,UACb,CAKMM,eAAegC,GACpB,MAAM9B,OAAEA,EAAMC,KAAEA,EAAI8B,UAAEA,GAAcnC,KAAKL,OAAOY,YAE3CP,KAAKF,MAASM,IACjBJ,KAAKF,KAAOsC,EAAGC,aAAa5B,EAAKC,QAAQ,GAAGL,KAAQ8B,KAAc,UAGpE,IAAIG,EAAetC,KAAKF,KAWxB,OATKM,IAIHkC,SAAsBtC,KAAKL,OAAOqB,UAAWuB,mBAAmBL,EAAIM,YAAaxC,KAAKF,OAEnF2C,QAAQ,8CAA+C,cAGrDH,EAAaI,MAAM,0BAC3B,CAKMxC,qBAIL,aAHMF,KAAK2C,uBACL3C,KAAKH,kBAAkBG,KAAKL,OAAOiD,WAElC5C,IACR"}
1
+ {"version":3,"file":"prepare-server.js","sources":["../../src/services/prepare-server.ts"],"sourcesContent":["import fs from 'fs';\nimport process from 'node:process';\nimport { pathToFileURL } from 'node:url';\nimport path from 'path';\nimport chalk from 'chalk';\nimport type { Request } from 'express';\nimport type { TRouteObject } from '@interfaces/route-object';\nimport type { IEntrypointOptions, IPrepareRenderOut } from '@node/entry';\nimport type { TRender } from '@node/render';\nimport type ServerConfig from '@services/server-config';\n\ninterface IPrepareServerEntrypointLoadOut<TAppProps = Record<string, any>> {\n render: TRender;\n routes: TRouteObject[];\n abortDelay?: number;\n onRequest?: IEntrypointOptions<TAppProps>['onRequest'];\n onRouterReady?: IEntrypointOptions<TAppProps>['onRouterReady'];\n onShellReady?: IEntrypointOptions<TAppProps>['onShellReady'];\n onShellError?: IEntrypointOptions<TAppProps>['onShellError'];\n onResponse?: IEntrypointOptions<TAppProps>['onResponse'];\n onError?: IEntrypointOptions<TAppProps>['onError'];\n getState?: IEntrypointOptions<TAppProps>['getState'];\n}\n\n/**\n * Load server entrypoint and template\n * DEV MODE: refresh entrypoint and template\n */\nclass PrepareServer {\n /**\n * Server configuration\n */\n protected readonly config: ServerConfig;\n\n /**\n * Entrypoint resolved params\n */\n protected entrypoint?: IPrepareServerEntrypointLoadOut;\n\n /**\n * Hook which calls after express server created\n */\n protected onServerCreated?: IEntrypointOptions['onServerCreated'];\n\n /**\n * Html shell\n */\n protected html: string;\n\n /**\n * @constructor\n */\n protected constructor(config: ServerConfig) {\n this.config = config;\n }\n\n /**\n * Init service\n */\n public static init(config: ServerConfig): PrepareServer {\n return new PrepareServer(config);\n }\n\n /**\n * Resolve and return entrypoint params\n */\n public async loadEntrypoint(shouldInit = true): Promise<IPrepareServerEntrypointLoadOut> {\n // load server entrypoint each time only in development mode (for fast refresh)\n if (this.entrypoint && this.config.isProd) {\n return this.entrypoint;\n }\n\n const { root, isProd, serverFile } = this.config.getParams();\n const entrypointPath = path.resolve(`${root}/${serverFile}`);\n\n let resolvedEntrypoint: IPrepareRenderOut;\n\n try {\n if (!isProd) {\n resolvedEntrypoint = (\n await this.config.getVite()!.ssrLoadModule(entrypointPath, {\n fixStacktrace: true,\n })\n ).default 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 } = resolvedEntrypoint;\n const { onServerCreated, ...renderParams } =\n (await init?.({\n config: this.config,\n })) ?? {};\n\n this.entrypoint = {\n render,\n routes,\n abortDelay,\n ...renderParams,\n };\n this.onServerCreated = onServerCreated;\n\n return this.entrypoint;\n }\n\n /**\n * Load and return html shell\n */\n public async loadHtml(req: Request): Promise<[string, string]> {\n const { isProd, root, indexFile } = this.config.getParams();\n\n if (!this.html || !isProd) {\n this.html = fs.readFileSync(path.resolve(`${root}/${indexFile}`), 'utf-8');\n }\n\n let modifiedHtml = this.html;\n\n if (!isProd) {\n // Apply Vite HTML transforms. This injects the Vite HMR client,\n // and also applies HTML transforms from Vite plugins, e.g. global\n // preambles from @vitejs/plugin-react\n modifiedHtml = (await this.config.getVite()!.transformIndexHtml(req.originalUrl, this.html))\n // Make vite script 'async'\n .replace(/(<script.+)(>[\\s\\S]+injectIntoGlobalHook.+)/, '$1async$2');\n }\n\n return modifiedHtml.split('<!--ssr-outlet-->') as [string, string];\n }\n\n /**\n * Run server created hook\n */\n public async onAppCreated(): Promise<PrepareServer> {\n await this.loadEntrypoint();\n await this.onServerCreated?.(this.config.getApp()!);\n\n return this;\n }\n}\n\nexport default PrepareServer;\n"],"names":["PrepareServer","config","entrypoint","onServerCreated","html","constructor","this","static","async","shouldInit","isProd","root","serverFile","getParams","entrypointPath","path","resolve","resolvedEntrypoint","import","pathToFileURL","toString","default","getVite","ssrLoadModule","fixStacktrace","e","Error","message","includes","getLogger","error","chalk","red","yellow","process","exit","init","render","routes","abortDelay","renderParams","req","indexFile","fs","readFileSync","modifiedHtml","transformIndexHtml","originalUrl","replace","split","loadEntrypoint","getApp"],"mappings":"gIA4BA,MAAMA,EAIeC,OAKTC,WAKAC,gBAKAC,KAKVC,YAAsBJ,GACpBK,KAAKL,OAASA,CACf,CAKMM,YAAYN,GACjB,OAAO,IAAID,EAAcC,EAC1B,CAKMO,qBAAqBC,GAAa,GAEvC,GAAIH,KAAKJ,YAAcI,KAAKL,OAAOS,OACjC,OAAOJ,KAAKJ,WAGd,MAAMS,KAAEA,EAAID,OAAEA,EAAME,WAAEA,GAAeN,KAAKL,OAAOY,YAC3CC,EAAiBC,EAAKC,QAAQ,GAAGL,KAAQC,KAE/C,IAAIK,EAEJ,IAQIA,EAPGP,SAQMQ,OAAOC,EAAcL,GAAgBM,aAC5CC,eAPMf,KAAKL,OAAOqB,UAAWC,cAAcT,EAAgB,CACzDU,eAAe,KAEjBH,OAML,CAAC,MAAOI,GACP,GACEA,aAAaC,OACbD,EAAEE,QAAQC,SAAS,uBACnBH,EAAEE,QAAQC,SAAS,WAcnB,OAZAtB,KAAKL,OACF4B,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,GAAetB,GACvCd,gBAAEA,KAAoBqC,SACnBJ,IAAO,CACZnC,OAAQK,KAAKL,WACR,CAAA,EAUT,OARAK,KAAKJ,WAAa,CAChBmC,SACAC,SACAC,gBACGC,GAELlC,KAAKH,gBAAkBA,EAEhBG,KAAKJ,UACb,CAKMM,eAAeiC,GACpB,MAAM/B,OAAEA,EAAMC,KAAEA,EAAI+B,UAAEA,GAAcpC,KAAKL,OAAOY,YAE3CP,KAAKF,MAASM,IACjBJ,KAAKF,KAAOuC,EAAGC,aAAa7B,EAAKC,QAAQ,GAAGL,KAAQ+B,KAAc,UAGpE,IAAIG,EAAevC,KAAKF,KAWxB,OATKM,IAIHmC,SAAsBvC,KAAKL,OAAOqB,UAAWwB,mBAAmBL,EAAIM,YAAazC,KAAKF,OAEnF4C,QAAQ,8CAA+C,cAGrDH,EAAaI,MAAM,0BAC3B,CAKMzC,qBAIL,aAHMF,KAAK4C,uBACL5C,KAAKH,kBAAkBG,KAAKL,OAAOkD,WAElC7C,IACR"}
@@ -1,2 +1,2 @@
1
- import t from"node:fs";import e from"node:path";import s from"chalk";import i from"./prepare-server.js";import r from"./server-config.js";var o;!function(t){t.style="style",t.script="script",t.image="image",t.font="font"}(o||(o={}));const n="\r\n";class a{static instance=null;config;root;buildDir;manifestName="manifest.json";assetsManifest="assets-manifest.json";viteAliases;routesAssets=null;constructor(t,{buildDir:e,viteAliases:s}={}){this.config=t,this.root=t.getParams().root,this.buildDir=e,this.viteAliases=s??t.getVite()?.config?.resolve.alias}static get(t,e={}){return null===a.instance&&(a.instance=new a(t,e)),a.instance}getOutDir(){return e.resolve(this.root,this.buildDir||"")}getAssetsManifestFile(){return`${this.getOutDir()}/server/${this.assetsManifest}`}loadClientManifest(){const s=e.resolve(this.root,`${this.buildDir||""}/client/.vite`),i=`${s}/${this.manifestName}`;if(!t.existsSync(i))return{};const r=JSON.parse(t.readFileSync(i,{encoding:"utf-8"}));return t.rmSync(i),0===t.readdirSync(s).length&&t.rmSync(s,{recursive:!0}),r}loadAssetsManifest(){if(null!==this.routesAssets)return this.routesAssets;const e=this.getAssetsManifestFile();return t.existsSync(e)?(this.routesAssets=JSON.parse(t.readFileSync(e,{encoding:"utf-8"})),this.routesAssets):{}}async getRoutesIds(t,e){const i={};for(const r in t){const o=t[r],n=[e,r].filter(Boolean).join("-");if(o.lazy)try{const t=await o.lazy();i[n]=this.normalizeRoutePath(t?.pathId)}catch(t){console.error(s.red("Failed to load route:"),o.path,t)}else o.children&&Object.assign(i,await this.getRoutesIds(o.children,n))}return i}sortAssets(t){return t.sort(((t,e)=>t.weight===e.weight?Number(t.isNested)-Number(e.isNested):t.weight-e.weight))}getRouteAssets(t,e,s=!1){const i=[...e?.assets??[],...e?.css??[],e?.file].reduce(((t,i)=>{if(i){const r=this.getAssetType(i),o=e.isEntry&&e.file===i;r&&(t[i]={url:`/${i}`,weight:o?1.9:this.getAssetWeight(i),type:r,isNested:s,isPreload:!o})}return t}),{});return e?.imports?.length&&e.imports.forEach((e=>{const s=t[e];s&&Object.assign(i,this.getRouteAssets(t,s,!0))})),i}async buildRoutesManifest(){const e=i.init(r.init({isProd:!0},{root:this.getOutDir()})),s=this.loadClientManifest(),{routes:o}=await e.loadEntrypoint(!1),n=await this.getRoutesIds(o),a=this.getRouteImportPostfix(),l={};Object.entries(n).forEach((([t,e])=>{const i=a.find((t=>void 0!==s[`${e}${t}`])),r=s[`${e}${i||""}`];l[t]=this.sortAssets(Object.values(this.getRouteAssets(s,r)))})),t.writeFileSync(this.getAssetsManifestFile(),JSON.stringify(l,null,2),{encoding:"utf-8"})}getAliases(){const t={};return this.viteAliases?.forEach((({find:e,replacement:s})=>{"string"==typeof e&&(t[e]=s)})),t}getRouteImportPostfix(){return["","/index"].map((t=>["",".js",".ts",".tsx"].map((e=>`${t}${e}`)))).flat()}normalizeRoutePath(t,s=!1){if(!t)return;let i="";if(t.startsWith("./")||t.startsWith("../"))i=e.resolve(this.root,t);else{const e=this.getAliases(),[s]=t.split("/");e[s]&&(i=t.replace(s,e[s]))}return i=i.split(e.win32.sep).join(e.posix.sep),s?i:i.replace(this.root,"").replace(/^\/|\/$/g,"")}getAssets(t){if(this.config.getVite())return this.getAssetsDev(t);const e=t?.map((({route:t})=>t.id)).filter(Boolean)??[];if(!e.length)return[];const s=this.loadAssetsManifest();return this.sortAssets(e.map((t=>s[t])).flat().filter(Boolean))}getAssetsDev(t){const e=t?.map((({route:t})=>this.normalizeRoutePath(t?.pathId,!0))).filter(Boolean)??[];if(!e.length)return[];let s={};const i=this.getRouteImportPostfix();return[`${this.root}/${this.config.getPluginConfig()?.clientFile??"client.ts"}`,...e].forEach((t=>{for(const e of i){const i=this.config.getVite()?.moduleGraph.getModuleById(`${t}${e}`);if(i){s={...s,...this.getModuleAssets(i)};break}}})),Object.values(s)}getModuleAssets(t,e=new Set){if(!t?.clientImportedModules.size||e.has(t.file))return{};let i={};return e.add(t.file),t.clientImportedModules.forEach((t=>{const{file:r,clientImportedModules:n,transformResult:a}=t,l=r?.split(".").at(-1);if(r&&l&&["css","scss"].includes(l)){const t=a?.code.match(/__vite__css\s+=\s+"(?<css>.+)"/)?.groups?.css;if(t)try{i[r]={type:o.style,url:r,weight:this.getAssetWeight(r),content:JSON.parse(`{"style": "${t}"}`).style,isNested:Boolean(e.size),isPreload:!1}}catch(t){console.warn(s.yellowBright("Failed to parse style: ",r))}}else n.size&&(i={...i,...this.getModuleAssets(t,e)})})),i}getAssetWeight(t){switch(this.getAssetType(t)){case o.style:return 1;case o.script:return 2;default:return 3}}getAssetType(t){const e=t.split(".").at(-1)?.toLowerCase();switch(e){case"css":case"scss":return o.style;case"js":return o.script;case"svg":case"jpg":case"jpeg":case"png":case"webp":case"gif":case"ico":return o.image;case"ttf":case"otf":case"woff":case"woff2":return o.font;default:return null}}writeEarlyHits(t,e){e.write(`HTTP/1.1 103 Early Hints${n}`),t.forEach((({type:t,url:s})=>{t&&["style","script"].includes(t)&&e.write(`Link: <${s}>; rel=preload; as=${t}${n}`)})),e.write(n)}injectAssets({routerContext:t,html:e,res:s,hasEarlyHints:i=!1}){const r=this.getAssets(t?.matches),n=r.map((({type:t,url:e,isPreload:s,content:i=""})=>{switch(t){case o.style:return this.config.getVite()?`<style data-vite-dev-id="${e}">${i}</style>`:`<link rel="stylesheet" href="${e}">`;case o.script:return s?this.config.isModulePreload?`<link rel="modulepreload" as="script" crossorigin href="${e}">`:null:`<script async type="module" crossorigin src="${e}"><\/script>`}return null})).filter(Boolean);e.header=e.header.replace("</head>",`${n.join("\n")}</head>`),i&&n.length&&s.socket&&this.writeEarlyHits(r,s.socket)}}export{a as default};
1
+ import t from"node:fs";import e from"node:path";import s from"chalk";import i from"./prepare-server.js";import r from"./server-config.js";var o;!function(t){t.style="style",t.script="script",t.image="image",t.font="font"}(o||(o={}));const n="\r\n";class a{static instance=null;config;root;buildDir;manifestName="manifest.json";assetsManifest="assets-manifest.json";viteAliases;routesAssets=null;constructor(t,{buildDir:e,viteAliases:s}={}){this.config=t,this.root=t.getParams().root,this.buildDir=e,this.viteAliases=s??t.getVite()?.config?.resolve.alias}static get(t,e={}){return null===a.instance&&(a.instance=new a(t,e)),a.instance}getOutDir(){return e.resolve(this.root,this.buildDir||"")}getAssetsManifestFile(){return`${this.getOutDir()}/server/${this.assetsManifest}`}loadClientManifest(){const s=e.resolve(this.root,`${this.buildDir||""}/client/.vite`),i=`${s}/${this.manifestName}`;if(!t.existsSync(i))return{};const r=JSON.parse(t.readFileSync(i,{encoding:"utf-8"}));return t.rmSync(i),0===t.readdirSync(s).length&&t.rmSync(s,{recursive:!0}),r}loadAssetsManifest(){if(null!==this.routesAssets)return this.routesAssets;const e=this.getAssetsManifestFile();return t.existsSync(e)?(this.routesAssets=JSON.parse(t.readFileSync(e,{encoding:"utf-8"})),this.routesAssets):{}}async getRoutesIds(t,e){const i={};for(const r in t){const o=t[r],n=[e,r].filter(Boolean).join("-");if(o.lazy)try{const t=await o.lazy();i[n]=this.normalizeRoutePath(t?.pathId)}catch(t){console.error(s.red("Failed to load route:"),o.path,t)}else o.children&&Object.assign(i,await this.getRoutesIds(o.children,n))}return i}sortAssets(t){return t.sort(((t,e)=>t.weight===e.weight?Number(t.isNested)-Number(e.isNested):t.weight-e.weight))}getRouteAssets(t,e,s=!1){const i=[...e?.assets??[],...e?.css??[],e?.file].reduce(((t,i)=>{if(i){const r=this.getAssetType(i),o=e.isEntry&&e.file===i;r&&(t[i]={url:`/${i}`,weight:o?1.9:this.getAssetWeight(i),type:r,isNested:s,isPreload:!o})}return t}),{});return e?.imports?.length&&e.imports.forEach((e=>{const s=t[e];s&&Object.assign(i,this.getRouteAssets(t,s,!0))})),i}async buildRoutesManifest(){const e=i.init(r.init({isProd:!0},{root:this.getOutDir()})),s=this.loadClientManifest(),{routes:o}=await e.loadEntrypoint(!1),n=await this.getRoutesIds(o),a=this.getRouteImportPostfix(),l={};Object.entries(n).forEach((([t,e])=>{const i=a.find((t=>void 0!==s[`${e}${t}`])),r=s[`${e}${i||""}`];l[t]=this.sortAssets(Object.values(this.getRouteAssets(s,r)))})),t.writeFileSync(this.getAssetsManifestFile(),JSON.stringify(l,null,2),{encoding:"utf-8"})}getAliases(){const t={};return this.viteAliases?.forEach((({find:e,replacement:s})=>{"string"==typeof e&&(t[e]=s)})),t}getRouteImportPostfix(){return["","/index"].map((t=>["",".js",".ts",".tsx"].map((e=>`${t}${e}`)))).flat()}normalizeRoutePath(t,s=!1){if(!t)return;let i="";if(t.startsWith("./")||t.startsWith("../"))i=e.resolve(this.root,t);else{const e=this.getAliases(),[s]=t.split("/");e[s]&&(i=t.replace(s,e[s]))}return i=i.split(e.win32.sep).join(e.posix.sep),s?i:i.replace(this.root,"").replace(/^(\/)|(\/)$/g,"")}getAssets(t){if(this.config.getVite())return this.getAssetsDev(t);const e=t?.map((({route:t})=>t.id)).filter(Boolean)??[];if(!e.length)return[];const s=this.loadAssetsManifest();return this.sortAssets(e.map((t=>s[t])).flat().filter(Boolean))}getAssetsDev(t){const e=t?.map((({route:t})=>this.normalizeRoutePath(t?.pathId,!0))).filter(Boolean)??[];if(!e.length)return[];let s={};const i=this.getRouteImportPostfix();return[`${this.root}/${this.config.getPluginConfig()?.clientFile??"client.ts"}`,...e].forEach((t=>{for(const e of i){const i=this.config.getVite()?.moduleGraph.getModuleById(`${t}${e}`);if(i){s={...s,...this.getModuleAssets(i)};break}}})),Object.values(s)}getModuleAssets(t,e=new Set){if(!t?.clientImportedModules.size||e.has(t.file))return{};let i={};return e.add(t.file),t.clientImportedModules.forEach((t=>{const{file:r,clientImportedModules:n,transformResult:a}=t,l=r?.split(".").at(-1);if(r&&l&&["css","scss"].includes(l)){const t=a?.code.match(/__vite__css\s+=\s+"(?<css>.+)"/)?.groups?.css;if(t)try{i[r]={type:o.style,url:r,weight:this.getAssetWeight(r),content:JSON.parse(`{"style": "${t}"}`).style,isNested:Boolean(e.size),isPreload:!1}}catch(t){console.warn(s.yellowBright("Failed to parse style: ",r))}}else n.size&&(i={...i,...this.getModuleAssets(t,e)})})),i}getAssetWeight(t){switch(this.getAssetType(t)){case o.style:return 1;case o.script:return 2;default:return 3}}getAssetType(t){const e=t.split(".").at(-1)?.toLowerCase();switch(e){case"css":case"scss":return o.style;case"js":return o.script;case"svg":case"jpg":case"jpeg":case"png":case"webp":case"gif":case"ico":return o.image;case"ttf":case"otf":case"woff":case"woff2":return o.font;default:return null}}writeEarlyHits(t,e){e.write(`HTTP/1.1 103 Early Hints${n}`),t.forEach((({type:t,url:s})=>{t&&["style","script"].includes(t)&&e.write(`Link: <${s}>; rel=preload; as=${t}${n}`)})),e.write(n)}injectAssets({routerContext:t,html:e,res:s,hasEarlyHints:i=!1}){const r=this.getAssets(t?.matches),n=r.map((({type:t,url:e,isPreload:s,content:i=""})=>{switch(t){case o.style:return this.config.getVite()?`<style data-vite-dev-id="${e}">${i}</style>`:`<link rel="stylesheet" href="${e}">`;case o.script:return s?this.config.isModulePreload?`<link rel="modulepreload" as="script" crossorigin href="${e}">`:null:`<script async type="module" crossorigin src="${e}"><\/script>`}return null})).filter(Boolean);e.header=e.header.replace("</head>",`${n.join("\n")}</head>`),i&&n.length&&s.socket&&this.writeEarlyHits(r,s.socket)}}export{a as default};
2
2
  //# sourceMappingURL=ssr-manifest.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ssr-manifest.js","sources":["../../src/services/ssr-manifest.ts"],"sourcesContent":["import fs from 'node:fs';\nimport type { Socket } from 'node:net';\nimport path from 'node:path';\nimport type { AgnosticDataRouteMatch } from '@remix-run/router/dist/utils';\nimport chalk from 'chalk';\nimport type { RouteObject } from 'react-router-dom';\nimport type { Alias, ModuleNode } from 'vite';\nimport type { IAsyncRoute } from '@helpers/import-route';\nimport type { IRequestContext } from '@node/render';\nimport PrepareServer from '@services/prepare-server';\nimport ServerConfig from '@services/server-config';\n\ninterface ISsrManifestParams {\n buildDir?: string;\n viteAliases?: Alias[];\n}\n\ninterface IManifest {\n [path: string]: {\n assets: string[];\n css: string[];\n file: string;\n isEntry?: boolean;\n imports: string[];\n };\n}\n\nenum AssetType {\n style = 'style',\n script = 'script',\n image = 'image',\n font = 'font',\n}\n\ninterface IAsset {\n type: AssetType;\n url: string;\n weight: number;\n isNested: boolean;\n isPreload: boolean;\n content?: string;\n}\n\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 * Project root path\n */\n protected readonly root: string;\n\n /**\n * Build dir\n */\n protected readonly buildDir?: string;\n\n /**\n * Client manifest file name\n */\n protected readonly manifestName = 'manifest.json';\n\n /**\n * Assets manifest file name\n */\n protected readonly assetsManifest = 'assets-manifest.json';\n\n /**\n * Vite resolve aliases\n */\n protected readonly viteAliases?: Alias[];\n\n /**\n * Loaded assets manifest file\n */\n protected routesAssets: Record<string, IAsset[]> | null = null;\n\n /**\n * @constructor\n */\n protected constructor(config: ServerConfig, { buildDir, viteAliases }: ISsrManifestParams = {}) {\n this.config = config;\n this.root = config.getParams().root;\n this.buildDir = buildDir;\n this.viteAliases = viteAliases ?? config.getVite()?.config?.resolve.alias;\n }\n\n /**\n * Get singleton instance\n */\n public static get(config: ServerConfig, params: ISsrManifestParams = {}): SsrManifest {\n if (SsrManifest.instance === null) {\n SsrManifest.instance = new SsrManifest(config, params);\n }\n\n return SsrManifest.instance;\n }\n\n /**\n * Get 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 getRoutesIds(\n routes: RouteObject[],\n index?: string,\n ): Promise<Record<string, string | undefined>> {\n const result: Record<string, string | undefined> = {};\n\n for (const routeIndex in routes) {\n const route = routes[routeIndex];\n const routeId = [index, routeIndex].filter(Boolean).join('-');\n\n if (route.lazy) {\n try {\n const resolvedRoute: IAsyncRoute = await route.lazy();\n\n result[routeId] = this.normalizeRoutePath(resolvedRoute?.pathId);\n } catch (e) {\n console.error(chalk.red('Failed to load route:'), route.path, e);\n }\n } else if (route.children) {\n Object.assign(result, await this.getRoutesIds(route.children, routeId));\n }\n }\n\n return result;\n }\n\n /**\n * Sort assets\n */\n protected sortAssets(assets: IAsset[]): IAsset[] {\n return assets.sort((a, b) =>\n a.weight === b.weight ? Number(a.isNested) - Number(b.isNested) : a.weight - b.weight,\n );\n }\n\n /**\n * Get recursive module assets\n */\n protected getRouteAssets(\n manifest: IManifest,\n module: IManifest[string],\n isNested = false,\n ): Record<string, IAsset> {\n const rootAssets = [...(module?.assets ?? []), ...(module?.css ?? []), module?.file];\n\n const assets = rootAssets.reduce(\n (res, asset) => {\n if (asset) {\n const type = this.getAssetType(asset);\n const isEntry = module.isEntry && module.file === asset;\n\n // keep only js,css,image,fonts files\n if (type) {\n res[asset] = {\n url: `/${asset}`,\n weight: isEntry ? 1.9 : this.getAssetWeight(asset),\n type,\n isNested,\n isPreload: !isEntry,\n };\n }\n }\n\n return res;\n },\n {} as Record<string, IAsset>,\n );\n\n // nested assets\n if (module?.imports?.length) {\n module.imports.forEach((nestedAsset) => {\n const nestedModule = manifest[nestedAsset];\n\n if (nestedModule) {\n Object.assign(assets, this.getRouteAssets(manifest, nestedModule, true));\n }\n });\n }\n\n return assets;\n }\n\n /**\n * Build routes manifest file\n */\n public async buildRoutesManifest(): Promise<void> {\n const prepareServer = PrepareServer.init(\n ServerConfig.init({ isProd: true }, { root: this.getOutDir() }),\n );\n const manifest = this.loadClientManifest();\n const { routes } = await prepareServer.loadEntrypoint(false);\n const routesPaths = await this.getRoutesIds(routes as RouteObject[]);\n const postfixes = this.getRouteImportPostfix();\n\n const result: Record<string, IAsset[]> = {};\n\n // find route assets\n Object.entries(routesPaths).forEach(([routeId, routePath]) => {\n const routePostfix = postfixes.find((postfix) => {\n const filePath = `${routePath}${postfix}`;\n\n return manifest[filePath] !== undefined;\n });\n const routeFile = `${routePath}${routePostfix || ''}`;\n const routeMeta = manifest[routeFile];\n\n result[routeId] = this.sortAssets(Object.values(this.getRouteAssets(manifest, routeMeta)));\n });\n\n fs.writeFileSync(this.getAssetsManifestFile(), JSON.stringify(result, null, 2), {\n encoding: 'utf-8',\n });\n }\n\n /**\n * Get vite aliases\n */\n protected getAliases(): Record<string, string> {\n const aliases: Record<string, string> = {};\n\n this.viteAliases?.forEach(({ find, replacement }) => {\n if (typeof find !== 'string') {\n return;\n }\n\n aliases[find] = replacement;\n });\n\n return aliases;\n }\n\n /**\n * Return route postfix\n */\n protected getRouteImportPostfix(): string[] {\n return ['', '/index']\n .map((prefix) => ['', '.js', '.ts', '.tsx'].map((ext) => `${prefix}${ext}`))\n .flat();\n }\n\n /**\n * Normalized route path\n */\n protected normalizeRoutePath(routePath?: string, withRoot = false): string | undefined {\n if (!routePath) {\n return;\n }\n\n let fullPath = '';\n\n // relative import\n if (routePath.startsWith('./') || routePath.startsWith('../')) {\n fullPath = path.resolve(this.root, routePath);\n } else {\n // alias import\n const aliases = this.getAliases();\n // get alias\n const [routeAlias] = routePath.split('/');\n\n if (aliases[routeAlias]) {\n fullPath = routePath.replace(routeAlias, aliases[routeAlias]);\n }\n }\n\n // normalize slashes\n fullPath = fullPath.split(path.win32.sep).join(path.posix.sep);\n\n if (withRoot) {\n return fullPath;\n }\n\n return fullPath.replace(this.root, '').replace(/^\\/|\\/$/g, '');\n }\n\n /**\n * Get route assets\n */\n protected getAssets(routes?: AgnosticDataRouteMatch[]): IAsset[] {\n if (this.config.getVite()) {\n return this.getAssetsDev(routes);\n }\n\n const routeIds = routes?.map(({ route }) => route.id).filter(Boolean) ?? [];\n\n if (!routeIds.length) {\n return [];\n }\n\n const routesAssets = this.loadAssetsManifest();\n\n return this.sortAssets(\n routeIds\n .map((routeId) => routesAssets[routeId])\n .flat()\n .filter(Boolean),\n );\n }\n\n /**\n * Get development route assets\n */\n protected getAssetsDev(routes?: AgnosticDataRouteMatch[]): IAsset[] {\n const routeIds =\n (routes\n ?.map(({ route }) => this.normalizeRoutePath((route as IAsyncRoute)?.pathId, true))\n .filter(Boolean) as string[]) ?? [];\n\n if (!routeIds.length) {\n return [];\n }\n\n let assets: TAssets = {};\n const postfixes = this.getRouteImportPostfix();\n const rootId = `${this.root}/${this.config.getPluginConfig()?.clientFile ?? 'client.ts'}`;\n\n [rootId, ...routeIds].forEach((moduleId) => {\n for (const ext of postfixes) {\n const module = this.config.getVite()?.moduleGraph.getModuleById(`${moduleId}${ext}`);\n\n if (module) {\n assets = { ...assets, ...this.getModuleAssets(module) };\n break;\n }\n }\n });\n\n return Object.values(assets);\n }\n\n /**\n * Get module assets\n */\n protected getModuleAssets(module?: ModuleNode, 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}\"}`).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","root","buildDir","manifestName","assetsManifest","viteAliases","routesAssets","constructor","this","getParams","getVite","resolve","alias","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","normalizeRoutePath","pathId","e","console","error","chalk","red","children","Object","assign","getRoutesIds","sortAssets","assets","sort","a","b","weight","Number","isNested","getRouteAssets","manifest","module","css","file","reduce","res","asset","type","getAssetType","isEntry","url","getAssetWeight","isPreload","imports","forEach","nestedAsset","nestedModule","prepareServer","PrepareServer","init","ServerConfig","isProd","loadEntrypoint","routesPaths","postfixes","getRouteImportPostfix","entries","routePath","routePostfix","find","postfix","undefined","routeMeta","values","writeFileSync","stringify","getAliases","aliases","replacement","map","prefix","ext","flat","withRoot","fullPath","startsWith","routeAlias","split","replace","win32","sep","posix","getAssets","getAssetsDev","routeIds","id","getPluginConfig","clientFile","moduleId","moduleGraph","getModuleById","getModuleAssets","skipModules","Set","clientImportedModules","size","has","add","subModule","transformResult","at","includes","code","match","groups","style","content","warn","yellowBright","script","toLowerCase","image","font","writeEarlyHits","socket","write","injectAssets","routerContext","html","hasEarlyHints","matches","htmlAssets","isModulePreload","header"],"mappings":"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"}
1
+ {"version":3,"file":"ssr-manifest.js","sources":["../../src/services/ssr-manifest.ts"],"sourcesContent":["import fs from 'node:fs';\nimport type { Socket } from 'node:net';\nimport path from 'node:path';\nimport type { AgnosticDataRouteMatch } from '@remix-run/router/dist/utils';\nimport chalk from 'chalk';\nimport type { RouteObject } from 'react-router-dom';\nimport type { Alias, ModuleNode } from 'vite';\nimport type { IAsyncRoute } from '@helpers/import-route';\nimport type { IRequestContext } from '@node/render';\nimport PrepareServer from '@services/prepare-server';\nimport ServerConfig from '@services/server-config';\n\ninterface ISsrManifestParams {\n buildDir?: string;\n viteAliases?: Alias[];\n}\n\ninterface IManifest {\n [path: string]: {\n assets: string[];\n css: string[];\n file: string;\n isEntry?: boolean;\n imports: string[];\n };\n}\n\nenum AssetType {\n style = 'style',\n script = 'script',\n image = 'image',\n font = 'font',\n}\n\ninterface IAsset {\n type: AssetType;\n url: string;\n weight: number;\n isNested: boolean;\n isPreload: boolean;\n content?: string;\n}\n\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 * Project root path\n */\n protected readonly root: string;\n\n /**\n * Build dir\n */\n protected readonly buildDir?: string;\n\n /**\n * Client manifest file name\n */\n protected readonly manifestName = 'manifest.json';\n\n /**\n * Assets manifest file name\n */\n protected readonly assetsManifest = 'assets-manifest.json';\n\n /**\n * Vite resolve aliases\n */\n protected readonly viteAliases?: Alias[];\n\n /**\n * Loaded assets manifest file\n */\n protected routesAssets: Record<string, IAsset[]> | null = null;\n\n /**\n * @constructor\n */\n protected constructor(config: ServerConfig, { buildDir, viteAliases }: ISsrManifestParams = {}) {\n this.config = config;\n this.root = config.getParams().root;\n this.buildDir = buildDir;\n this.viteAliases = viteAliases ?? config.getVite()?.config?.resolve.alias;\n }\n\n /**\n * Get singleton instance\n */\n public static get(config: ServerConfig, params: ISsrManifestParams = {}): SsrManifest {\n if (SsrManifest.instance === null) {\n SsrManifest.instance = new SsrManifest(config, params);\n }\n\n return SsrManifest.instance;\n }\n\n /**\n * Get 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 getRoutesIds(\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.normalizeRoutePath(resolvedRoute?.pathId);\n } catch (e) {\n console.error(chalk.red('Failed to load route:'), route.path, e);\n }\n } else if (route.children) {\n Object.assign(result, await this.getRoutesIds(route.children, routeId));\n }\n }\n\n return result;\n }\n\n /**\n * Sort assets\n */\n protected sortAssets(assets: IAsset[]): IAsset[] {\n return assets.sort((a, b) =>\n a.weight === b.weight ? Number(a.isNested) - Number(b.isNested) : a.weight - b.weight,\n );\n }\n\n /**\n * Get recursive module assets\n */\n protected getRouteAssets(\n manifest: IManifest,\n module: IManifest[string],\n isNested = false,\n ): Record<string, IAsset> {\n const rootAssets = [...(module?.assets ?? []), ...(module?.css ?? []), module?.file];\n\n const assets = rootAssets.reduce(\n (res, asset) => {\n if (asset) {\n const type = this.getAssetType(asset);\n const isEntry = module.isEntry && module.file === asset;\n\n // keep only js,css,image,fonts files\n if (type) {\n res[asset] = {\n url: `/${asset}`,\n weight: isEntry ? 1.9 : this.getAssetWeight(asset),\n type,\n isNested,\n isPreload: !isEntry,\n };\n }\n }\n\n return res;\n },\n {} as Record<string, IAsset>,\n );\n\n // nested assets\n if (module?.imports?.length) {\n module.imports.forEach((nestedAsset) => {\n const nestedModule = manifest[nestedAsset];\n\n if (nestedModule) {\n Object.assign(assets, this.getRouteAssets(manifest, nestedModule, true));\n }\n });\n }\n\n return assets;\n }\n\n /**\n * Build routes manifest file\n */\n public async buildRoutesManifest(): Promise<void> {\n const prepareServer = PrepareServer.init(\n ServerConfig.init({ isProd: true }, { root: this.getOutDir() }),\n );\n const manifest = this.loadClientManifest();\n const { routes } = await prepareServer.loadEntrypoint(false);\n const routesPaths = await this.getRoutesIds(routes as RouteObject[]);\n const postfixes = this.getRouteImportPostfix();\n\n const result: Record<string, IAsset[]> = {};\n\n // find route assets\n Object.entries(routesPaths).forEach(([routeId, routePath]) => {\n const routePostfix = postfixes.find((postfix) => {\n const filePath = `${routePath}${postfix}`;\n\n return manifest[filePath] !== undefined;\n });\n const routeFile = `${routePath}${routePostfix || ''}`;\n const routeMeta = manifest[routeFile];\n\n result[routeId] = this.sortAssets(Object.values(this.getRouteAssets(manifest, routeMeta)));\n });\n\n fs.writeFileSync(this.getAssetsManifestFile(), JSON.stringify(result, null, 2), {\n encoding: 'utf-8',\n });\n }\n\n /**\n * Get vite aliases\n */\n protected getAliases(): Record<string, string> {\n const aliases: Record<string, string> = {};\n\n this.viteAliases?.forEach(({ find, replacement }) => {\n if (typeof find !== 'string') {\n return;\n }\n\n aliases[find] = replacement;\n });\n\n return aliases;\n }\n\n /**\n * Return route postfix\n */\n protected getRouteImportPostfix(): string[] {\n return ['', '/index']\n .map((prefix) => ['', '.js', '.ts', '.tsx'].map((ext) => `${prefix}${ext}`))\n .flat();\n }\n\n /**\n * Normalized route path\n */\n protected normalizeRoutePath(routePath?: string, withRoot = false): string | undefined {\n if (!routePath) {\n return;\n }\n\n let fullPath = '';\n\n // relative import\n if (routePath.startsWith('./') || routePath.startsWith('../')) {\n fullPath = path.resolve(this.root, routePath);\n } else {\n // alias import\n const aliases = this.getAliases();\n // get alias\n const [routeAlias] = routePath.split('/');\n\n if (aliases[routeAlias]) {\n fullPath = routePath.replace(routeAlias, aliases[routeAlias]);\n }\n }\n\n // normalize slashes\n fullPath = fullPath.split(path.win32.sep).join(path.posix.sep);\n\n if (withRoot) {\n return fullPath;\n }\n\n return fullPath.replace(this.root, '').replace(/^(\\/)|(\\/)$/g, '');\n }\n\n /**\n * Get route assets\n */\n protected getAssets(routes?: AgnosticDataRouteMatch[]): IAsset[] {\n if (this.config.getVite()) {\n return this.getAssetsDev(routes);\n }\n\n const routeIds = routes?.map(({ route }) => route.id).filter(Boolean) ?? [];\n\n if (!routeIds.length) {\n return [];\n }\n\n const routesAssets = this.loadAssetsManifest();\n\n return this.sortAssets(\n routeIds\n .map((routeId) => routesAssets[routeId])\n .flat()\n .filter(Boolean),\n );\n }\n\n /**\n * Get development route assets\n */\n protected getAssetsDev(routes?: AgnosticDataRouteMatch[]): IAsset[] {\n const routeIds =\n (routes\n ?.map(({ route }) => this.normalizeRoutePath((route as IAsyncRoute)?.pathId, true))\n .filter(Boolean) as string[]) ?? [];\n\n if (!routeIds.length) {\n return [];\n }\n\n let assets: TAssets = {};\n const postfixes = this.getRouteImportPostfix();\n const rootId = `${this.root}/${this.config.getPluginConfig()?.clientFile ?? 'client.ts'}`;\n\n [rootId, ...routeIds].forEach((moduleId) => {\n for (const ext of postfixes) {\n const module = this.config.getVite()?.moduleGraph.getModuleById(`${moduleId}${ext}`);\n\n if (module) {\n assets = { ...assets, ...this.getModuleAssets(module) };\n break;\n }\n }\n });\n\n return Object.values(assets);\n }\n\n /**\n * Get module assets\n */\n protected getModuleAssets(module?: ModuleNode, 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","root","buildDir","manifestName","assetsManifest","viteAliases","routesAssets","constructor","this","getParams","getVite","resolve","alias","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","normalizeRoutePath","pathId","e","console","error","chalk","red","children","Object","assign","getRoutesIds","sortAssets","assets","sort","a","b","weight","Number","isNested","getRouteAssets","manifest","module","css","file","reduce","res","asset","type","getAssetType","isEntry","url","getAssetWeight","isPreload","imports","forEach","nestedAsset","nestedModule","prepareServer","PrepareServer","init","ServerConfig","isProd","loadEntrypoint","routesPaths","postfixes","getRouteImportPostfix","entries","routePath","routePostfix","find","postfix","undefined","routeMeta","values","writeFileSync","stringify","getAliases","aliases","replacement","map","prefix","ext","flat","withRoot","fullPath","startsWith","routeAlias","split","replace","win32","sep","posix","getAssets","getAssetsDev","routeIds","id","getPluginConfig","clientFile","moduleId","moduleGraph","getModuleById","getModuleAssets","skipModules","Set","clientImportedModules","size","has","add","subModule","transformResult","at","includes","code","match","groups","style","content","warn","yellowBright","script","toLowerCase","image","font","writeEarlyHits","socket","write","injectAssets","routerContext","html","hasEarlyHints","matches","htmlAssets","isModulePreload","header"],"mappings":"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"}