perf: inject script tags for page common chunk imports

pull/5/head
Evan You 5 years ago
parent ddc9d519c6
commit 57d900d4b3

@ -14,11 +14,11 @@ export type BuildOptions = Pick<
export async function build(buildOptions: BuildOptions = {}) { export async function build(buildOptions: BuildOptions = {}) {
const siteConfig = await resolveConfig(buildOptions.root) const siteConfig = await resolveConfig(buildOptions.root)
try { try {
const result = await bundle(siteConfig, buildOptions) const [clientResult] = await bundle(siteConfig, buildOptions)
console.log('rendering pages...') console.log('rendering pages...')
for (const page of siteConfig.pages) { for (const page of siteConfig.pages) {
await renderPage(siteConfig, page, result) await renderPage(siteConfig, page, clientResult)
} }
if (await exists(siteConfig.publicDir)) { if (await exists(siteConfig.publicDir)) {

@ -3,13 +3,14 @@ import { promises as fs } from 'fs'
import { SiteConfig, HeadConfig } from '../config' import { SiteConfig, HeadConfig } from '../config'
import { BuildResult } from 'vite' import { BuildResult } from 'vite'
import { renderToString } from '@vue/server-renderer' import { renderToString } from '@vue/server-renderer'
import { OutputChunk } from 'rollup'
const escape = require('escape-html') const escape = require('escape-html')
export async function renderPage( export async function renderPage(
config: SiteConfig, config: SiteConfig,
page: string, // foo.md page: string, // foo.md
result: BuildResult[] result: BuildResult
) { ) {
const { createApp } = require(path.join(config.tempDir, '_assets/index.js')) const { createApp } = require(path.join(config.tempDir, '_assets/index.js'))
const { app, router } = createApp() const { app, router } = createApp()
@ -17,15 +18,29 @@ export async function renderPage(
router.go(routePath) router.go(routePath)
const content = await renderToString(app) const content = await renderToString(app)
const assetPath = `${config.site.base}_assets` const pageJsFileName = page.replace(/\//g, '_') + '.js'
const pageJsPath = page.replace(/\//g, '_') + '.js'
// resolve page data so we can render head tags
const { __pageData } = require(path.join( const { __pageData } = require(path.join(
config.tempDir, config.tempDir,
'_assets', '_assets',
pageJsPath pageJsFileName
)) ))
const pageData = JSON.parse(__pageData) 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 = ` const html = `
<html lang="en-US"> <html lang="en-US">
<head> <head>
@ -39,8 +54,8 @@ export async function renderPage(
</head> </head>
<body> <body>
<div id="app">${content}</div> <div id="app">${content}</div>
<script type="module" src="${assetPath}/${pageJsPath}"></script> ${pageImportScripts}${renderScript(pageJsFileName)}
<script type="module" src="${assetPath}/index.js"></script> ${renderScript(`index.js`)}
</body> </body>
</html>`.trim() </html>`.trim()
const htmlFileName = path.join(config.outDir, page.replace(/\.md$/, '.html')) const htmlFileName = path.join(config.outDir, page.replace(/\.md$/, '.html'))
@ -48,6 +63,23 @@ export async function renderPage(
await fs.writeFile(htmlFileName, html) 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[]) { function renderHead(head: HeadConfig[]) {
if (!head || !head.length) { if (!head || !head.length) {
return '' return ''

Loading…
Cancel
Save