Skip to content

Commit 090eb0c

Browse files
committed
wip(compiler-ssr): v-html, v-text & textarea value
1 parent b59524e commit 090eb0c

File tree

6 files changed

+137
-74
lines changed

6 files changed

+137
-74
lines changed

packages/compiler-ssr/__tests__/ssrCompile.spec.ts

-62
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { getCompiledString } from './utils'
2+
3+
describe('element', () => {
4+
test('basic elements', () => {
5+
expect(getCompiledString(`<div></div>`)).toMatchInlineSnapshot(
6+
`"\`<div></div>\`"`
7+
)
8+
expect(getCompiledString(`<div/>`)).toMatchInlineSnapshot(
9+
`"\`<div></div>\`"`
10+
)
11+
})
12+
13+
test('static attrs', () => {
14+
expect(
15+
getCompiledString(`<div id="foo" class="bar"></div>`)
16+
).toMatchInlineSnapshot(`"\`<div id=\\"foo\\" class=\\"bar\\"></div>\`"`)
17+
})
18+
19+
test('nested elements', () => {
20+
expect(
21+
getCompiledString(`<div><span></span><span></span></div>`)
22+
).toMatchInlineSnapshot(`"\`<div><span></span><span></span></div>\`"`)
23+
})
24+
25+
test('void element', () => {
26+
expect(getCompiledString(`<input>`)).toMatchInlineSnapshot(`"\`<input>\`"`)
27+
})
28+
29+
test('v-html', () => {
30+
expect(getCompiledString(`<div v-html="foo"/>`)).toMatchInlineSnapshot(
31+
`"\`<div>\${_ctx.foo}</div>\`"`
32+
)
33+
})
34+
35+
test('v-text', () => {
36+
expect(getCompiledString(`<div v-text="foo"/>`)).toMatchInlineSnapshot(
37+
`"\`<div>\${interpolate(_ctx.foo)}</div>\`"`
38+
)
39+
})
40+
41+
test('<textarea> with dynamic value', () => {
42+
expect(getCompiledString(`<textarea :value="foo"/>`)).toMatchInlineSnapshot(
43+
`"\`<textarea>\${interpolate(_ctx.foo)}</textarea>\`"`
44+
)
45+
})
46+
47+
test('<textarea> with static value', () => {
48+
expect(
49+
getCompiledString(`<textarea value="fo&gt;o"/>`)
50+
).toMatchInlineSnapshot(`"\`<textarea>fo&gt;o</textarea>\`"`)
51+
})
52+
})
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { getCompiledString } from './utils'
2+
3+
describe('text', () => {
4+
test('static text', () => {
5+
expect(getCompiledString(`foo`)).toMatchInlineSnapshot(`"\`foo\`"`)
6+
})
7+
8+
test('static text escape', () => {
9+
expect(getCompiledString(`&lt;foo&gt;`)).toMatchInlineSnapshot(
10+
`"\`&lt;foo&gt;\`"`
11+
)
12+
})
13+
14+
test('nested elements with static text', () => {
15+
expect(
16+
getCompiledString(`<div><span>hello</span><span>bye</span></div>`)
17+
).toMatchInlineSnapshot(
18+
`"\`<div><span>hello</span><span>bye</span></div>\`"`
19+
)
20+
})
21+
22+
test('interpolation', () => {
23+
expect(getCompiledString(`foo {{ bar }} baz`)).toMatchInlineSnapshot(
24+
`"\`foo \${interpolate(_ctx.bar)} baz\`"`
25+
)
26+
})
27+
28+
test('nested elements with interpolation', () => {
29+
expect(
30+
getCompiledString(
31+
`<div><span>{{ foo }} bar</span><span>baz {{ qux }}</span></div>`
32+
)
33+
).toMatchInlineSnapshot(
34+
`"\`<div><span>\${interpolate(_ctx.foo)} bar</span><span>baz \${interpolate(_ctx.qux)}</span></div>\`"`
35+
)
36+
})
37+
})
+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { compile } from '../src'
2+
3+
export function getCompiledString(src: string): string {
4+
return compile(src).code.match(/_push\((.*)\)/)![1]
5+
}

packages/compiler-ssr/src/runtimeHelpers.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { registerRuntimeHelpers } from '@vue/compiler-core'
1+
import { registerRuntimeHelpers } from '@vue/compiler-dom'
22

33
export const INTERPOLATE = Symbol(`interpolate`)
44

packages/compiler-ssr/src/transforms/ssrTransformElement.ts

+42-11
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ import {
33
NodeTypes,
44
ElementTypes,
55
TemplateLiteral,
6-
createTemplateLiteral
6+
createTemplateLiteral,
7+
createInterpolation
78
} from '@vue/compiler-dom'
89
import { escapeHtml } from '@vue/shared'
910

@@ -43,27 +44,57 @@ export const ssrTransformElement: NodeTransform = (node, context) => {
4344
// element
4445
// generate the template literal representing the open tag.
4546
const openTag: TemplateLiteral['elements'] = [`<${node.tag}`]
47+
let rawChildren
4648

4749
for (let i = 0; i < node.props.length; i++) {
4850
const prop = node.props[i]
4951
if (prop.type === NodeTypes.DIRECTIVE) {
50-
const directiveTransform = context.directiveTransforms[prop.name]
51-
if (directiveTransform) {
52-
// TODO directive transforms
52+
// special cases with children override
53+
if (prop.name === 'html' && prop.exp) {
54+
node.children = []
55+
rawChildren = prop.exp
56+
} else if (prop.name === 'text' && prop.exp) {
57+
node.children = [createInterpolation(prop.exp, prop.loc)]
58+
} else if (
59+
// v-bind:value on textarea
60+
node.tag === 'textarea' &&
61+
prop.name === 'bind' &&
62+
prop.exp &&
63+
prop.arg &&
64+
prop.arg.type === NodeTypes.SIMPLE_EXPRESSION &&
65+
prop.arg.isStatic &&
66+
prop.arg.content === 'value'
67+
) {
68+
node.children = [createInterpolation(prop.exp, prop.loc)]
69+
// TODO handle <textrea> with dynamic v-bind
5370
} else {
54-
// no corresponding ssr directive transform found.
55-
// TODO emit error
71+
const directiveTransform = context.directiveTransforms[prop.name]
72+
if (directiveTransform) {
73+
// TODO directive transforms
74+
} else {
75+
// no corresponding ssr directive transform found.
76+
// TODO emit error
77+
}
5678
}
5779
} else {
58-
// static prop
59-
openTag.push(
60-
` ${prop.name}` +
61-
(prop.value ? `="${escapeHtml(prop.value.content)}"` : ``)
62-
)
80+
// special case: value on <textarea>
81+
if (node.tag === 'textarea' && prop.name === 'value' && prop.value) {
82+
node.children = []
83+
rawChildren = escapeHtml(prop.value.content)
84+
} else {
85+
// static prop
86+
openTag.push(
87+
` ${prop.name}` +
88+
(prop.value ? `="${escapeHtml(prop.value.content)}"` : ``)
89+
)
90+
}
6391
}
6492
}
6593

6694
openTag.push(`>`)
95+
if (rawChildren) {
96+
openTag.push(rawChildren)
97+
}
6798
node.ssrCodegenNode = createTemplateLiteral(openTag)
6899
}
69100
}

0 commit comments

Comments
 (0)