diff --git a/package-lock.json b/package-lock.json index 482a3c20f..04e23b6b1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5368,7 +5368,7 @@ }, "devDependencies": { "@types/deepmerge": "^2.2.0", - "@types/node": "^14.0", + "@types/node": "^18.4", "@types/nprogress": "^0.2.0", "@types/qs": "^6.9.0", "esbuild": "^0.16.13", @@ -5377,11 +5377,14 @@ } }, "packages/core/node_modules/@types/node": { - "version": "14.18.63", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.63.tgz", - "integrity": "sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ==", + "version": "18.19.74", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.74.tgz", + "integrity": "sha512-HMwEkkifei3L605gFdV+/UwtpxP6JSzM+xFk2Ia6DNFSwSVBRh9qp5Tgf4lNFOMfPVuU0WnkcWpXZpgn5ufO4A==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "undici-types": "~5.26.4" + } }, "packages/core/node_modules/typescript": { "version": "4.9.5", @@ -5397,6 +5400,13 @@ "node": ">=4.2.0" } }, + "packages/core/node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true, + "license": "MIT" + }, "packages/react": { "name": "@inertiajs/react", "version": "2.0.3", diff --git a/packages/core/package.json b/packages/core/package.json index 9cc60d4d3..9c31d6411 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -57,7 +57,7 @@ }, "devDependencies": { "@types/deepmerge": "^2.2.0", - "@types/node": "^14.0", + "@types/node": "^18.4", "@types/nprogress": "^0.2.0", "@types/qs": "^6.9.0", "esbuild": "^0.16.13", diff --git a/packages/core/src/server.ts b/packages/core/src/server.ts index 0be5230c6..b3d061809 100644 --- a/packages/core/src/server.ts +++ b/packages/core/src/server.ts @@ -1,9 +1,16 @@ import { createServer, IncomingMessage } from 'http' import * as process from 'process' import { InertiaAppResponse, Page } from './types' +import cluster from 'node:cluster'; +import { availableParallelism } from 'node:os'; type AppCallback = (page: Page) => InertiaAppResponse type RouteHandler = (request: IncomingMessage) => Promise +type ServerOptions = { + port?: number + cluster?: boolean +} +type Port = number const readableToString: (readable: IncomingMessage) => Promise = (readable) => new Promise((resolve, reject) => { @@ -13,8 +20,23 @@ const readableToString: (readable: IncomingMessage) => Promise = (readab readable.on('error', (err) => reject(err)) }) -export default (render: AppCallback, port?: number): void => { - const _port = port || 13714 +export default (render: AppCallback, options?: Port | ServerOptions): void => { + const _port = typeof options === 'number' ? options : options?.port ?? 13714; + const _useCluster = typeof options === 'object' && options?.cluster !== undefined ? options.cluster : false; + + const log = (message: string) => { + console.log(_useCluster && !cluster.isPrimary ? `[${cluster.worker?.id ?? 'N/A'} / ${cluster.worker?.process?.pid ?? 'N/A'}] ${message}` : message) + } + + if (_useCluster && cluster.isPrimary) { + log('Primary Inertia SSR server process started...') + + for (let i = 0; i < availableParallelism(); i++) { + cluster.fork() + } + + return + } const routes: Record = { '/health': async () => ({ status: 'OK', timestamp: Date.now() }), @@ -34,7 +56,7 @@ export default (render: AppCallback, port?: number): void => { } response.end() - }).listen(_port, () => console.log('Inertia SSR server started.')) + }).listen(_port, () => log('Inertia SSR server started.')) - console.log(`Starting SSR server on port ${_port}...`) + log(`Starting SSR server on port ${_port}...`) }