Skip to content

Commit

Permalink
feat: v-memo
Browse files Browse the repository at this point in the history
  • Loading branch information
yyx990803 committed Jul 16, 2021
1 parent 5cea9a1 commit 3b64508
Show file tree
Hide file tree
Showing 23 changed files with 562 additions and 130 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ export function render(_ctx, _cache) {
return (_openBlock(), _createElementBlock(\\"div\\", null, [
_createElementVNode(\\"div\\", null, [
_createElementVNode(\\"div\\", {
onClick: _cache[1] || (_cache[1] = (...args) => (_ctx.foo && _ctx.foo(...args)))
onClick: _cache[0] || (_cache[0] = (...args) => (_ctx.foo && _ctx.foo(...args)))
})
])
]))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`compiler: v-memo transform on component 1`] = `
"import { resolveComponent as _resolveComponent, createVNode as _createVNode, withMemo as _withMemo, openBlock as _openBlock, createElementBlock as _createElementBlock } from \\"vue\\"
export function render(_ctx, _cache) {
const _component_Comp = _resolveComponent(\\"Comp\\")
return (_openBlock(), _createElementBlock(\\"div\\", null, [
_withMemo([_ctx.x], () => _createVNode(_component_Comp), _cache, 0)
]))
}"
`;

exports[`compiler: v-memo transform on normal element 1`] = `
"import { openBlock as _openBlock, createElementBlock as _createElementBlock, withMemo as _withMemo } from \\"vue\\"
export function render(_ctx, _cache) {
return (_openBlock(), _createElementBlock(\\"div\\", null, [
_withMemo([_ctx.x], () => (_openBlock(), _createElementBlock(\\"div\\")), _cache, 0)
]))
}"
`;

exports[`compiler: v-memo transform on root element 1`] = `
"import { openBlock as _openBlock, createElementBlock as _createElementBlock, withMemo as _withMemo } from \\"vue\\"
export function render(_ctx, _cache) {
return _withMemo([_ctx.x], () => (_openBlock(), _createElementBlock(\\"div\\")), _cache, 0)
}"
`;

exports[`compiler: v-memo transform on template v-for 1`] = `
"import { renderList as _renderList, Fragment as _Fragment, openBlock as _openBlock, createElementBlock as _createElementBlock, isMemoSame as _isMemoSame, withMemo as _withMemo } from \\"vue\\"
export function render(_ctx, _cache) {
return (_openBlock(), _createElementBlock(\\"div\\", null, [
(_openBlock(true), _createElementBlock(_Fragment, null, _renderList(_ctx.list, ({ x, y }, __, ___, _cached) => {
const _memo = ([x, y === z])
if (_cached && _cached.key === x && _isMemoSame(_cached.memo, _memo)) return _cached
const _item = (_openBlock(), _createElementBlock(\\"span\\", { key: x }, \\"foobar\\"))
_item.memo = _memo
return _item
}, _cache, 0), 128 /* KEYED_FRAGMENT */))
]))
}"
`;

exports[`compiler: v-memo transform on v-for 1`] = `
"import { renderList as _renderList, Fragment as _Fragment, openBlock as _openBlock, createElementBlock as _createElementBlock, createElementVNode as _createElementVNode, isMemoSame as _isMemoSame, withMemo as _withMemo } from \\"vue\\"
export function render(_ctx, _cache) {
return (_openBlock(), _createElementBlock(\\"div\\", null, [
(_openBlock(true), _createElementBlock(_Fragment, null, _renderList(_ctx.list, ({ x, y }, __, ___, _cached) => {
const _memo = ([x, y === _ctx.z])
if (_cached && _cached.key === x && _isMemoSame(_cached.memo, _memo)) return _cached
const _item = (_openBlock(), _createElementBlock(\\"div\\", { key: x }, [
_createElementVNode(\\"span\\", null, \\"foobar\\")
]))
_item.memo = _memo
return _item
}, _cache, 0), 128 /* KEYED_FRAGMENT */))
]))
}"
`;

