server.js 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. // @ts-check
  2. const fs = require('fs')
  3. const path = require('path')
  4. const express = require('express')
  5. const isTest = process.env.NODE_ENV === 'test' || !!process.env.VITE_TEST_BUILD
  6. async function createServer(
  7. root = process.cwd(),
  8. isProd = process.env.NODE_ENV === 'production'
  9. ) {
  10. const resolve = (p) => path.resolve(__dirname, p)
  11. const indexProd = isProd
  12. ? fs.readFileSync(resolve('dist/client/index.html'), 'utf-8')
  13. : ''
  14. const manifest = isProd
  15. ? // @ts-ignore
  16. require('./dist/client/ssr-manifest.json')
  17. : {}
  18. const app = express()
  19. /**
  20. * @type {import('vite').ViteDevServer}
  21. */
  22. let vite
  23. if (!isProd) {
  24. vite = await require('vite').createServer({
  25. root,
  26. logLevel: isTest ? 'error' : 'info',
  27. server: {
  28. middlewareMode: 'ssr',
  29. watch: {
  30. // During tests we edit the files too fast and sometimes chokidar
  31. // misses change events, so enforce polling for consistency
  32. usePolling: true,
  33. interval: 100
  34. }
  35. }
  36. })
  37. // use vite's connect instance as middleware
  38. app.use(vite.middlewares)
  39. } else {
  40. app.use(require('compression')())
  41. app.use(
  42. require('serve-static')(resolve('dist/client'), {
  43. index: false
  44. })
  45. )
  46. }
  47. app.use('*', async (req, res) => {
  48. try {
  49. const url = req.originalUrl
  50. let template, render
  51. if (!isProd) {
  52. // always read fresh template in dev
  53. template = fs.readFileSync(resolve('index.html'), 'utf-8')
  54. template = await vite.transformIndexHtml(url, template)
  55. render = (await vite.ssrLoadModule('/src/entry-server.js')).render
  56. } else {
  57. template = indexProd
  58. // @ts-ignore
  59. render = require('./dist/server/entry-server.js').render
  60. }
  61. const [appHtml, preloadLinks] = await render(url, manifest)
  62. const html = template
  63. .replace(`<!--preload-links-->`, preloadLinks)
  64. .replace(`<!--app-html-->`, appHtml)
  65. res.status(200).set({ 'Content-Type': 'text/html' }).end(html)
  66. } catch (e) {
  67. vite && vite.ssrFixStacktrace(e)
  68. console.log(e.stack)
  69. res.status(500).end(e.stack)
  70. }
  71. })
  72. return { app, vite }
  73. }
  74. if (!isTest) {
  75. createServer().then(({ app }) =>
  76. app.listen(5173, () => {
  77. console.log('http://localhost:5173')
  78. })
  79. )
  80. }
  81. // for test use
  82. exports.createServer = createServer