|
|
|
@ -3,13 +3,14 @@ import { promises as fs } from 'fs'
|
|
|
|
|
import { SiteConfig, HeadConfig } from '../config'
|
|
|
|
|
import { BuildResult } from 'vite'
|
|
|
|
|
import { renderToString } from '@vue/server-renderer'
|
|
|
|
|
import { OutputChunk } from 'rollup'
|
|
|
|
|
|
|
|
|
|
const escape = require('escape-html')
|
|
|
|
|
|
|
|
|
|
export async function renderPage(
|
|
|
|
|
config: SiteConfig,
|
|
|
|
|
page: string, // foo.md
|
|
|
|
|
result: BuildResult[]
|
|
|
|
|
result: BuildResult
|
|
|
|
|
) {
|
|
|
|
|
const { createApp } = require(path.join(config.tempDir, '_assets/index.js'))
|
|
|
|
|
const { app, router } = createApp()
|
|
|
|
@ -17,15 +18,29 @@ export async function renderPage(
|
|
|
|
|
router.go(routePath)
|
|
|
|
|
const content = await renderToString(app)
|
|
|
|
|
|
|
|
|
|
const assetPath = `${config.site.base}_assets`
|
|
|
|
|
const pageJsPath = page.replace(/\//g, '_') + '.js'
|
|
|
|
|
const pageJsFileName = page.replace(/\//g, '_') + '.js'
|
|
|
|
|
|
|
|
|
|
// resolve page data so we can render head tags
|
|
|
|
|
const { __pageData } = require(path.join(
|
|
|
|
|
config.tempDir,
|
|
|
|
|
'_assets',
|
|
|
|
|
pageJsPath
|
|
|
|
|
pageJsFileName
|
|
|
|
|
))
|
|
|
|
|
const pageData = JSON.parse(__pageData)
|
|
|
|
|
|
|
|
|
|
const assetPath = `${config.site.base}_assets`
|
|
|
|
|
const renderScript = (file: string) => {
|
|
|
|
|
return `<script type="module" async src="${assetPath}/${file}"></script>`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// resolve imports for index.js + page.md.js and inject script tags for
|
|
|
|
|
// them as well so we fetch everything as early as possible without having
|
|
|
|
|
// to wait for entry chunks to parse
|
|
|
|
|
const pageImports = resolvePageImports(config, page, result)
|
|
|
|
|
const pageImportScripts = pageImports.length
|
|
|
|
|
? pageImports.map((i) => renderScript(i)).join('\n') + `\n `
|
|
|
|
|
: ``
|
|
|
|
|
|
|
|
|
|
const html = `
|
|
|
|
|
<html lang="en-US">
|
|
|
|
|
<head>
|
|
|
|
@ -39,8 +54,8 @@ export async function renderPage(
|
|
|
|
|
</head>
|
|
|
|
|
<body>
|
|
|
|
|
<div id="app">${content}</div>
|
|
|
|
|
<script type="module" src="${assetPath}/${pageJsPath}"></script>
|
|
|
|
|
<script type="module" src="${assetPath}/index.js"></script>
|
|
|
|
|
${pageImportScripts}${renderScript(pageJsFileName)}
|
|
|
|
|
${renderScript(`index.js`)}
|
|
|
|
|
</body>
|
|
|
|
|
</html>`.trim()
|
|
|
|
|
const htmlFileName = path.join(config.outDir, page.replace(/\.md$/, '.html'))
|
|
|
|
@ -48,6 +63,23 @@ export async function renderPage(
|
|
|
|
|
await fs.writeFile(htmlFileName, html)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function resolvePageImports(
|
|
|
|
|
config: SiteConfig,
|
|
|
|
|
page: string,
|
|
|
|
|
result: BuildResult
|
|
|
|
|
) {
|
|
|
|
|
// find the page's js chunk and inject script tags for its imports so that
|
|
|
|
|
// they are start fetching as early as possible
|
|
|
|
|
const indexChunk = result.js.find(
|
|
|
|
|
(chunk) => chunk.type === 'chunk' && chunk.fileName === `_assets/index.js`
|
|
|
|
|
) as OutputChunk
|
|
|
|
|
const srcPath = path.join(config.root, page)
|
|
|
|
|
const pageChunk = result.js.find(
|
|
|
|
|
(chunk) => chunk.type === 'chunk' && chunk.facadeModuleId === srcPath
|
|
|
|
|
) as OutputChunk
|
|
|
|
|
return Array.from(new Set([...indexChunk.imports, ...pageChunk.imports]))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function renderHead(head: HeadConfig[]) {
|
|
|
|
|
if (!head || !head.length) {
|
|
|
|
|
return ''
|
|
|
|
|