Skip to content

Commit

Permalink
perf: inject script tags for page common chunk imports
Browse files Browse the repository at this point in the history
  • Loading branch information
yyx990803 committed May 2, 2020
1 parent ddc9d51 commit 57d900d
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 8 deletions.
4 changes: 2 additions & 2 deletions src/build/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ export type BuildOptions = Pick<
export async function build(buildOptions: BuildOptions = {}) {
const siteConfig = await resolveConfig(buildOptions.root)
try {
const result = await bundle(siteConfig, buildOptions)
const [clientResult] = await bundle(siteConfig, buildOptions)

console.log('rendering pages...')
for (const page of siteConfig.pages) {
await renderPage(siteConfig, page, result)
await renderPage(siteConfig, page, clientResult)
}

if (await exists(siteConfig.publicDir)) {
Expand Down
44 changes: 38 additions & 6 deletions src/build/render.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,44 @@ 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()
const routePath = `/${page.replace(/\.md$/, '')}`
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>
Expand All @@ -39,15 +54,32 @@ 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'))
await fs.mkdir(path.dirname(htmlFileName), { recursive: true })
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 ''
Expand Down

0 comments on commit 57d900d

Please sign in to comment.