import {createRequestHandler} from '@remix-run/express'; import compression from 'compression'; import express from 'express'; import morgan from 'morgan'; const isProduction = process.env.NODE_ENV === 'production'; const app = express(); let server; if (isProduction) { const {createServer} = await import('node:http'); server = createServer(app); } else { const {execSync} = await import('node:child_process'); const {mkdirSync, readFileSync, statSync} = await import('node:fs'); const cacheDirectory = `${import.meta.dirname}/node_modules/.cache`; mkdirSync(cacheDirectory, {recursive: true}); try { statSync(`${cacheDirectory}/localhost-key.pem`); } catch (error) { // eslint-disable-line no-unused-vars execSync(`mkcert -cert-file ${cacheDirectory}/localhost.pem -key-file ${cacheDirectory}/localhost-key.pem localhost`) } const serverOptions = { key: readFileSync(`${cacheDirectory}/localhost-key.pem`), cert: readFileSync(`${cacheDirectory}/localhost.pem`), }; const {createServer} = await import('node:https'); server = createServer(serverOptions, app); } const viteDevServer = isProduction ? undefined : await import('vite').then((vite) => vite.createServer({ server: {middlewareMode: {server}}, }) ); const remixHandler = createRequestHandler({ build: () => ( viteDevServer ? viteDevServer.ssrLoadModule('virtual:remix/server-build') : import('./build/server/index.js') ), }); // WebSocket let listen; if (isProduction) { ({listen} = await import('./websocket.js')); } else { const {createViteRuntime} = await import('vite'); const runtime = await createViteRuntime(viteDevServer); ({listen} = await runtime.executeEntrypoint('/websocket.js')); } await listen(server); app.use(compression()); // http://expressjs.com/en/advanced/best-practice-security.html#at-a-minimum-disable-x-powered-by-header app.disable('x-powered-by'); // handle asset requests if (viteDevServer) { app.use(viteDevServer.middlewares); } else { // Vite fingerprints its assets so we can cache forever. app.use( '/assets', express.static('build/client/assets', { immutable: true, maxAge: '1y' }) ); } // Everything else (like favicon.ico) is cached for an hour. You may want to be // more aggressive with this caching. app.use(express.static('build/client', { maxAge: '1h' })); app.use(morgan('tiny')); // handle SSR requests app.all('*', remixHandler); const port = process.env.PORT || 3000; server.listen(port, () => console.log(`Express server listening at http${isProduction ? '' : 's'}://localhost:${port}`) );