Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 19a870d

Browse files
authored
fix(compiler-vapor): use createElement path for plain template (#14744)
1 parent 05426e0 commit 19a870d

14 files changed

Lines changed: 546 additions & 32 deletions

File tree

‎packages/compiler-vapor/__tests__/abbreviation.spec.ts‎

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -179,17 +179,17 @@ test('always close tags', () => {
179179
'<div><textarea></textarea><span>sibling</span></div>',
180180
)
181181

182-
// template always needs closing tag unless rightmost
183-
checkAbbr(
184-
'<div><template></template></div>',
185-
'<div><template>',
186-
'<div><template></template></div>',
187-
)
188-
checkAbbr(
189-
'<div><template></template><span>sibling</span></div>',
190-
'<div><template></template><span>sibling',
191-
'<div><template></template><span>sibling</span></div>',
192-
)
182+
// native <template> now always goes through createElement path
183+
// checkAbbr(
184+
// '<div><template></template></div>',
185+
// '<div><template>',
186+
// '<div><template></template></div>',
187+
// )
188+
// checkAbbr(
189+
// '<div><template></template><span>sibling</span></div>',
190+
// '<div><template></template><span>sibling',
191+
// '<div><template></template><span>sibling</span></div>',
192+
// )
193193

194194
// script always needs closing tag unless rightmost
195195
checkAbbr(

‎packages/compiler-vapor/__tests__/transforms/__snapshots__/transformElement.spec.ts.snap‎

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,20 @@ export function render(_ctx) {
400400
}"
401401
`;
402402
403+
exports[`compiler: element transform > custom element with dynamic child 1`] = `
404+
"import { createPlainElement as _createPlainElement, txt as _txt, insert as _insert, toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect, template as _template } from 'vue';
405+
const t0 = _template("<div> ")
406+
407+
export function render(_ctx) {
408+
const n1 = _createPlainElement("my-custom-element", null, null, true)
409+
const n0 = t0()
410+
const x0 = _txt(n0)
411+
_insert(n0, n1)
412+
_renderEffect(() => _setText(x0, _toDisplayString(_ctx.msg)))
413+
return n1
414+
}"
415+
`;
416+
403417
exports[`compiler: element transform > dynamic component > capitalized version w/ static binding 1`] = `
404418
"import { resolveDynamicComponent as _resolveDynamicComponent, createComponentWithFallback as _createComponentWithFallback } from 'vue';
405419
@@ -519,6 +533,57 @@ export function render(_ctx) {
519533
}"
520534
`;
521535
536+
exports[`compiler: element transform > plain template element 1`] = `
537+
"import { createPlainElement as _createPlainElement, txt as _txt, insert as _insert, toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect, template as _template } from 'vue';
538+
const t0 = _template("<div> ")
539+
540+
export function render(_ctx) {
541+
const n1 = _createPlainElement("template", null, null, true)
542+
const n0 = t0()
543+
const x0 = _txt(n0)
544+
_insert(n0, n1)
545+
_renderEffect(() => _setText(x0, _toDisplayString(_ctx.msg)))
546+
return n1
547+
}"
548+
`;
549+
550+
exports[`compiler: element transform > plain template element with dynamic text child 1`] = `
551+
"import { createPlainElement as _createPlainElement, insert as _insert, toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect, template as _template } from 'vue';
552+
const t0 = _template("")
553+
554+
export function render(_ctx) {
555+
const n1 = _createPlainElement("template", null, null, true)
556+
const n0 = t0()
557+
_insert(n0, n1)
558+
_renderEffect(() => _setText(n0, _toDisplayString(_ctx.msg)))
559+
return n1
560+
}"
561+
`;
562+
563+
exports[`compiler: element transform > plain template element with static child 1`] = `
564+
"import { createPlainElement as _createPlainElement, insert as _insert, template as _template } from 'vue';
565+
const t0 = _template("<div>hi")
566+
567+
export function render(_ctx) {
568+
const n1 = _createPlainElement("template", null, null, true)
569+
const n0 = t0()
570+
_insert(n0, n1)
571+
return n1
572+
}"
573+
`;
574+
575+
exports[`compiler: element transform > plain template element with static text child 1`] = `
576+
"import { createPlainElement as _createPlainElement, insert as _insert, template as _template } from 'vue';
577+
const t0 = _template("hello")
578+
579+
export function render(_ctx) {
580+
const n1 = _createPlainElement("template", null, null, true)
581+
const n0 = t0()
582+
_insert(n0, n1)
583+
return n1
584+
}"
585+
`;
586+
522587
exports[`compiler: element transform > props + child 1`] = `
523588
"import { template as _template } from 'vue';
524589
const t0 = _template("<div id=foo><span>", true)

‎packages/compiler-vapor/__tests__/transforms/__snapshots__/transformText.spec.ts.snap‎

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,48 @@ export function render(_ctx) {
2121
}"
2222
`;
2323
24+
exports[`compiler: text transform > escapes raw static text for custom element createElement path 1`] = `
25+
"import { createPlainElement as _createPlainElement, setText as _setText, insert as _insert, template as _template } from 'vue';
26+
const t0 = _template("")
27+
28+
export function render(_ctx) {
29+
const n1 = _createPlainElement("my-el", null, null, true)
30+
const n0 = t0()
31+
_setText(n0, "<b>foo</b>")
32+
_insert(n0, n1)
33+
return n1
34+
}"
35+
`;
36+
37+
exports[`compiler: text transform > escapes raw static text for plain template createElement path 1`] = `
38+
"import { createPlainElement as _createPlainElement, setText as _setText, insert as _insert, template as _template } from 'vue';
39+
const t0 = _template("")
40+
41+
export function render(_ctx) {
42+
const n1 = _createPlainElement("template", null, null, true)
43+
const n0 = t0()
44+
_setText(n0, "<b>foo</b>")
45+
_insert(n0, n1)
46+
return n1
47+
}"
48+
`;
49+
50+
exports[`compiler: text transform > materializes literal interpolation text for mixed plain template children 1`] = `
51+
"import { createPlainElement as _createPlainElement, setText as _setText, insert as _insert, template as _template } from 'vue';
52+
const t0 = _template("<span></span>")
53+
const t1 = _template("")
54+
55+
export function render(_ctx) {
56+
const n2 = _createPlainElement("template", null, null, true)
57+
const n0 = t0()
58+
const n1 = t1()
59+
_setText(n1, "<b>foo</b>")
60+
_insert([n0, n1], n2)
61+
_insert([n0, n1], n2)
62+
return n2
63+
}"
64+
`;
65+
2466
exports[`compiler: text transform > no consecutive text 1`] = `
2567
"import { setText as _setText, template as _template } from 'vue';
2668
const t0 = _template(" ")

‎packages/compiler-vapor/__tests__/transforms/__snapshots__/vText.spec.ts.snap‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,16 @@ export function render(_ctx) {
5454
return n0
5555
}"
5656
`;
57+
58+
exports[`v-text > work with plain template createElement path 1`] = `
59+
"import { createPlainElement as _createPlainElement, insert as _insert, toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect, template as _template } from 'vue';
60+
const t0 = _template("")
61+
62+
export function render(_ctx) {
63+
const n1 = _createPlainElement("template", null, null, true)
64+
const n0 = t0()
65+
_insert(n0, n1)
66+
_renderEffect(() => _setText(n0, _toDisplayString(_ctx.foo)))
67+
return n1
68+
}"
69+
`;

‎packages/compiler-vapor/__tests__/transforms/transformElement.spec.ts‎

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1151,6 +1151,53 @@ describe('compiler: element transform', () => {
11511151
expect(code).toContain('createPlainElement')
11521152
})
11531153

1154+
test('custom element with dynamic child', () => {
1155+
const { code } = compileWithElementTransform(
1156+
'<my-custom-element><div>{{ msg }}</div></my-custom-element>',
1157+
{
1158+
isCustomElement: tag => tag === 'my-custom-element',
1159+
},
1160+
)
1161+
expect(code).toMatchSnapshot()
1162+
expect(code).toContain('createPlainElement')
1163+
expect(code).toContain('_insert(')
1164+
})
1165+
1166+
test('plain template element', () => {
1167+
const { code } = compileWithElementTransform(
1168+
'<template><div>{{ msg }}</div></template>',
1169+
)
1170+
expect(code).toMatchSnapshot()
1171+
expect(code).toContain('createPlainElement')
1172+
expect(code).not.toContain('_template("<template>')
1173+
})
1174+
1175+
test('plain template element with static child', () => {
1176+
const { code } = compileWithElementTransform(
1177+
'<template><div>hi</div></template>',
1178+
)
1179+
expect(code).toMatchSnapshot()
1180+
expect(code).toContain('createPlainElement')
1181+
expect(code).not.toContain('_template("<template>')
1182+
})
1183+
1184+
test('plain template element with static text child', () => {
1185+
const { code } = compileWithElementTransform('<template>hello</template>')
1186+
expect(code).toMatchSnapshot()
1187+
expect(code).toContain('createPlainElement')
1188+
expect(code).not.toContain('_template("<template>')
1189+
})
1190+
1191+
test('plain template element with dynamic text child', () => {
1192+
const { code } = compileWithElementTransform(
1193+
'<template>{{ msg }}</template>',
1194+
)
1195+
expect(code).toMatchSnapshot()
1196+
expect(code).toContain('createPlainElement')
1197+
expect(code).toContain('_insert(')
1198+
expect(code).not.toContain('_txt(n0)')
1199+
})
1200+
11541201
test('svg', () => {
11551202
const t = `<svg><circle r="40"></circle></svg>`
11561203
const { code, ir } = compileWithElementTransform(t)

‎packages/compiler-vapor/__tests__/transforms/transformText.spec.ts‎

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,39 @@ describe('compiler: text transform', () => {
6262
expect([...ir.template.keys()]).not.toContain('<code><script>')
6363
})
6464

65+
it('escapes raw static text for plain template createElement path', () => {
66+
const { code } = compileWithTextTransform(
67+
'<template>&lt;b&gt;foo&lt;/b&gt;</template>',
68+
)
69+
expect(code).toMatchSnapshot()
70+
expect(code).toContain('const t0 = _template("")')
71+
expect(code).toContain('_setText(n0, "<b>foo</b>")')
72+
expect(code).not.toContain('_template("<b>foo</b>")')
73+
})
74+
75+
it('escapes raw static text for custom element createElement path', () => {
76+
const { code } = compileWithTextTransform(
77+
'<my-el>&lt;b&gt;foo&lt;/b&gt;</my-el>',
78+
{
79+
isCustomElement: tag => tag === 'my-el',
80+
},
81+
)
82+
expect(code).toMatchSnapshot()
83+
expect(code).toContain('const t0 = _template("")')
84+
expect(code).toContain('_setText(n0, "<b>foo</b>")')
85+
expect(code).not.toContain('_template("<b>foo</b>")')
86+
})
87+
88+
it('materializes literal interpolation text for mixed plain template children', () => {
89+
const { code } = compileWithTextTransform(
90+
'<template><span></span>{{ "<b>foo</b>" }}</template>',
91+
)
92+
expect(code).toMatchSnapshot()
93+
expect(code).toContain('const t1 = _template("")')
94+
expect(code).toContain('_setText(n1, "<b>foo</b>")')
95+
expect(code).not.toContain('_template("<b>foo</b>")')
96+
})
97+
6598
it('should not escape quotes in root-level text nodes', () => {
6699
// Root-level text goes through createTextNode() which doesn't need escaping
67100
const { ir } = compileWithTextTransform(`Howdy y'all`)

‎packages/compiler-vapor/__tests__/transforms/vText.spec.ts‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,14 @@ describe('v-text', () => {
7070
expect(code).contains('setBlockText(n0, _toDisplayString(_ctx.foo))')
7171
})
7272

73+
test('work with plain template createElement path', () => {
74+
const { code } = compileWithVText(`<template v-text="foo"></template>`)
75+
expect(code).matchSnapshot()
76+
expect(code).toContain('createPlainElement')
77+
expect(code).toContain('_insert(')
78+
expect(code).not.toContain('_txt(n0)')
79+
})
80+
7381
test('should raise error and ignore children when v-text is present', () => {
7482
const onError = vi.fn()
7583
const { code, ir } = compileWithVText(`<div v-text="test">hello</div>`, {

‎packages/compiler-vapor/src/generators/component.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ export function genCreateComponent(
8585
...genCall(
8686
operation.dynamic && !operation.dynamic.isStatic
8787
? helper('createDynamicComponent')
88-
: operation.isCustomElement
88+
: operation.useCreateElement
8989
? helper('createPlainElement')
9090
: operation.asset
9191
? helper('createComponentWithFallback')
@@ -100,7 +100,7 @@ export function genCreateComponent(
100100
]
101101

102102
function genTag() {
103-
if (operation.isCustomElement) {
103+
if (operation.useCreateElement) {
104104
return JSON.stringify(operation.tag)
105105
} else if (operation.dynamic) {
106106
if (operation.dynamic.isStatic) {

‎packages/compiler-vapor/src/ir/index.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ export interface CreateComponentIRNode extends BaseIRNode {
221221
root: boolean
222222
once: boolean
223223
dynamic?: SimpleExpressionNode
224-
isCustomElement: boolean
224+
useCreateElement: boolean
225225
parent?: number
226226
anchor?: number
227227
logicalIndex?: number

‎packages/compiler-vapor/src/transforms/transformChildren.ts‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
type InsertionStateTypes,
1212
isBlockOperation,
1313
} from '../ir'
14+
import { shouldUseCreateElement } from './transformElement'
1415

1516
export const transformChildren: NodeTransform = (node, context) => {
1617
const isFragment =
@@ -21,6 +22,10 @@ export const transformChildren: NodeTransform = (node, context) => {
2122

2223
if (!isFragment && node.type !== NodeTypes.ELEMENT) return
2324

25+
const useCreateElement =
26+
node.type === NodeTypes.ELEMENT &&
27+
shouldUseCreateElement(node, context as TransformContext<ElementNode>)
28+
2429
for (const [i, child] of node.children.entries()) {
2530
const childContext = context.create(child, i)
2631
transformNode(childContext)
@@ -37,6 +42,21 @@ export const transformChildren: NodeTransform = (node, context) => {
3742
) {
3843
context.block.returns.push(childContext.dynamic.id!)
3944
}
45+
} else if (useCreateElement) {
46+
const createsNode =
47+
childContext.template !== '' ||
48+
childDynamic.template != null ||
49+
childDynamic.id !== undefined ||
50+
childDynamic.operation !== undefined ||
51+
childDynamic.hasDynamicChild === true
52+
53+
if (createsNode) {
54+
// createElement-backed parents don't materialize childNodes from a
55+
// static HTML string, so every real child node must be inserted.
56+
childContext.reference()
57+
childContext.registerTemplate()
58+
childDynamic.flags |= DynamicFlag.INSERT | DynamicFlag.NON_TEMPLATE
59+
}
4060
} else {
4161
context.childrenTemplate.push(childContext.template)
4262
}

0 commit comments

Comments
 (0)