render.js 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. "use strict";
  2. var __importDefault = (this && this.__importDefault) || function (mod) {
  3. return (mod && mod.__esModule) ? mod : { "default": mod };
  4. };
  5. Object.defineProperty(exports, "__esModule", { value: true });
  6. exports.renderPage = void 0;
  7. const path_1 = __importDefault(require("path"));
  8. const fs_extra_1 = __importDefault(require("fs-extra"));
  9. const config_1 = require("../config");
  10. const escape = require('escape-html');
  11. async function renderPage(config, page, // foo.md
  12. result, appChunk, cssChunk, pageToHashMap, hashMapStirng) {
  13. const { createApp } = require(path_1.default.join(config.tempDir, `_assets/app.js`));
  14. const { app, router } = createApp();
  15. const routePath = `/${page.replace(/\.md$/, '')}`;
  16. const siteData = config_1.resolveSiteDataByRoute(config.site, routePath);
  17. router.go(routePath);
  18. // lazy require server-renderer for production build
  19. const content = await require('@vue/server-renderer').renderToString(app);
  20. const pageName = page.replace(/\//g, '_');
  21. // server build doesn't need hash
  22. const pageServerJsFileName = pageName + '.js';
  23. // for any initial page load, we only need the lean version of the page js
  24. // since the static content is already on the page!
  25. const pageHash = pageToHashMap[pageName];
  26. const pageClientJsFileName = pageName + `.` + pageHash + '.lean.js';
  27. // resolve page data so we can render head tags
  28. const { __pageData } = require(path_1.default.join(config.tempDir, `_assets`, pageServerJsFileName));
  29. const pageData = JSON.parse(__pageData);
  30. const assetPath = `${siteData.base}_assets/`;
  31. const preloadLinks = [
  32. // resolve imports for index.js + page.md.js and inject script tags for
  33. // them as well so we fetch everything as early as possible without having
  34. // to wait for entry chunks to parse
  35. ...resolvePageImports(config, page, result, appChunk),
  36. pageClientJsFileName,
  37. appChunk.fileName
  38. ]
  39. .map((file) => {
  40. return `<link rel="modulepreload" href="${assetPath}${file}">`;
  41. })
  42. .join('\n ');
  43. const html = `
  44. <!DOCTYPE html>
  45. <html lang="${siteData.lang}">
  46. <head>
  47. <meta charset="utf-8">
  48. <meta name="viewport" content="width=device-width,initial-scale=1">
  49. <title>
  50. ${pageData.title ? pageData.title + ` | ` : ``}${siteData.title}
  51. </title>
  52. <meta name="description" content="${siteData.description}">
  53. <link rel="stylesheet" href="${assetPath}${cssChunk.fileName}">
  54. ${preloadLinks}
  55. ${renderHead(siteData.head)}
  56. ${renderHead(pageData.frontmatter.head)}
  57. </head>
  58. <body>
  59. <div id="app">${content}</div>
  60. <script>__VP_HASH_MAP__ = JSON.parse(${hashMapStirng})</script>
  61. <script type="module" async src="${assetPath}${appChunk.fileName}"></script>
  62. </body>
  63. </html>`.trim();
  64. const htmlFileName = path_1.default.join(config.outDir, page.replace(/\.md$/, '.html'));
  65. await fs_extra_1.default.ensureDir(path_1.default.dirname(htmlFileName));
  66. await fs_extra_1.default.writeFile(htmlFileName, html);
  67. }
  68. exports.renderPage = renderPage;
  69. function resolvePageImports(config, page, result, indexChunk) {
  70. // find the page's js chunk and inject script tags for its imports so that
  71. // they are start fetching as early as possible
  72. const srcPath = path_1.default.resolve(config.root, page);
  73. const pageChunk = result.assets.find((chunk) => chunk.type === 'chunk' && chunk.facadeModuleId === srcPath);
  74. return Array.from(new Set([...indexChunk.imports, ...pageChunk.imports]));
  75. }
  76. function renderHead(head) {
  77. if (!head || !head.length) {
  78. return '';
  79. }
  80. return head
  81. .map(([tag, attrs = {}, innerHTML = '']) => {
  82. const openTag = `<${tag}${renderAttrs(attrs)}>`;
  83. if (tag !== 'link' && tag !== 'meta') {
  84. return `${openTag}${innerHTML}</${tag}>`;
  85. }
  86. else {
  87. return openTag;
  88. }
  89. })
  90. .join('\n ');
  91. }
  92. function renderAttrs(attrs) {
  93. return Object.keys(attrs)
  94. .map((key) => {
  95. return ` ${key}="${escape(attrs[key])}"`;
  96. })
  97. .join('');
  98. }
  99. //# sourceMappingURL=render.js.map