| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104 |
- import fs from 'node:fs/promises'
- import express from 'express'
- import { Transform } from 'node:stream'
- // Constants
- const isProduction = process.env.NODE_ENV === 'production'
- const port = process.env.PORT || 5173
- const base = process.env.BASE || '/'
- const ABORT_DELAY = 10000
- // Cached production assets
- const templateHtml = isProduction
- ? await fs.readFile('./dist/client/index.html', 'utf-8')
- : ''
- // Create http server
- const app = express()
- // Add Vite or respective production middlewares
- /** @type {import('vite').ViteDevServer | undefined} */
- let vite
- if (!isProduction) {
- const { createServer } = await import('vite')
- vite = await createServer({
- server: { middlewareMode: true },
- appType: 'custom',
- base,
- })
- app.use(vite.middlewares)
- } else {
- const compression = (await import('compression')).default
- const sirv = (await import('sirv')).default
- app.use(compression())
- app.use(base, sirv('./dist/client', { extensions: [] }))
- }
- // Serve HTML
- app.use('*all', async (req, res) => {
- try {
- const url = req.originalUrl.replace(base, '')
- /** @type {string} */
- let template
- /** @type {import('./src/entry-server.ts').render} */
- let render
- if (!isProduction) {
- // Always read fresh template in development
- template = await fs.readFile('./index.html', 'utf-8')
- template = await vite.transformIndexHtml(url, template)
- render = (await vite.ssrLoadModule('/src/entry-server.tsx')).render
- } else {
- template = templateHtml
- render = (await import('./dist/server/entry-server.js')).render
- }
- let didError = false
- const { pipe, abort } = render(url, {
- onShellError() {
- res.status(500)
- res.set({ 'Content-Type': 'text/html' })
- res.send('<h1>Something went wrong</h1>')
- },
- onShellReady() {
- res.status(didError ? 500 : 200)
- res.set({ 'Content-Type': 'text/html' })
- const transformStream = new Transform({
- transform(chunk, encoding, callback) {
- res.write(chunk, encoding)
- callback()
- },
- })
- const [htmlStart, htmlEnd] = template.split(`<!--app-html-->`)
- res.write(htmlStart)
- transformStream.on('finish', () => {
- res.end(htmlEnd)
- })
- pipe(transformStream)
- },
- onError(error) {
- didError = true
- console.error(error)
- },
- })
- setTimeout(() => {
- abort()
- }, ABORT_DELAY)
- } catch (e) {
- vite?.ssrFixStacktrace(e)
- console.log(e.stack)
- res.status(500).end(e.stack)
- }
- })
- // Start http server
- app.listen(port, () => {
- console.log(`Server started at http://localhost:${port}`)
- })
|