Skip to content

Commit 3c84f82

Browse files
committed
perf: use inline templates for rendering html
1 parent bd64eb2 commit 3c84f82

File tree

1 file changed

+119
-38
lines changed

1 file changed

+119
-38
lines changed

src/runtime.ts

Lines changed: 119 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -210,56 +210,152 @@ export function getRequestDependencies(ssrContext: SSRContext, rendererContext:
210210

211211
export function renderStyles(ssrContext: SSRContext, rendererContext: RendererContext): string {
212212
const { styles } = getRequestDependencies(ssrContext, rendererContext)
213-
return Object.values(styles).map(resource =>
214-
renderLinkToString({ rel: 'stylesheet', href: rendererContext.buildAssetsURL(resource.file), crossorigin: '' }),
215-
).join('')
213+
let result = ''
214+
for (const key in styles) {
215+
const resource = styles[key]!
216+
result += `<link rel="stylesheet" href="${rendererContext.buildAssetsURL(resource.file)}" crossorigin>`
217+
}
218+
return result
216219
}
217220

218221
export function getResources(ssrContext: SSRContext, rendererContext: RendererContext): LinkAttributes[] {
219222
return [...getPreloadLinks(ssrContext, rendererContext), ...getPrefetchLinks(ssrContext, rendererContext)]
220223
}
221224

222-
export function renderResourceHints(ssrContext: SSRContext, rendererContext: RendererContext): string {
223-
return getResources(ssrContext, rendererContext).map(renderLinkToString).join('')
225+
function renderResourceHints(ssrContext: SSRContext, rendererContext: RendererContext): string {
226+
const { preload, prefetch } = getRequestDependencies(ssrContext, rendererContext)
227+
let result = ''
228+
229+
// Render preload links
230+
for (const key in preload) {
231+
const resource = preload[key]!
232+
const href = rendererContext.buildAssetsURL(resource.file)
233+
const rel = resource.module ? 'modulepreload' : 'preload'
234+
const crossorigin = (resource.resourceType === 'style' || resource.resourceType === 'font' || resource.resourceType === 'script' || resource.module) ? ' crossorigin' : ''
235+
236+
if (resource.resourceType && resource.mimeType) {
237+
result += `<link rel="${rel}" as="${resource.resourceType}" type="${resource.mimeType}"${crossorigin} href="${href}">`
238+
}
239+
else if (resource.resourceType) {
240+
result += `<link rel="${rel}" as="${resource.resourceType}"${crossorigin} href="${href}">`
241+
}
242+
else {
243+
result += `<link rel="${rel}"${crossorigin} href="${href}">`
244+
}
245+
}
246+
// Render prefetch links
247+
for (const key in prefetch) {
248+
const resource = prefetch[key]!
249+
const href = rendererContext.buildAssetsURL(resource.file)
250+
const crossorigin = (resource.resourceType === 'style' || resource.resourceType === 'font' || resource.resourceType === 'script' || resource.module) ? ' crossorigin' : ''
251+
252+
if (resource.resourceType && resource.mimeType) {
253+
result += `<link rel="prefetch" as="${resource.resourceType}" type="${resource.mimeType}"${crossorigin} href="${href}">`
254+
}
255+
else if (resource.resourceType) {
256+
result += `<link rel="prefetch" as="${resource.resourceType}"${crossorigin} href="${href}">`
257+
}
258+
else {
259+
result += `<link rel="prefetch"${crossorigin} href="${href}">`
260+
}
261+
}
262+
263+
return result
224264
}
225265

226-
export function renderResourceHeaders(ssrContext: SSRContext, rendererContext: RendererContext): Record<string, string> {
266+
function renderResourceHeaders(ssrContext: SSRContext, rendererContext: RendererContext): Record<string, string> {
267+
const { preload, prefetch } = getRequestDependencies(ssrContext, rendererContext)
268+
const links: string[] = []
269+
270+
// Render preload headers
271+
for (const key in preload) {
272+
const resource = preload[key]!
273+
const href = rendererContext.buildAssetsURL(resource.file)
274+
const rel = resource.module ? 'modulepreload' : 'preload'
275+
let header = `<${href}>; rel="${rel}"`
276+
277+
if (resource.resourceType) {
278+
header += `; as="${resource.resourceType}"`
279+
}
280+
if (resource.mimeType) {
281+
header += `; type="${resource.mimeType}"`
282+
}
283+
if (resource.resourceType === 'style' || resource.resourceType === 'font' || resource.resourceType === 'script' || resource.module) {
284+
header += '; crossorigin'
285+
}
286+
287+
links.push(header)
288+
}
289+
290+
// Render prefetch headers
291+
for (const key in prefetch) {
292+
const resource = prefetch[key]!
293+
const href = rendererContext.buildAssetsURL(resource.file)
294+
let header = `<${href}>; rel="prefetch"`
295+
296+
if (resource.resourceType) {
297+
header += `; as="${resource.resourceType}"`
298+
}
299+
if (resource.mimeType) {
300+
header += `; type="${resource.mimeType}"`
301+
}
302+
if (resource.resourceType === 'style' || resource.resourceType === 'font' || resource.resourceType === 'script' || resource.module) {
303+
header += '; crossorigin'
304+
}
305+
306+
links.push(header)
307+
}
308+
227309
return {
228-
link: getResources(ssrContext, rendererContext).map(renderLinkToHeader).join(', '),
310+
link: links.join(', '),
229311
}
230312
}
231313

232314
export function getPreloadLinks(ssrContext: SSRContext, rendererContext: RendererContext): LinkAttributes[] {
233315
const { preload } = getRequestDependencies(ssrContext, rendererContext)
234-
return Object.values(preload)
235-
.map(resource => ({
316+
const result: LinkAttributes[] = []
317+
for (const key in preload) {
318+
const resource = preload[key]!
319+
result.push({
236320
rel: resource.module ? 'modulepreload' : 'preload',
237321
as: resource.resourceType,
238322
type: resource.mimeType ?? null,
239323
crossorigin: resource.resourceType === 'style' || resource.resourceType === 'font' || resource.resourceType === 'script' || resource.module ? '' : null,
240324
href: rendererContext.buildAssetsURL(resource.file),
241-
}))
325+
})
326+
}
327+
return result
242328
}
243329

244330
export function getPrefetchLinks(ssrContext: SSRContext, rendererContext: RendererContext): LinkAttributes[] {
245331
const { prefetch } = getRequestDependencies(ssrContext, rendererContext)
246-
return Object.values(prefetch).map(resource => ({
247-
rel: 'prefetch',
248-
as: resource.resourceType,
249-
type: resource.mimeType ?? null,
250-
crossorigin: resource.resourceType === 'style' || resource.resourceType === 'font' || resource.resourceType === 'script' || resource.module ? '' : null,
251-
href: rendererContext.buildAssetsURL(resource.file),
252-
}))
332+
const result: LinkAttributes[] = []
333+
for (const key in prefetch) {
334+
const resource = prefetch[key]!
335+
result.push({
336+
rel: 'prefetch',
337+
as: resource.resourceType,
338+
type: resource.mimeType ?? null,
339+
crossorigin: resource.resourceType === 'style' || resource.resourceType === 'font' || resource.resourceType === 'script' || resource.module ? '' : null,
340+
href: rendererContext.buildAssetsURL(resource.file),
341+
})
342+
}
343+
return result
253344
}
254345

255346
export function renderScripts(ssrContext: SSRContext, rendererContext: RendererContext): string {
256347
const { scripts } = getRequestDependencies(ssrContext, rendererContext)
257-
return Object.values(scripts).map(resource => renderScriptToString({
258-
type: resource.module ? 'module' : null,
259-
src: rendererContext.buildAssetsURL(resource.file),
260-
defer: resource.module ? null : '',
261-
crossorigin: '',
262-
})).join('')
348+
let result = ''
349+
for (const key in scripts) {
350+
const resource = scripts[key]!
351+
if (resource.module) {
352+
result += `<script type="module" src="${rendererContext.buildAssetsURL(resource.file)}" crossorigin></script>`
353+
}
354+
else {
355+
result += `<script src="${rendererContext.buildAssetsURL(resource.file)}" defer crossorigin></script>`
356+
}
357+
}
358+
return result
263359
}
264360

265361
export type RenderFunction = (ssrContext: SSRContext, rendererContext: RendererContext) => unknown
@@ -293,18 +389,3 @@ export function createRenderer<App>(createApp: ImportOf<CreateApp<App>>, renderO
293389
},
294390
}
295391
}
296-
297-
// --- Internal ---
298-
299-
// Utilities to render script and link tags, and link headers
300-
function renderScriptToString(attrs: Record<string, string | null>) {
301-
return `<script${Object.entries(attrs).map(([key, value]) => value === null ? '' : value ? ` ${key}="${value}"` : ' ' + key).join('')}></script>`
302-
}
303-
304-
function renderLinkToString(attrs: LinkAttributes) {
305-
return `<link${Object.entries(attrs).map(([key, value]) => value === null ? '' : value ? ` ${key}="${value}"` : ' ' + key).join('')}>`
306-
}
307-
308-
function renderLinkToHeader(attrs: LinkAttributes) {
309-
return `<${attrs.href}>${Object.entries(attrs).map(([key, value]) => key === 'href' || value === null ? '' : value ? `; ${key}="${value}"` : `; ${key}`).join('')}`
310-
}

0 commit comments

Comments
 (0)