__TEST__: true,
__VERSION__: require('./package.json').version,
__BROWSER__: false,
+ __BUNDLER__: false,
__RUNTIME_COMPILE__: true,
__FEATURE_OPTIONS__: true,
__FEATURE_SUSPENSE__: true
return (_openBlock(), _createBlock(\\"div\\", null, [
_createVNode(\\"span\\", null, _toString(value + index), 1 /* TEXT */)
]))
- }), 128 /* UNKEYED_FRAGMENT */))
+ }), 256 /* UNKEYED_FRAGMENT */))
], 2 /* CLASS */))
}
}"
return (openBlock(), createBlock(\\"div\\", null, [
createVNode(\\"span\\", null, toString(value + index), 1 /* TEXT */)
]))
- }), 128 /* UNKEYED_FRAGMENT */))
+ }), 256 /* UNKEYED_FRAGMENT */))
], 2 /* CLASS */))
}"
`;
return (openBlock(), createBlock(\\"div\\", null, [
createVNode(\\"span\\", null, toString(value + index), 1 /* TEXT */)
]))
- }), 128 /* UNKEYED_FRAGMENT */))
+ }), 256 /* UNKEYED_FRAGMENT */))
], 2 /* CLASS */))
}"
`;
import { transformElement } from '../src/transforms/transformElement'
import { transformSlotOutlet } from '../src/transforms/transformSlotOutlet'
import { transformText } from '../src/transforms/transformText'
+import { genFlagText } from './testUtils'
+import { PatchFlags } from '@vue/shared'
describe('compiler: transform', () => {
test('context state', () => {
[
{ type: NodeTypes.ELEMENT, tag: `div` },
{ type: NodeTypes.ELEMENT, tag: `div` }
- ]
+ ],
+ genFlagText(PatchFlags.STABLE_FRAGMENT)
])
)
})
return (_openBlock(), _createBlock(\\"p\\", null, [
_createVNode(\\"span\\", null, _toString(o + 'foo'), 1 /* TEXT */)
]))
- }), 128 /* UNKEYED_FRAGMENT */))
+ }), 256 /* UNKEYED_FRAGMENT */))
]))
}
}"
return (_openBlock(), _createBlock(\\"p\\", null, [
_createVNode(\\"span\\", null, _toString(o), 1 /* TEXT */)
]))
- }), 128 /* UNKEYED_FRAGMENT */))
+ }), 256 /* UNKEYED_FRAGMENT */))
]))
}
}"
return (_openBlock(), _createBlock(\\"div\\", _hoisted_1, [
_hoisted_2
]))
- }), 128 /* UNKEYED_FRAGMENT */))
+ }), 256 /* UNKEYED_FRAGMENT */))
]))
}
}"
_createVNode(\\"div\\"),
_createTextVNode(_toString(foo) + \\" bar \\" + _toString(baz), 1 /* TEXT */),
_createVNode(\\"div\\")
- ]))
+ ], 64 /* STABLE_FRAGMENT */))
}
}"
`;
_createVNode(\\"div\\"),
_createTextVNode(\\"hello\\"),
_createVNode(\\"div\\")
- ]))
+ ], 64 /* STABLE_FRAGMENT */))
}
}"
`;
_createVNode(\\"div\\"),
_createTextVNode(\\"hello\\"),
_createVNode(\\"div\\")
- ]))
+ ], 64 /* STABLE_FRAGMENT */))
}
}"
`;
return (_openBlock(false), _createBlock(_Fragment, null, _renderList(items, (item) => {
return (_openBlock(), _createBlock(\\"span\\"))
- }), 128 /* UNKEYED_FRAGMENT */))
+ }), 256 /* UNKEYED_FRAGMENT */))
}
}"
`;
return (_openBlock(), _createBlock(_Fragment, { key: item }, [
\\"hello\\",
_createVNode(\\"span\\")
- ]))
- }), 64 /* KEYED_FRAGMENT */))
+ ], 64 /* STABLE_FRAGMENT */))
+ }), 128 /* KEYED_FRAGMENT */))
}
}"
`;
return (_openBlock(false), _createBlock(_Fragment, null, _renderList(items, (item) => {
return (_openBlock(), _createBlock(\\"span\\", { key: item }))
- }), 64 /* KEYED_FRAGMENT */))
+ }), 128 /* KEYED_FRAGMENT */))
}
}"
`;
return (_openBlock(false), _createBlock(_Fragment, null, _renderList(items, (item, __, index) => {
return (_openBlock(), _createBlock(\\"span\\"))
- }), 128 /* UNKEYED_FRAGMENT */))
+ }), 256 /* UNKEYED_FRAGMENT */))
}
}"
`;
return (_openBlock(false), _createBlock(_Fragment, null, _renderList(items, (_, __, index) => {
return (_openBlock(), _createBlock(\\"span\\"))
- }), 128 /* UNKEYED_FRAGMENT */))
+ }), 256 /* UNKEYED_FRAGMENT */))
}
}"
`;
return (_openBlock(false), _createBlock(_Fragment, null, _renderList(items, (_, key, index) => {
return (_openBlock(), _createBlock(\\"span\\"))
- }), 128 /* UNKEYED_FRAGMENT */))
+ }), 256 /* UNKEYED_FRAGMENT */))
}
}"
`;
return (_openBlock(), _createBlock(_Fragment, null, [
\\"hello\\",
_createVNode(\\"span\\")
- ]))
- }), 128 /* UNKEYED_FRAGMENT */))
+ ], 64 /* STABLE_FRAGMENT */))
+ }), 256 /* UNKEYED_FRAGMENT */))
}
}"
`;
return (_openBlock(false), _createBlock(_Fragment, null, _renderList(items, (item) => {
return _renderSlot($slots, \\"default\\")
- }), 128 /* UNKEYED_FRAGMENT */))
+ }), 256 /* UNKEYED_FRAGMENT */))
}
}"
`;
return (_openBlock(false), _createBlock(_Fragment, null, _renderList(items, (item) => {
return _renderSlot($slots, \\"default\\")
- }), 128 /* UNKEYED_FRAGMENT */))
+ }), 256 /* UNKEYED_FRAGMENT */))
}
}"
`;
return (_openBlock(), _withDirectives(_createBlock(\\"div\\", null, null, 32 /* NEED_PATCH */), [
[_directive_foo]
]))
- }), 128 /* UNKEYED_FRAGMENT */))
+ }), 256 /* UNKEYED_FRAGMENT */))
}
}"
`;
return (_openBlock(), ok
? _createBlock(_Fragment, { key: 0 }, _renderList(list, (i) => {
return (_openBlock(), _createBlock(\\"div\\"))
- }), 128 /* UNKEYED_FRAGMENT */)
+ }), 256 /* UNKEYED_FRAGMENT */)
: _createCommentVNode(\\"v-if\\", true))
}
}"
return (_openBlock(false), _createBlock(_Fragment, null, _renderList(items, (item, key, index) => {
return (_openBlock(), _createBlock(\\"span\\"))
- }), 128 /* UNKEYED_FRAGMENT */))
+ }), 256 /* UNKEYED_FRAGMENT */))
}
}"
`;
[_ctx.one]: ({ foo }) => [toString(foo), toString(_ctx.bar)],
[_ctx.two]: ({ bar }) => [toString(_ctx.foo), toString(bar)],
_compiled: true
- }, 256 /* DYNAMIC_SLOTS */))
+ }, 512 /* DYNAMIC_SLOTS */))
}"
`;
fn: () => [toString(name)]
}
})
- ]), 256 /* DYNAMIC_SLOTS */))
+ ]), 512 /* DYNAMIC_SLOTS */))
}"
`;
fn: (props) => [toString(props)]
}
: undefined
- ]), 256 /* DYNAMIC_SLOTS */))
+ ]), 512 /* DYNAMIC_SLOTS */))
}"
`;
name: \\"one\\",
fn: () => [\\"baz\\"]
}
- ]), 256 /* DYNAMIC_SLOTS */))
+ ]), 512 /* DYNAMIC_SLOTS */))
}
}"
`;
fn: () => [\\"hello\\"]
}
: undefined
- ]), 256 /* DYNAMIC_SLOTS */))
+ ]), 512 /* DYNAMIC_SLOTS */))
}
}"
`;
createVNode(_component_Inner, null, {
default: ({ bar }) => [toString(foo), toString(bar), toString(_ctx.baz)],
_compiled: true
- }, 256 /* DYNAMIC_SLOTS */),
+ }, 512 /* DYNAMIC_SLOTS */),
\\" \\",
toString(foo),
toString(_ctx.bar),
RENDER_SLOT,
WITH_DIRECTIVES
} from '../../src/runtimeHelpers'
-import { PatchFlags } from '@vue/runtime-dom'
+import { PatchFlags } from '@vue/shared'
import { createObjectMatcher, genFlagText } from '../testUtils'
function parseWithForTransform(
[
{ type: NodeTypes.TEXT, content: `hello` },
{ type: NodeTypes.ELEMENT, tag: `span` }
- ]
+ ],
+ genFlagText(PatchFlags.STABLE_FRAGMENT)
]
})
expect(generate(root).code).toMatchSnapshot()
[
{ type: NodeTypes.TEXT, content: `hello` },
{ type: NodeTypes.ELEMENT, tag: `span` }
- ]
+ ],
+ genFlagText(PatchFlags.STABLE_FRAGMENT)
]
})
expect(generate(root).code).toMatchSnapshot()
helper(FRAGMENT),
`null`,
root.children,
- `${PatchFlags.UNKEYED_FRAGMENT} /* ${
- PatchFlagNames[PatchFlags.UNKEYED_FRAGMENT]
+ `${PatchFlags.STABLE_FRAGMENT} /* ${
+ PatchFlagNames[PatchFlags.STABLE_FRAGMENT]
} */`
]),
context
createCallExpression(helper(CREATE_BLOCK), [
helper(FRAGMENT),
keyProperty ? createObjectExpression([keyProperty]) : `null`,
- node.children
+ node.children,
+ `${PatchFlags.STABLE_FRAGMENT} /* ${
+ PatchFlagNames[PatchFlags.STABLE_FRAGMENT]
+ } */`
]),
context
)
_createVNode(\\"div\\", null, \\"test\\"),
_createVNode(\\"div\\", { style: _hoisted_1 }, \\"red\\"),
_createVNode(\\"div\\", { style: {color: 'green'} }, null, 4 /* STYLE */)
- ]))
+ ], 64 /* STABLE_FRAGMENT */))
}
}"
`;
createVNode(\\"img\\", { src: _imports_0 }),
createVNode(\\"img\\", { src: _imports_1 }),
createVNode(\\"img\\", { src: _imports_1 })
- ]))
+ ], 64 /* STABLE_FRAGMENT */))
}"
`;
src: \\"./logo.png\\",
srcset: _hoisted_7
})
- ]))
+ ], 64 /* STABLE_FRAGMENT */))
}"
`;
resetOps,
dumpOps,
NodeOpTypes,
- serializeInner
+ serializeInner,
+ createTextVNode
} from '@vue/runtime-test'
describe('renderer: fragment', () => {
createVNode(
Fragment,
null,
- [h('div', 'one'), 'two'],
+ [
+ createVNode('div', null, 'one', PatchFlags.TEXT),
+ createTextVNode('two')
+ ],
PatchFlags.UNKEYED_FRAGMENT
),
root
createVNode(
Fragment,
null,
- [h('div', 'foo'), 'bar', 'baz'],
+ [
+ createVNode('div', null, 'foo', PatchFlags.TEXT),
+ createTextVNode('bar'),
+ createTextVNode('baz')
+ ],
PatchFlags.KEYED_FRAGMENT
),
root
PROPS: number
NEED_PATCH: number
FULL_PROPS: number
+ STABLE_FRAGMENT: number
KEYED_FRAGMENT: number
UNKEYED_FRAGMENT: number
DYNAMIC_SLOTS: number
const fragmentEndAnchor = (n2.anchor = n1
? n1.anchor
: hostCreateComment(showID ? `fragment-${devFragmentID}-end` : ''))!
- if (showID) {
- devFragmentID++
+ const { patchFlag } = n2
+ if (patchFlag > 0) {
+ optimized = true
}
if (n1 == null) {
+ if (showID) {
+ devFragmentID++
+ }
hostInsert(fragmentStartAnchor, container, anchor)
hostInsert(fragmentEndAnchor, container, anchor)
// a fragment can only have array children
optimized
)
} else {
- patchChildren(
- n1,
- n2,
- container,
- fragmentEndAnchor,
- parentComponent,
- parentSuspense,
- isSVG,
- optimized
- )
+ if (patchFlag & PatchFlags.STABLE_FRAGMENT && n2.dynamicChildren) {
+ // a stable fragment (template root or <template v-for>) doesn't need to
+ // patch children order, but it may contain dynamicChildren.
+ patchBlockChildren(
+ n1.dynamicChildren!,
+ n2.dynamicChildren,
+ container,
+ parentComponent,
+ parentSuspense,
+ isSVG
+ )
+ } else {
+ // keyed / unkeyed, or manual fragments.
+ // for keyed & unkeyed, since they are compiler generated from v-for,
+ // each child is guarunteed to be a block so the fragment will never
+ // have dynamicChildren.
+ patchChildren(
+ n1,
+ n2,
+ container,
+ fragmentEndAnchor,
+ parentComponent,
+ parentSuspense,
+ isSVG,
+ optimized
+ )
+ }
}
}
}
// fast path
if (patchFlag > 0) {
- optimized = true
if (patchFlag & PatchFlags.KEYED_FRAGMENT) {
// this could be either fully-keyed or mixed (some keyed some not)
// presence of patchFlag means children are guaranteed to be arrays
while (i <= e1 && i <= e2) {
const n1 = c1[e1]
const n2 = optimized
- ? (c2[i] as HostVNode)
+ ? (c2[e2] as HostVNode)
: (c2[e2] = normalizeVNode(c2[e2]))
if (isSameVNodeType(n1, n2)) {
patch(
// value.
NEED_PATCH = 1 << 5,
+ // Indicates a fragment whose children order doesn't change.
+ STABLE_FRAGMENT = 1 << 6,
+
// Indicates a fragment with keyed or partially keyed children
- KEYED_FRAGMENT = 1 << 6,
+ KEYED_FRAGMENT = 1 << 7,
// Indicates a fragment with unkeyed children.
- UNKEYED_FRAGMENT = 1 << 7,
+ UNKEYED_FRAGMENT = 1 << 8,
// Indicates a component with dynamic slots (e.g. slot that references a v-for
// iterated value, or dynamic slot names).
// Components with this flag are always force updated.
- DYNAMIC_SLOTS = 1 << 8,
+ DYNAMIC_SLOTS = 1 << 9,
// A special flag that indicates that the diffing algorithm should bail out
// of optimized mode. This is only on block fragments created by renderSlot()
[PatchFlags.PROPS]: `PROPS`,
[PatchFlags.NEED_PATCH]: `NEED_PATCH`,
[PatchFlags.FULL_PROPS]: `FULL_PROPS`,
+ [PatchFlags.STABLE_FRAGMENT]: `STABLE_FRAGMENT`,
[PatchFlags.KEYED_FRAGMENT]: `KEYED_FRAGMENT`,
[PatchFlags.UNKEYED_FRAGMENT]: `UNKEYED_FRAGMENT`,
[PatchFlags.DYNAMIC_SLOTS]: `DYNAMIC_SLOTS`,
page.on('console', e => {
if (e.type() === 'error') {
- console.error(`Error from Puppeteer-loaded page:`, e)
+ const err = e.args()[0] as any
+ console.error(
+ `Error from Puppeteer-loaded page:\n`,
+ err._remoteObject.description
+ )
}
})
})