feat(compiler-core): re-implement v-once to use cache mechanism
This commit is contained in:
@@ -21,6 +21,20 @@ export default function render() {
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`compiler: codegen CacheExpression w/ isVNode: true 1`] = `
|
||||
"
|
||||
export default function render() {
|
||||
const _ctx = this
|
||||
const _cache = _ctx.$cache
|
||||
return _cache[1] || (
|
||||
setBlockTracking(-1),
|
||||
_cache[1] = foo,
|
||||
setBlockTracking(1),
|
||||
_cache[1]
|
||||
)
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`compiler: codegen ConditionalExpression 1`] = `
|
||||
"
|
||||
return function render() {
|
||||
|
||||
@@ -380,4 +380,33 @@ describe('compiler: codegen', () => {
|
||||
expect(code).toMatch(`_cache[1] || (_cache[1] = foo)`)
|
||||
expect(code).toMatchSnapshot()
|
||||
})
|
||||
|
||||
test('CacheExpression w/ isVNode: true', () => {
|
||||
const { code } = generate(
|
||||
createRoot({
|
||||
cached: 1,
|
||||
codegenNode: createCacheExpression(
|
||||
1,
|
||||
createSimpleExpression(`foo`, false),
|
||||
true
|
||||
)
|
||||
}),
|
||||
{
|
||||
mode: 'module',
|
||||
prefixIdentifiers: true
|
||||
}
|
||||
)
|
||||
expect(code).toMatch(`const _cache = _ctx.$cache`)
|
||||
expect(code).toMatch(
|
||||
`
|
||||
_cache[1] || (
|
||||
setBlockTracking(-1),
|
||||
_cache[1] = foo,
|
||||
setBlockTracking(1),
|
||||
_cache[1]
|
||||
)
|
||||
`.trim()
|
||||
)
|
||||
expect(code).toMatchSnapshot()
|
||||
})
|
||||
})
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`compiler: v-once transform as root node 1`] = `
|
||||
"const _Vue = Vue
|
||||
|
||||
return function render() {
|
||||
with (this) {
|
||||
const { setBlockTracking: _setBlockTracking, createVNode: _createVNode } = _Vue
|
||||
const _cache = $cache
|
||||
|
||||
return _cache[1] || (
|
||||
_setBlockTracking(-1),
|
||||
_cache[1] = _createVNode(\\"div\\", { id: foo }, null, 8 /* PROPS */, [\\"id\\"]),
|
||||
_setBlockTracking(1),
|
||||
_cache[1]
|
||||
)
|
||||
}
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`compiler: v-once transform on component 1`] = `
|
||||
"const _Vue = Vue
|
||||
|
||||
return function render() {
|
||||
with (this) {
|
||||
const { setBlockTracking: _setBlockTracking, resolveComponent: _resolveComponent, createVNode: _createVNode, createBlock: _createBlock, openBlock: _openBlock } = _Vue
|
||||
const _cache = $cache
|
||||
|
||||
const _component_Comp = _resolveComponent(\\"Comp\\")
|
||||
|
||||
return (_openBlock(), _createBlock(\\"div\\", null, [
|
||||
_cache[1] || (
|
||||
_setBlockTracking(-1),
|
||||
_cache[1] = _createVNode(_component_Comp, { id: foo }, null, 8 /* PROPS */, [\\"id\\"]),
|
||||
_setBlockTracking(1),
|
||||
_cache[1]
|
||||
)
|
||||
]))
|
||||
}
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`compiler: v-once transform on nested plain element 1`] = `
|
||||
"const _Vue = Vue
|
||||
|
||||
return function render() {
|
||||
with (this) {
|
||||
const { setBlockTracking: _setBlockTracking, createVNode: _createVNode, createBlock: _createBlock, openBlock: _openBlock } = _Vue
|
||||
const _cache = $cache
|
||||
|
||||
return (_openBlock(), _createBlock(\\"div\\", null, [
|
||||
_cache[1] || (
|
||||
_setBlockTracking(-1),
|
||||
_cache[1] = _createVNode(\\"div\\", { id: foo }, null, 8 /* PROPS */, [\\"id\\"]),
|
||||
_setBlockTracking(1),
|
||||
_cache[1]
|
||||
)
|
||||
]))
|
||||
}
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`compiler: v-once transform on slot outlet 1`] = `
|
||||
"const _Vue = Vue
|
||||
|
||||
return function render() {
|
||||
with (this) {
|
||||
const { setBlockTracking: _setBlockTracking, renderSlot: _renderSlot, createVNode: _createVNode, createBlock: _createBlock, openBlock: _openBlock } = _Vue
|
||||
const _cache = $cache
|
||||
|
||||
return (_openBlock(), _createBlock(\\"div\\", null, [
|
||||
_cache[1] || (
|
||||
_setBlockTracking(-1),
|
||||
_cache[1] = _renderSlot($slots, \\"default\\"),
|
||||
_setBlockTracking(1),
|
||||
_cache[1]
|
||||
)
|
||||
]))
|
||||
}
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`compiler: v-once transform with hoistStatic: true 1`] = `
|
||||
"const _Vue = Vue
|
||||
|
||||
return function render() {
|
||||
with (this) {
|
||||
const { setBlockTracking: _setBlockTracking, createVNode: _createVNode, createBlock: _createBlock, openBlock: _openBlock } = _Vue
|
||||
const _cache = $cache
|
||||
|
||||
return (_openBlock(), _createBlock(\\"div\\", null, [
|
||||
_cache[1] || (
|
||||
_setBlockTracking(-1),
|
||||
_cache[1] = _createVNode(\\"div\\"),
|
||||
_setBlockTracking(1),
|
||||
_cache[1]
|
||||
)
|
||||
]))
|
||||
}
|
||||
}"
|
||||
`;
|
||||
@@ -387,7 +387,8 @@ describe('compiler: transform v-model', () => {
|
||||
const root = parseWithVModel('<Comp v-model.trim.bar-baz="foo" />', {
|
||||
prefixIdentifiers: true
|
||||
})
|
||||
const args = (root.children[0] as ComponentNode).codegenNode!.arguments
|
||||
const args = ((root.children[0] as ComponentNode)
|
||||
.codegenNode as CallExpression).arguments
|
||||
// props
|
||||
expect(args[1]).toMatchObject({
|
||||
properties: [
|
||||
|
||||
@@ -1,28 +1,109 @@
|
||||
import { parse, transform, ElementNode, CallExpression } from '../../src'
|
||||
import {
|
||||
parse,
|
||||
transform,
|
||||
NodeTypes,
|
||||
generate,
|
||||
CompilerOptions
|
||||
} from '../../src'
|
||||
import { transformOnce } from '../../src/transforms/vOnce'
|
||||
import { transformElement } from '../../src/transforms/transformElement'
|
||||
import { createObjectMatcher } from '../testUtils'
|
||||
import {
|
||||
CREATE_VNODE,
|
||||
RENDER_SLOT,
|
||||
SET_BLOCK_TRACKING
|
||||
} from '../../src/runtimeHelpers'
|
||||
import { transformBind } from '../../src/transforms/vBind'
|
||||
import { transformSlotOutlet } from '../../src/transforms/transformSlotOutlet'
|
||||
|
||||
function transformWithOnce(template: string) {
|
||||
function transformWithOnce(template: string, options: CompilerOptions = {}) {
|
||||
const ast = parse(template)
|
||||
transform(ast, {
|
||||
nodeTransforms: [transformElement],
|
||||
nodeTransforms: [transformOnce, transformElement, transformSlotOutlet],
|
||||
directiveTransforms: {
|
||||
once: transformOnce
|
||||
}
|
||||
bind: transformBind
|
||||
},
|
||||
...options
|
||||
})
|
||||
return ast.children[0] as ElementNode
|
||||
return ast
|
||||
}
|
||||
|
||||
describe('compiler: v-once transform', () => {
|
||||
test('should add no props to DOM', () => {
|
||||
const node = transformWithOnce(`<div v-once />`)
|
||||
const codegenArgs = (node.codegenNode as CallExpression).arguments
|
||||
test('as root node', () => {
|
||||
const root = transformWithOnce(`<div :id="foo" v-once />`)
|
||||
expect(root.cached).toBe(1)
|
||||
expect(root.helpers).toContain(SET_BLOCK_TRACKING)
|
||||
expect(root.codegenNode).toMatchObject({
|
||||
type: NodeTypes.JS_CACHE_EXPRESSION,
|
||||
index: 1,
|
||||
value: {
|
||||
type: NodeTypes.JS_CALL_EXPRESSION,
|
||||
callee: CREATE_VNODE
|
||||
}
|
||||
})
|
||||
expect(generate(root).code).toMatchSnapshot()
|
||||
})
|
||||
|
||||
expect(codegenArgs[1]).toMatchObject(
|
||||
createObjectMatcher({
|
||||
$once: `[true]`
|
||||
})
|
||||
)
|
||||
test('on nested plain element', () => {
|
||||
const root = transformWithOnce(`<div><div :id="foo" v-once /></div>`)
|
||||
expect(root.cached).toBe(1)
|
||||
expect(root.helpers).toContain(SET_BLOCK_TRACKING)
|
||||
expect((root.children[0] as any).children[0].codegenNode).toMatchObject({
|
||||
type: NodeTypes.JS_CACHE_EXPRESSION,
|
||||
index: 1,
|
||||
value: {
|
||||
type: NodeTypes.JS_CALL_EXPRESSION,
|
||||
callee: CREATE_VNODE
|
||||
}
|
||||
})
|
||||
expect(generate(root).code).toMatchSnapshot()
|
||||
})
|
||||
|
||||
test('on component', () => {
|
||||
const root = transformWithOnce(`<div><Comp :id="foo" v-once /></div>`)
|
||||
expect(root.cached).toBe(1)
|
||||
expect(root.helpers).toContain(SET_BLOCK_TRACKING)
|
||||
expect((root.children[0] as any).children[0].codegenNode).toMatchObject({
|
||||
type: NodeTypes.JS_CACHE_EXPRESSION,
|
||||
index: 1,
|
||||
value: {
|
||||
type: NodeTypes.JS_CALL_EXPRESSION,
|
||||
callee: CREATE_VNODE
|
||||
}
|
||||
})
|
||||
expect(generate(root).code).toMatchSnapshot()
|
||||
})
|
||||
|
||||
test('on slot outlet', () => {
|
||||
const root = transformWithOnce(`<div><slot v-once /></div>`)
|
||||
expect(root.cached).toBe(1)
|
||||
expect(root.helpers).toContain(SET_BLOCK_TRACKING)
|
||||
expect((root.children[0] as any).children[0].codegenNode).toMatchObject({
|
||||
type: NodeTypes.JS_CACHE_EXPRESSION,
|
||||
index: 1,
|
||||
value: {
|
||||
type: NodeTypes.JS_CALL_EXPRESSION,
|
||||
callee: RENDER_SLOT
|
||||
}
|
||||
})
|
||||
expect(generate(root).code).toMatchSnapshot()
|
||||
})
|
||||
|
||||
// cached nodes should be ignored by hoistStatic transform
|
||||
test('with hoistStatic: true', () => {
|
||||
const root = transformWithOnce(`<div><div v-once /></div>`, {
|
||||
hoistStatic: true
|
||||
})
|
||||
expect(root.cached).toBe(1)
|
||||
expect(root.helpers).toContain(SET_BLOCK_TRACKING)
|
||||
expect(root.hoists.length).toBe(0)
|
||||
expect((root.children[0] as any).children[0].codegenNode).toMatchObject({
|
||||
type: NodeTypes.JS_CACHE_EXPRESSION,
|
||||
index: 1,
|
||||
value: {
|
||||
type: NodeTypes.JS_CALL_EXPRESSION,
|
||||
callee: CREATE_VNODE
|
||||
}
|
||||
})
|
||||
expect(generate(root).code).toMatchSnapshot()
|
||||
})
|
||||
})
|
||||
|
||||
@@ -365,7 +365,7 @@ describe('compiler: transform component slots', () => {
|
||||
} else {
|
||||
const innerComp = (root.children[0] as ComponentNode)
|
||||
.children[0] as ComponentNode
|
||||
flag = innerComp.codegenNode!.arguments[3]
|
||||
flag = (innerComp.codegenNode as CallExpression).arguments[3]
|
||||
}
|
||||
if (shouldForce) {
|
||||
expect(flag).toBe(genFlagText(PatchFlags.DYNAMIC_SLOTS))
|
||||
|
||||
Reference in New Issue
Block a user