Skip to content

Commit

Permalink
refactor(web): improve server configuration and startup logic
Browse files Browse the repository at this point in the history
Enhanced server configuration schema with annotations and streamlined
 `NODE_ENV` handling. Refactored code to replace redundant logic with
  a cleaner `switch` statement for environment handling. Updated
  build path argument parsing to ensure correct application startup.
  • Loading branch information
suddenlyGiovanni committed Dec 17, 2024
1 parent 7fa09a9 commit 4e7e746
Showing 1 changed file with 64 additions and 60 deletions.
124 changes: 64 additions & 60 deletions apps/web/server/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,19 @@ import type { ViteDevServer } from 'vite'
class Config extends Schema.Class<Config>('Config')({
NODE_ENV: Schema.optionalWith(Schema.Literal('development', 'production'), {
default: () => 'production',
}).annotations({
description: 'Environment to run the server in',
}),
PORT: Schema.optional(Schema.NumberFromString.pipe(Schema.int())).annotations({
description: 'Port to run the server on',
}),
HOST: Schema.optional(Schema.String).annotations({
description: 'Host to run the server on',
}),
buildPathArg: Schema.String.annotations({
description: 'Path to the server build',
message: () => 'Usage: node server/server.ts <server-build-path>',
}),
PORT: Schema.optional(Schema.NumberFromString.pipe(Schema.int())),
HOST: Schema.optional(Schema.String),
}) {
static decodeUnknownSync = Schema.decodeUnknownSync(this)
}
Expand Down Expand Up @@ -72,18 +82,57 @@ async function run({
NODE_ENV: 'development' | 'production'
PORT: number
HOST: undefined | string
buildPathArg: undefined | string
buildPathArg: string
}): Promise<void> {
const isDevelopment = NODE_ENV === 'development'
const app: express.Express = express()

app.disable('x-powered-by')

app.use(compression())

switch (NODE_ENV) {
case 'development': {
console.log('Starting development server')

const viteDevServer: ViteDevServer = await import('vite').then(vite =>
vite.createServer({
server: { middlewareMode: true },
}),
)

app.use(viteDevServer.middlewares)
app.use(async (req, res, next) => {
try {
const source = (await viteDevServer.ssrLoadModule('./server/app.ts')) as {
app: express.Express
}
return await source.app(req, res, next)
} catch (error: unknown) {
if (typeof error === 'object' && error instanceof Error) {
viteDevServer.ssrFixStacktrace(error)
}
next(error)
}
})

break
}
case 'production': {
console.log('Starting production server')

app.use('/assets', express.static('build/client/assets', { immutable: true, maxAge: '1y' }))

app.use(express.static('build/client', { maxAge: '1h' }))

if (!buildPathArg) {
// biome-ignore lint/suspicious/noConsole: <explanation>
console.error(`
Usage: node server/server.ts <server-build-path>`)
process.exit(1)
app.use(await import(path.resolve(buildPathArg)).then(mod => mod.app))

break
}
default:
throw new Error(`Unknown NODE_ENV: ${NODE_ENV}`)
}

const buildPath = path.resolve(buildPathArg)
app.use(morgan('tiny'))

const onListen = (): void => {
const address =
Expand All @@ -93,69 +142,24 @@ async function run({
.find(ip => String(ip?.family).includes('4') && !ip?.internal)?.address

if (address) {
// biome-ignore lint/suspicious/noConsoleLog: <explanation>
// biome-ignore lint/suspicious/noConsole: <explanation>
console.log(`[react-router-serve] http://localhost:${PORT} (http://${address}:${PORT})`)
} else {
// biome-ignore lint/suspicious/noConsole: <explanation>
// biome-ignore lint/suspicious/noConsoleLog: <explanation>
console.log(`[react-router-serve] http://localhost:${PORT}`)
}
}

const app: express.Express = express()

app.disable('x-powered-by')

app.use(compression())

if (isDevelopment) {
console.log('Starting development server')

const viteDevServer: ViteDevServer = await import('vite').then(vite =>
vite.createServer({
server: { middlewareMode: true },
}),
)

app.use(viteDevServer.middlewares)
app.use(async (req, res, next) => {
try {
const source = (await viteDevServer.ssrLoadModule('./server/app.ts')) as {
app: express.Express
}
return await source.app(req, res, next)
} catch (error: unknown) {
if (typeof error === 'object' && error instanceof Error) {
viteDevServer.ssrFixStacktrace(error)
}
next(error)
}
})
} else {
console.log('Starting production server')

app.use('/assets', express.static('build/client/assets', { immutable: true, maxAge: '1y' }))

app.use(express.static('build/client', { maxAge: '1h' }))

app.use(await import(buildPath).then(mod => mod.app))
}

app.use(morgan('tiny'))

const server = HOST ? app.listen(PORT, HOST, onListen) : app.listen(PORT, onListen)

for (const signal of ['SIGTERM', 'SIGINT']) {
process.once(signal, () => server?.close(console.error))
}
}

const env = Config.decodeUnknownSync(process.env)
const config = Config.decodeUnknownSync({ ...process.env, buildPathArg: process.argv[2] })

run({
NODE_ENV: env.NODE_ENV,
PORT: await getPort({ port: env.PORT ?? 5173 }),
HOST: env.HOST,
buildPathArg: process.argv[2],
NODE_ENV: config.NODE_ENV,
PORT: await getPort({ port: config.PORT ?? 5173 }),
HOST: config.HOST,
buildPathArg: config.buildPathArg,
})

0 comments on commit 4e7e746

Please sign in to comment.