Refactoring to Typescript...
This commit is contained in:
@@ -0,0 +1,124 @@
|
||||
import path from 'path'
|
||||
import fs from 'fs/promises'
|
||||
|
||||
import express from 'express'
|
||||
import morgan from 'morgan'
|
||||
|
||||
import { createServer as createViteServer } from 'vite'
|
||||
|
||||
import { createApiRouter } from './server/routes.js'
|
||||
import { RenderFunction } from './shared/ssr.js'
|
||||
|
||||
const HTML_ROUTES = ['/', '/login', '/problem/:id', '/admin', '/profile']
|
||||
|
||||
const config = {
|
||||
isDevelopment: process.env.MODE === 'development',
|
||||
port: process.env.PORT || 3000,
|
||||
}
|
||||
|
||||
if (config.isDevelopment) {
|
||||
console.log(`[Config] Running in development mode`)
|
||||
console.log(`[Config] PORT = ${config.port}`)
|
||||
}
|
||||
|
||||
function mountIndexHtmlRoutes(r, serveIndexHtml) {
|
||||
for (const route of HTML_ROUTES) {
|
||||
console.log(`[Server] Mounted index html for "${route}"`)
|
||||
r.get(route, serveIndexHtml)
|
||||
}
|
||||
|
||||
r.use('*', (_req, res) => {
|
||||
res.redirect('/')
|
||||
})
|
||||
}
|
||||
|
||||
async function createDevRouter() {
|
||||
const r = express.Router()
|
||||
|
||||
const vite = await createViteServer({
|
||||
server: { middlewareMode: true },
|
||||
appType: 'custom',
|
||||
})
|
||||
|
||||
r.use(vite.middlewares)
|
||||
mountIndexHtmlRoutes(r, async (req, res, next) => {
|
||||
try {
|
||||
const indexHtml = await fs.readFile(path.resolve('./index.html'), 'utf-8')
|
||||
const transformedTemplate = await vite.transformIndexHtml(req.originalUrl, indexHtml)
|
||||
|
||||
// Load (to be bundled) entry point for server side rendering
|
||||
const render: RenderFunction = (await vite.ssrLoadModule('./client/entry-server.tsx'))
|
||||
.default
|
||||
|
||||
const { html, metadata } = render(req.originalUrl)
|
||||
|
||||
process.stdout.write('[Metadata] ')
|
||||
console.dir(metadata)
|
||||
|
||||
const fullUrl = `${req.protocol}://${req.get('host')}${req.originalUrl}`
|
||||
const metaTagsHtml =
|
||||
'' +
|
||||
(metadata.title
|
||||
? `<meta property="og:title" content="${metadata.title}" />\n`
|
||||
: '') +
|
||||
(metadata.description
|
||||
? `<meta property="og:description" content="${metadata.description}" />\n`
|
||||
: '') +
|
||||
`<meta property="og:url" content="${fullUrl}" />\n`
|
||||
|
||||
res.send(
|
||||
transformedTemplate
|
||||
.replace('<!-- INJECT META TAGS -->', metaTagsHtml)
|
||||
.replace('<!-- SSR OUTLET -->', html)
|
||||
)
|
||||
} catch (error) {
|
||||
vite.ssrFixStacktrace(error)
|
||||
next(error)
|
||||
}
|
||||
})
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
async function createProductionRouter() {
|
||||
// Load bundled entry point for server side rendering
|
||||
const render: RenderFunction = ((await import('./dist/entry-server/entry-server.js')) as any)
|
||||
.default
|
||||
|
||||
const r = express.Router()
|
||||
|
||||
r.use('/', express.static('dist/client'))
|
||||
|
||||
mountIndexHtmlRoutes(r, async (req, res) => {
|
||||
const transformedTemplate = await fs.readFile(
|
||||
path.resolve('./dist/client/index.html'),
|
||||
'utf-8'
|
||||
)
|
||||
|
||||
const { html, metadata } = render(req.originalUrl)
|
||||
|
||||
res.send(transformedTemplate.replace('<!-- SSR OUTLET -->', html))
|
||||
})
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const app = express()
|
||||
|
||||
app.use(morgan('dev'))
|
||||
|
||||
app.use('/', await createApiRouter())
|
||||
|
||||
if (config.isDevelopment) {
|
||||
app.use('/', await createDevRouter())
|
||||
} else {
|
||||
app.use('/', await createProductionRouter())
|
||||
}
|
||||
|
||||
app.listen(config.port, () => {
|
||||
console.log(`Listening on port ${config.port}...`)
|
||||
})
|
||||
}
|
||||
|
||||
main()
|
||||
Reference in New Issue
Block a user