exports[`compiler: v-memo transform on v-if 1`] = `
"import { createElementVNode as _createElementVNode, createTextVNode as _createTextVNode, openBlock as _openBlock, createElementBlock as _createElementBlock, withMemo as _withMemo, createCommentVNode as _createCommentVNode, resolveComponent as _resolveComponent, createBlock as _createBlock } from \\"vue\\"
export function render(_ctx, _cache) {
const _component_Comp = _resolveComponent(\\"Comp\\")
return (_openBlock(), _createElementBlock(\\"div\\", null, [
(_ctx.ok)
? _withMemo([_ctx.x], () => (_openBlock(), _createElementBlock(\\"div\\", { key: 0 }, [
_createElementVNode(\\"span\\", null, \\"foo\\"),
_createTextVNode(\\"bar\\")
])), _cache, 0)
: _withMemo([_ctx.x], () => (_openBlock(), _createBlock(_component_Comp, { key: 1 })), _cache, 1)
]))
}"
`;
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ return function render(_ctx, _cache) {
with (_ctx) {
const { setBlockTracking: _setBlockTracking, createElementVNode: _createElementVNode } = _Vue
return _cache[1] || (
return _cache[0] || (
_setBlockTracking(-1),
_cache[1] = _createElementVNode(\\"div\\", { id: foo }, null, 8 /* PROPS */, [\\"id\\"]),
_cache[0] = _createElementVNode(\\"div\\", { id: foo }, null, 8 /* PROPS */, [\\"id\\"]),
_setBlockTracking(1),
_cache[1]
_cache[0]
)
}
}"
Expand All @@ -27,11 +27,11 @@ return function render(_ctx, _cache) {
const _component_Comp = _resolveComponent(\\"Comp\\")
return (_openBlock(), _createElementBlock(\\"div\\", null, [
_cache[1] || (
_cache[0] || (
_setBlockTracking(-1),
_cache[1] = _createVNode(_component_Comp, { id: foo }, null, 8 /* PROPS */, [\\"id\\"]),
_cache[0] = _createVNode(_component_Comp, { id: foo }, null, 8 /* PROPS */, [\\"id\\"]),
_setBlockTracking(1),
_cache[1]
_cache[0]
)
]))
}
Expand All @@ -46,11 +46,11 @@ return function render(_ctx, _cache) {
const { setBlockTracking: _setBlockTracking, createElementVNode: _createElementVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue
return (_openBlock(), _createElementBlock(\\"div\\", null, [
_cache[1] || (
_cache[0] || (
_setBlockTracking(-1),
_cache[1] = _createElementVNode(\\"div\\", { id: foo }, null, 8 /* PROPS */, [\\"id\\"]),
_cache[0] = _createElementVNode(\\"div\\", { id: foo }, null, 8 /* PROPS */, [\\"id\\"]),
_setBlockTracking(1),
_cache[1]
_cache[0]
)
]))
}
Expand All @@ -65,11 +65,11 @@ return function render(_ctx, _cache) {
const { setBlockTracking: _setBlockTracking, renderSlot: _renderSlot, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue
return (_openBlock(), _createElementBlock(\\"div\\", null, [
_cache[1] || (
_cache[0] || (
_setBlockTracking(-1),
_cache[1] = _renderSlot($slots, \\"default\\"),
_cache[0] = _renderSlot($slots, \\"default\\"),
_setBlockTracking(1),
_cache[1]
_cache[0]
)
]))
}
Expand All @@ -84,11 +84,11 @@ return function render(_ctx, _cache) {
const { setBlockTracking: _setBlockTracking, createElementVNode: _createElementVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue
return (_openBlock(), _createElementBlock(\\"div\\", null, [
_cache[1] || (
_cache[0] || (
_setBlockTracking(-1),
_cache[1] = _createElementVNode(\\"div\\"),
_cache[0] = _createElementVNode(\\"div\\"),
_setBlockTracking(1),
_cache[1]
_cache[0]
)
]))
}
Expand Down
56 changes: 56 additions & 0 deletions packages/compiler-core/__tests__/transforms/vMemo.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { baseCompile } from '../../src'

describe('compiler: v-memo transform', () => {
function compile(content: string) {
return baseCompile(`<div>${content}</div>`, {
mode: 'module',
prefixIdentifiers: true
}).code
}

test('on root element', () => {
expect(
baseCompile(`<div v-memo="[x]"></div>`, {
mode: 'module',
prefixIdentifiers: true
}).code
).toMatchSnapshot()
})

test('on normal element', () => {
expect(compile(`<div v-memo="[x]"></div>`)).toMatchSnapshot()
})

test('on component', () => {
expect(compile(`<Comp v-memo="[x]"></Comp>`)).toMatchSnapshot()
})

test('on v-if', () => {
expect(
compile(
`<div v-if="ok" v-memo="[x]"><span>foo</span>bar</div>
<Comp v-else v-memo="[x]"></Comp>`
)
).toMatchSnapshot()
})

test('on v-for', () => {
expect(
compile(
`<div v-for="{ x, y } in list" :key="x" v-memo="[x, y === z]">
<span>foobar</span>
</div>`
)
).toMatchSnapshot()
})

test('on template v-for', () => {
expect(
compile(
`<template v-for="{ x, y } in list" :key="x" v-memo="[x, y === z]">
<span>foobar</span>
</template>`
)
).toMatchSnapshot()
})
})
10 changes: 5 additions & 5 deletions packages/compiler-core/__tests__/transforms/vOn.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -452,7 +452,7 @@ describe('compiler: transform v-on', () => {
(vnodeCall.props as ObjectExpression).properties[0].value
).toMatchObject({
type: NodeTypes.JS_CACHE_EXPRESSION,
index: 1,
index: 0,
value: {
type: NodeTypes.SIMPLE_EXPRESSION,
content: `() => {}`
Expand All @@ -473,7 +473,7 @@ describe('compiler: transform v-on', () => {
(vnodeCall.props as ObjectExpression).properties[0].value
).toMatchObject({
type: NodeTypes.JS_CACHE_EXPRESSION,
index: 1,
index: 0,
value: {
type: NodeTypes.COMPOUND_EXPRESSION,
children: [
Expand All @@ -498,7 +498,7 @@ describe('compiler: transform v-on', () => {
(vnodeCall.props as ObjectExpression).properties[0].value
).toMatchObject({
type: NodeTypes.JS_CACHE_EXPRESSION,
index: 1,
index: 0,
value: {
type: NodeTypes.COMPOUND_EXPRESSION,
children: [
Expand Down Expand Up @@ -543,7 +543,7 @@ describe('compiler: transform v-on', () => {
(vnodeCall.props as ObjectExpression).properties[0].value
).toMatchObject({
type: NodeTypes.JS_CACHE_EXPRESSION,
index: 1,
index: 0,
value: {
type: NodeTypes.COMPOUND_EXPRESSION,
children: [`() => `, { content: `_ctx.foo` }, `()`]
Expand All @@ -565,7 +565,7 @@ describe('compiler: transform v-on', () => {
(vnodeCall.props as ObjectExpression).properties[0].value
).toMatchObject({
type: NodeTypes.JS_CACHE_EXPRESSION,
index: 1,
index: 0,
value: {
type: NodeTypes.COMPOUND_EXPRESSION,
children: [
Expand Down
10 changes: 5 additions & 5 deletions packages/compiler-core/__tests__/transforms/vOnce.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ describe('compiler: v-once transform', () => {
expect(root.helpers).toContain(SET_BLOCK_TRACKING)
expect(root.codegenNode).toMatchObject({
type: NodeTypes.JS_CACHE_EXPRESSION,
index: 1,
index: 0,
value: {
type: NodeTypes.VNODE_CALL,
tag: `"div"`
Expand All @@ -41,7 +41,7 @@ describe('compiler: v-once transform', () => {
expect(root.helpers).toContain(SET_BLOCK_TRACKING)
expect((root.children[0] as any).children[0].codegenNode).toMatchObject({
type: NodeTypes.JS_CACHE_EXPRESSION,
index: 1,
index: 0,
value: {
type: NodeTypes.VNODE_CALL,
tag: `"div"`
Expand All @@ -56,7 +56,7 @@ describe('compiler: v-once transform', () => {
expect(root.helpers).toContain(SET_BLOCK_TRACKING)
expect((root.children[0] as any).children[0].codegenNode).toMatchObject({
type: NodeTypes.JS_CACHE_EXPRESSION,
index: 1,
index: 0,
value: {
type: NodeTypes.VNODE_CALL,
tag: `_component_Comp`
Expand All @@ -71,7 +71,7 @@ describe('compiler: v-once transform', () => {
expect(root.helpers).toContain(SET_BLOCK_TRACKING)
expect((root.children[0] as any).children[0].codegenNode).toMatchObject({
type: NodeTypes.JS_CACHE_EXPRESSION,
index: 1,
index: 0,
value: {
type: NodeTypes.JS_CALL_EXPRESSION,
callee: RENDER_SLOT
Expand All @@ -90,7 +90,7 @@ describe('compiler: v-once transform', () => {
expect(root.hoists.length).toBe(0)
expect((root.children[0] as any).children[0].codegenNode).toMatchObject({
type: NodeTypes.JS_CACHE_EXPRESSION,
index: 1,
index: 0,
value: {
type: NodeTypes.VNODE_CALL,
tag: `"div"`
Expand Down
20 changes: 16 additions & 4 deletions packages/compiler-core/src/ast.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import {
RENDER_LIST,
OPEN_BLOCK,
FRAGMENT,
WITH_DIRECTIVES
WITH_DIRECTIVES,
WITH_MEMO
} from './runtimeHelpers'
import { PropsExpression } from './transforms/transformElement'
import { ImportItem, TransformContext } from './transform'
Expand Down Expand Up @@ -135,6 +136,7 @@ export interface PlainElementNode extends BaseElementNode {
| VNodeCall
| SimpleExpressionNode // when hoisted
| CacheExpression // when cached by v-once
| MemoExpression // when cached by v-memo
| undefined
ssrCodegenNode?: TemplateLiteral
}
Expand All @@ -144,6 +146,7 @@ export interface ComponentNode extends BaseElementNode {
codegenNode:
| VNodeCall
| CacheExpression // when cached by v-once
| MemoExpression // when cached by v-memo
| undefined
ssrCodegenNode?: CallExpression
}
Expand Down Expand Up @@ -375,6 +378,15 @@ export interface CacheExpression extends Node {
isVNode: boolean
}

export interface MemoExpression extends CallExpression {
callee: typeof WITH_MEMO
arguments: [ExpressionNode, MemoFactory, string, string]
}

interface MemoFactory extends FunctionExpression {
returns: BlockCodegenNode
}

// SSR-specific Node Types -----------------------------------------------------

export type SSRCodegenNode =
Expand Down Expand Up @@ -499,8 +511,8 @@ export interface DynamicSlotFnProperty extends Property {
export type BlockCodegenNode = VNodeCall | RenderSlotCall

export interface IfConditionalExpression extends ConditionalExpression {
consequent: BlockCodegenNode
alternate: BlockCodegenNode | IfConditionalExpression
consequent: BlockCodegenNode | MemoExpression
alternate: BlockCodegenNode | IfConditionalExpression | MemoExpression
}

export interface ForCodegenNode extends VNodeCall {
Expand Down Expand Up @@ -627,7 +639,7 @@ export function createObjectProperty(

export function createSimpleExpression(
content: SimpleExpressionNode['content'],
isStatic: SimpleExpressionNode['isStatic'],
isStatic: SimpleExpressionNode['isStatic'] = false,
loc: SourceLocation = locStub,
constType: ConstantTypes = ConstantTypes.NOT_CONSTANT
): SimpleExpressionNode {
Expand Down
6 changes: 3 additions & 3 deletions packages/compiler-core/src/codegen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -651,11 +651,11 @@ function genNode(node: CodegenNode | symbol | string, context: CodegenContext) {
case NodeTypes.JS_CACHE_EXPRESSION:
genCacheExpression(node, context)
break

// SSR only types
case NodeTypes.JS_BLOCK_STATEMENT:
!__BROWSER__ && genNodeList(node.body, context, true, false)
genNodeList(node.body, context, true, false)
break

// SSR only types
case NodeTypes.JS_TEMPLATE_LITERAL:
!__BROWSER__ && genTemplateLiteral(node, context)
break
Expand Down
Loading

0 comments on commit 3b64508

Please sign in to comment.