}"
`;
+exports[`compiler: codegen forNode with constant expression 1`] = `
+"
+return function render(_ctx, _cache) {
+ with (_ctx) {
+ return (_openBlock(), _createBlock(_Fragment, null, _renderList(), 64 /* STABLE_FRAGMENT */))
+ }
+}"
+`;
+
exports[`compiler: codegen function mode preamble 1`] = `
"const _Vue = Vue
FRAGMENT,
RENDER_LIST
} from '../src/runtimeHelpers'
-import { createElementWithCodegen } from './testUtils'
+import { createElementWithCodegen, genFlagText } from './testUtils'
import { PatchFlags } from '@vue/shared'
function createRoot(options: Partial<RootNode> = {}): RootNode {
type: NodeTypes.VNODE_CALL,
tag: FRAGMENT,
isBlock: true,
- isForBlock: true,
+ disableTracking: true,
props: undefined,
children: createCallExpression(RENDER_LIST),
patchFlag: '1',
expect(code).toMatchSnapshot()
})
+ test('forNode with constant expression', () => {
+ const { code } = generate(
+ createRoot({
+ codegenNode: {
+ type: NodeTypes.FOR,
+ loc: locStub,
+ source: createSimpleExpression('1 + 2', false, locStub, true),
+ valueAlias: undefined,
+ keyAlias: undefined,
+ objectIndexAlias: undefined,
+ children: [],
+ parseResult: {} as any,
+ codegenNode: {
+ type: NodeTypes.VNODE_CALL,
+ tag: FRAGMENT,
+ isBlock: true,
+ disableTracking: false,
+ props: undefined,
+ children: createCallExpression(RENDER_LIST),
+ patchFlag: genFlagText(PatchFlags.STABLE_FRAGMENT),
+ dynamicProps: undefined,
+ directives: undefined,
+ loc: locStub
+ } as ForCodegenNode
+ }
+ })
+ )
+ expect(code).toMatch(`openBlock()`)
+ expect(code).toMatchSnapshot()
+ })
+
test('Element (callExpression + objectExpression + TemplateChildNode[])', () => {
const { code } = generate(
createRoot({
dynamicProps,
directives: undefined,
isBlock: false,
- isForBlock: false,
+ disableTracking: false,
loc: locStub
}
}
}"
`;
+exports[`compiler: v-for codegen v-for with constant expression 1`] = `
+"const _Vue = Vue
+
+return function render(_ctx, _cache) {
+ with (_ctx) {
+ const { renderList: _renderList, Fragment: _Fragment, openBlock: _openBlock, createBlock: _createBlock, toDisplayString: _toDisplayString, createVNode: _createVNode } = _Vue
+
+ return (_openBlock(), _createBlock(_Fragment, null, _renderList(10, (item) => {
+ return _createVNode(\\"p\\", null, _toDisplayString(item), 1 /* TEXT */)
+ }), 64 /* STABLE_FRAGMENT */))
+ }
+}"
+`;
+
exports[`compiler: v-for codegen v-if + v-for 1`] = `
"const _Vue = Vue
function assertSharedCodegen(
node: ForCodegenNode,
keyed: boolean = false,
- customReturn: boolean = false
+ customReturn: boolean = false,
+ disableTracking: boolean = true
) {
expect(node).toMatchObject({
type: NodeTypes.VNODE_CALL,
tag: FRAGMENT,
- isForBlock: true,
- patchFlag: keyed
- ? genFlagText(PatchFlags.KEYED_FRAGMENT)
- : genFlagText(PatchFlags.UNKEYED_FRAGMENT),
+ disableTracking,
+ patchFlag: !disableTracking
+ ? genFlagText(PatchFlags.STABLE_FRAGMENT)
+ : keyed
+ ? genFlagText(PatchFlags.KEYED_FRAGMENT)
+ : genFlagText(PatchFlags.UNKEYED_FRAGMENT),
children: {
type: NodeTypes.JS_CALL_EXPRESSION,
callee: RENDER_LIST,
? {}
: {
type: NodeTypes.VNODE_CALL,
- isBlock: true
+ isBlock: disableTracking
}
}
]
expect(generate(root).code).toMatchSnapshot()
})
+ test('v-for with constant expression', () => {
+ const {
+ root,
+ node: { codegenNode }
+ } = parseWithForTransform('<p v-for="item in 10">{{item}}</p>', {
+ prefixIdentifiers: true
+ })
+
+ expect(
+ assertSharedCodegen(
+ codegenNode,
+ false /* keyed */,
+ false /* customReturn */,
+ false /* disableTracking */
+ )
+ ).toMatchObject({
+ source: { content: `10`, isConstant: true },
+ params: [{ content: `item` }],
+ innerVNodeCall: {
+ tag: `"p"`,
+ props: undefined,
+ isBlock: false,
+ children: {
+ type: NodeTypes.INTERPOLATION,
+ content: {
+ type: NodeTypes.SIMPLE_EXPRESSION,
+ content: 'item',
+ isStatic: false,
+ isConstant: false
+ }
+ },
+ patchFlag: genFlagText(PatchFlags.TEXT)
+ }
+ })
+ expect(generate(root).code).toMatchSnapshot()
+ })
+
test('template v-for', () => {
const {
root,
key: `[0]`
}),
isBlock: true,
- isForBlock: true,
+ disableTracking: true,
patchFlag: genFlagText(PatchFlags.UNKEYED_FRAGMENT),
children: {
type: NodeTypes.JS_CALL_EXPRESSION,
dynamicProps: string | undefined
directives: DirectiveArguments | undefined
isBlock: boolean
- isForBlock: boolean
+ disableTracking: boolean
}
// JS Node Types ---------------------------------------------------------------
props: undefined
children: ForRenderListExpression
patchFlag: string
- isForBlock: true
+ disableTracking: boolean
}
export interface ForRenderListExpression extends CallExpression {
dynamicProps?: VNodeCall['dynamicProps'],
directives?: VNodeCall['directives'],
isBlock: VNodeCall['isBlock'] = false,
- isForBlock: VNodeCall['isForBlock'] = false,
+ disableTracking: VNodeCall['disableTracking'] = false,
loc = locStub
): VNodeCall {
if (context) {
dynamicProps,
directives,
isBlock,
- isForBlock,
+ disableTracking,
loc
}
}
dynamicProps,
directives,
isBlock,
- isForBlock
+ disableTracking
} = node
if (directives) {
push(helper(WITH_DIRECTIVES) + `(`)
}
if (isBlock) {
- push(`(${helper(OPEN_BLOCK)}(${isForBlock ? `true` : ``}), `)
+ push(`(${helper(OPEN_BLOCK)}(${disableTracking ? `true` : ``}), `)
}
if (pure) {
push(PURE_ANNOTATION)
vnodeDynamicProps,
vnodeDirectives,
!!shouldUseBlock,
- false /* isForBlock */,
+ false /* disableTracking */,
node.loc
)
}
forNode.source
]) as ForRenderListExpression
const keyProp = findProp(node, `key`)
- const fragmentFlag = keyProp
- ? PatchFlags.KEYED_FRAGMENT
- : PatchFlags.UNKEYED_FRAGMENT
+ const isStableFragment =
+ forNode.source.type === NodeTypes.SIMPLE_EXPRESSION &&
+ forNode.source.isConstant
+ const fragmentFlag = isStableFragment
+ ? PatchFlags.STABLE_FRAGMENT
+ : keyProp
+ ? PatchFlags.KEYED_FRAGMENT
+ : PatchFlags.UNKEYED_FRAGMENT
forNode.codegenNode = createVNodeCall(
context,
helper(FRAGMENT),
undefined,
undefined,
true /* isBlock */,
- true /* isForBlock */,
+ !isStableFragment /* disableTracking */,
node.loc
) as ForCodegenNode
// but mark it as a block.
childBlock = (children[0] as PlainElementNode)
.codegenNode as VNodeCall
- childBlock.isBlock = true
- helper(OPEN_BLOCK)
- helper(CREATE_BLOCK)
+ childBlock.isBlock = !isStableFragment
+ if (childBlock.isBlock) {
+ helper(OPEN_BLOCK)
+ helper(CREATE_BLOCK)
+ }
}
renderExp.arguments.push(createFunctionExpression(