perf: improve memory usage for static vnodes

Use the already mounted nodes as cache instead of separate caching via
template. This reduces memory usage by 30%+ in VitePress.
This commit is contained in:
Evan You
2022-01-16 20:39:55 +08:00
parent f4f0966b33
commit ed9eb62e59
3 changed files with 42 additions and 11 deletions

View File

@@ -4,7 +4,7 @@ export const svgNS = 'http://www.w3.org/2000/svg'
const doc = (typeof document !== 'undefined' ? document : null) as Document
const staticTemplateCache = new Map<string, DocumentFragment>()
const templateContainer = doc && doc.createElement('template')
export const nodeOps: Omit<RendererOptions<Node, Element>, 'patchProp'> = {
insert: (child, parent, anchor) => {
@@ -73,14 +73,19 @@ export const nodeOps: Omit<RendererOptions<Node, Element>, 'patchProp'> = {
// Reason: innerHTML.
// Static content here can only come from compiled templates.
// As long as the user only uses trusted templates, this is safe.
insertStaticContent(content, parent, anchor, isSVG) {
insertStaticContent(content, parent, anchor, isSVG, start, end) {
// <parent> before | first ... last | anchor </parent>
const before = anchor ? anchor.previousSibling : parent.lastChild
let template = staticTemplateCache.get(content)
if (!template) {
const t = doc.createElement('template')
t.innerHTML = isSVG ? `<svg>${content}</svg>` : content
template = t.content
if (start && end) {
// cached
while (true) {
parent.insertBefore(start!.cloneNode(true), anchor)
if (start === end || !(start = start!.nextSibling)) break
}
} else {
// fresh insert
templateContainer.innerHTML = isSVG ? `<svg>${content}</svg>` : content
const template = templateContainer.content
if (isSVG) {
// remove outer svg wrapper
const wrapper = template.firstChild!
@@ -89,9 +94,8 @@ export const nodeOps: Omit<RendererOptions<Node, Element>, 'patchProp'> = {
}
template.removeChild(wrapper)
}
staticTemplateCache.set(content, template)
parent.insertBefore(template, anchor)
}
parent.insertBefore(template.cloneNode(true), anchor)
return [
// first
before ? before.nextSibling! : parent.firstChild!,