wip(compiler): tests for new stringification
This commit is contained in:
parent
dbf627f136
commit
baa6973b13
@ -103,7 +103,7 @@ export interface RootNode extends Node {
|
||||
helpers: symbol[]
|
||||
components: string[]
|
||||
directives: string[]
|
||||
hoists: JSChildNode[]
|
||||
hoists: (JSChildNode | null)[]
|
||||
imports: ImportItem[]
|
||||
cached: number
|
||||
temps: number
|
||||
|
@ -434,7 +434,7 @@ function genAssets(
|
||||
}
|
||||
}
|
||||
|
||||
function genHoists(hoists: JSChildNode[], context: CodegenContext) {
|
||||
function genHoists(hoists: (JSChildNode | null)[], context: CodegenContext) {
|
||||
if (!hoists.length) {
|
||||
return
|
||||
}
|
||||
@ -451,9 +451,11 @@ function genHoists(hoists: JSChildNode[], context: CodegenContext) {
|
||||
}
|
||||
|
||||
hoists.forEach((exp, i) => {
|
||||
if (exp) {
|
||||
push(`const _hoisted_${i + 1} = `)
|
||||
genNode(exp, context)
|
||||
newline()
|
||||
}
|
||||
})
|
||||
|
||||
if (genScopeId) {
|
||||
|
@ -82,7 +82,7 @@ export interface TransformContext extends Required<TransformOptions> {
|
||||
helpers: Set<symbol>
|
||||
components: Set<string>
|
||||
directives: Set<string>
|
||||
hoists: JSChildNode[]
|
||||
hoists: (JSChildNode | null)[]
|
||||
imports: Set<ImportItem>
|
||||
temps: number
|
||||
cached: number
|
||||
|
@ -31,7 +31,7 @@ describe('stringify static html', () => {
|
||||
)
|
||||
expect(ast.hoists.length).toBe(1)
|
||||
// should be a normal vnode call
|
||||
expect(ast.hoists[0].type).toBe(NodeTypes.VNODE_CALL)
|
||||
expect(ast.hoists[0]!.type).toBe(NodeTypes.VNODE_CALL)
|
||||
})
|
||||
|
||||
test('should work on eligible content (elements with binding > 5)', () => {
|
||||
@ -52,7 +52,8 @@ describe('stringify static html', () => {
|
||||
`<span class="foo"></span>`,
|
||||
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT
|
||||
)}</div>`
|
||||
)
|
||||
),
|
||||
'1'
|
||||
]
|
||||
})
|
||||
})
|
||||
@ -75,7 +76,36 @@ describe('stringify static html', () => {
|
||||
`<span></span>`,
|
||||
StringifyThresholds.NODE_COUNT
|
||||
)}</div>`
|
||||
),
|
||||
'1'
|
||||
]
|
||||
})
|
||||
})
|
||||
|
||||
test('should work for multiple adjacent nodes', () => {
|
||||
const { ast } = compileWithStringify(
|
||||
`<div>${repeat(
|
||||
`<span class="foo"/>`,
|
||||
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT
|
||||
)}</div>`
|
||||
)
|
||||
// should have 5 hoisted nodes, but the other 4 should be null
|
||||
expect(ast.hoists.length).toBe(5)
|
||||
for (let i = 1; i < 5; i++) {
|
||||
expect(ast.hoists[i]).toBe(null)
|
||||
}
|
||||
// should be optimized now
|
||||
expect(ast.hoists[0]).toMatchObject({
|
||||
type: NodeTypes.JS_CALL_EXPRESSION,
|
||||
callee: CREATE_STATIC,
|
||||
arguments: [
|
||||
JSON.stringify(
|
||||
repeat(
|
||||
`<span class="foo"></span>`,
|
||||
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT
|
||||
)
|
||||
),
|
||||
'5'
|
||||
]
|
||||
})
|
||||
})
|
||||
@ -98,7 +128,8 @@ describe('stringify static html', () => {
|
||||
`<span class="foo bar">1 + false</span>`,
|
||||
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT
|
||||
)}</div>`
|
||||
)
|
||||
),
|
||||
'1'
|
||||
]
|
||||
})
|
||||
})
|
||||
@ -122,7 +153,8 @@ describe('stringify static html', () => {
|
||||
`<span class="foo>ar">1 + <</span>` + `<span>&</span>`,
|
||||
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT
|
||||
)}</div>`
|
||||
)
|
||||
),
|
||||
'1'
|
||||
]
|
||||
})
|
||||
})
|
||||
|
@ -13,8 +13,7 @@ import {
|
||||
ExpressionNode,
|
||||
ElementTypes,
|
||||
PlainElementNode,
|
||||
JSChildNode,
|
||||
createSimpleExpression
|
||||
JSChildNode
|
||||
} from '@vue/compiler-core'
|
||||
import {
|
||||
isVoidTag,
|
||||
@ -39,9 +38,42 @@ export const enum StringifyThresholds {
|
||||
export const stringifyStatic: HoistTransform = (children, context) => {
|
||||
let nc = 0 // current node count
|
||||
let ec = 0 // current element with binding count
|
||||
const currentEligibleNodes: PlainElementNode[] = []
|
||||
const currentChunk: PlainElementNode[] = []
|
||||
|
||||
for (let i = 0; i < children.length; i++) {
|
||||
const stringifyCurrentChunk = (currentIndex: number): number => {
|
||||
if (
|
||||
nc >= StringifyThresholds.NODE_COUNT ||
|
||||
ec >= StringifyThresholds.ELEMENT_WITH_BINDING_COUNT
|
||||
) {
|
||||
// combine all currently eligible nodes into a single static vnode call
|
||||
const staticCall = createCallExpression(context.helper(CREATE_STATIC), [
|
||||
JSON.stringify(
|
||||
currentChunk.map(node => stringifyElement(node, context)).join('')
|
||||
),
|
||||
// the 2nd argument indicates the number of DOM nodes this static vnode
|
||||
// will insert / hydrate
|
||||
String(currentChunk.length)
|
||||
])
|
||||
// replace the first node's hoisted expression with the static vnode call
|
||||
replaceHoist(currentChunk[0], staticCall, context)
|
||||
|
||||
if (currentChunk.length > 1) {
|
||||
for (let i = 1; i < currentChunk.length; i++) {
|
||||
// for the merged nodes, set their hoisted expression to null
|
||||
replaceHoist(currentChunk[i], null, context)
|
||||
}
|
||||
|
||||
// also remove merged nodes from children
|
||||
const deleteCount = currentChunk.length - 1
|
||||
children.splice(currentIndex - currentChunk.length + 1, deleteCount)
|
||||
return deleteCount
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
let i = 0
|
||||
for (; i < children.length; i++) {
|
||||
const child = children[i]
|
||||
const hoisted = getHoistedNode(child)
|
||||
if (hoisted) {
|
||||
@ -52,54 +84,21 @@ export const stringifyStatic: HoistTransform = (children, context) => {
|
||||
// node is stringifiable, record state
|
||||
nc += result[0]
|
||||
ec += result[1]
|
||||
currentEligibleNodes.push(node)
|
||||
currentChunk.push(node)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// we only reach here if we ran into a node that is not stringifiable
|
||||
// check if currently analyzed nodes meet criteria for stringification.
|
||||
if (
|
||||
nc >= StringifyThresholds.NODE_COUNT ||
|
||||
ec >= StringifyThresholds.ELEMENT_WITH_BINDING_COUNT
|
||||
) {
|
||||
// combine all currently eligible nodes into a single static vnode call
|
||||
const staticCall = createCallExpression(context.helper(CREATE_STATIC), [
|
||||
JSON.stringify(
|
||||
currentEligibleNodes
|
||||
.map(node => stringifyElement(node, context))
|
||||
.join('')
|
||||
),
|
||||
// the 2nd argument indicates the number of DOM nodes this static vnode
|
||||
// will insert / hydrate
|
||||
String(currentEligibleNodes.length)
|
||||
])
|
||||
// replace the first node's hoisted expression with the static vnode call
|
||||
replaceHoist(currentEligibleNodes[0], staticCall, context)
|
||||
|
||||
const n = currentEligibleNodes.length
|
||||
if (n > 1) {
|
||||
for (let j = 1; j < n; j++) {
|
||||
// for the merged nodes, set their hoisted expression to null
|
||||
replaceHoist(
|
||||
currentEligibleNodes[j],
|
||||
createSimpleExpression(`null`, false),
|
||||
context
|
||||
)
|
||||
}
|
||||
// also remove merged nodes from children
|
||||
const deleteCount = n - 1
|
||||
children.splice(i - n + 1, deleteCount)
|
||||
// adjust iteration index
|
||||
i -= deleteCount
|
||||
}
|
||||
}
|
||||
|
||||
i -= stringifyCurrentChunk(i)
|
||||
// reset state
|
||||
nc = 0
|
||||
ec = 0
|
||||
currentEligibleNodes.length = 0
|
||||
currentChunk.length = 0
|
||||
}
|
||||
// in case the last node was also stringifiable
|
||||
stringifyCurrentChunk(i)
|
||||
}
|
||||
|
||||
const getHoistedNode = (node: TemplateChildNode) =>
|
||||
@ -116,7 +115,7 @@ const isStringifiableAttr = (name: string) => {
|
||||
|
||||
const replaceHoist = (
|
||||
node: PlainElementNode,
|
||||
replacement: JSChildNode,
|
||||
replacement: JSChildNode | null,
|
||||
context: TransformContext
|
||||
) => {
|
||||
const hoistToReplace = (node.codegenNode as SimpleExpressionNode).hoisted!
|
||||
|
Loading…
Reference in New Issue
Block a user