entry-server.js 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. import { createApp } from './main'
  2. import { renderToString } from '@vue/server-renderer'
  3. import {
  4. UNI_SSR,
  5. UNI_SSR_DATA,
  6. UNI_SSR_STORE,
  7. UNI_SSR_TITLE,
  8. UNI_SSR_GLOBAL_DATA,
  9. } from '@dcloudio/uni-shared'
  10. import { plugin } from '@dcloudio/uni-h5'
  11. import { getSsrGlobalData } from '@dcloudio/uni-app'
  12. export async function render(url, manifest = {}) {
  13. const { app, store } = createApp()
  14. app.use(plugin)
  15. const router = app.router
  16. // set the router to the desired URL before rendering
  17. await router.push(url)
  18. await router.isReady()
  19. // passing SSR context object which will be available via useSSRContext()
  20. // @vitejs/plugin-vue injects code into a component's setup() that registers
  21. // itself on ctx.modules. After the render, ctx.modules would contain all the
  22. // components that have been instantiated during this render call.
  23. const ctx = {}
  24. const appHtml = await renderToString(app, ctx)
  25. // the SSR manifest generated by Vite contains module -> chunk/asset mapping
  26. // which we can then use to determine what files need to be preloaded for this
  27. // request.
  28. const preloadLinks = renderPreloadLinks(ctx.modules, manifest)
  29. // the SSR context
  30. const __uniSSR = ctx[UNI_SSR] || (ctx[UNI_SSR] = {})
  31. if (!__uniSSR[UNI_SSR_DATA]) {
  32. __uniSSR[UNI_SSR_DATA] = {}
  33. }
  34. __uniSSR[UNI_SSR_GLOBAL_DATA] = getSsrGlobalData()
  35. if (store) {
  36. __uniSSR[UNI_SSR_STORE] = store.state
  37. }
  38. const appContext = renderAppContext(ctx)
  39. const title = ctx[UNI_SSR_TITLE] || ''
  40. const headMeta = renderHeadMeta(ctx)
  41. return {
  42. title,
  43. headMeta,
  44. preloadLinks,
  45. appHtml,
  46. appContext,
  47. }
  48. }
  49. function renderPreloadLinks(modules, manifest) {
  50. let links = ''
  51. const seen = new Set()
  52. modules.forEach((id) => {
  53. const files = manifest[id]
  54. if (files) {
  55. files.forEach((file) => {
  56. if (!seen.has(file)) {
  57. seen.add(file)
  58. links += renderPreloadLink(file)
  59. }
  60. })
  61. }
  62. })
  63. return links
  64. }
  65. function renderPreloadLink(file) {
  66. if (file.endsWith('.js')) {
  67. return '<link rel="modulepreload" crossorigin href="' + file + '">'
  68. } else if (file.endsWith('.css')) {
  69. return '<link rel="stylesheet" href="' + file + '">'
  70. } else {
  71. // TODO
  72. return ''
  73. }
  74. }
  75. function renderAppContext(ctx) {
  76. return `<script>window.__uniSSR = ${JSON.stringify(ctx[UNI_SSR])}</script>`
  77. }
  78. function renderHeadMeta(ctx) {
  79. if (!ctx.__teleportBuffers || !ctx.__teleportBuffers.head) {
  80. return ''
  81. }
  82. return ctx.__teleportBuffers.head
  83. .map((buffer) =>
  84. buffer
  85. .toString()
  86. .replace(/\s+data-v-[a-f0-9]{8}/gi, '')
  87. .replace('<!--[-->', '')
  88. .replace('<!--]--><!---->', '')
  89. )
  90. .join('\n')
  91. }