Skip to content

Commit e5f23d9

Browse files
committed
fix component attrs/domProps merging in SSR
1 parent 240df14 commit e5f23d9

File tree

3 files changed

+77
-16
lines changed

3 files changed

+77
-16
lines changed

src/platforms/web/server/modules/attrs.js

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,28 @@ import {
88

99
export default function renderAttrs (node: VNodeWithData): string {
1010
let res = ''
11-
if (node.data.attrs) {
12-
res += render(node.data.attrs)
11+
if (node.data.attrs || node.parent) {
12+
res += render(node)
1313
}
1414
return res
1515
}
1616

17-
function render (attrs: { [key: string]: any }): string {
17+
function render (node): string {
18+
let attrs = node.data.attrs
1819
let res = ''
20+
21+
let parent = node.parent
22+
while (parent) {
23+
if (parent.data && parent.data.attrs) {
24+
attrs = Object.assign({}, attrs, parent.data.attrs)
25+
}
26+
parent = parent.parent
27+
}
28+
29+
if (!attrs) {
30+
return res
31+
}
32+
1933
for (const key in attrs) {
2034
if (key === 'style') {
2135
// leave it to the style module

src/platforms/web/server/modules/dom-props.js

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,31 @@ import VNode from 'core/vdom/vnode'
44
import { renderAttr } from './attrs'
55
import { propsToAttrMap, isRenderableAttr } from 'web/util/attrs'
66

7-
export default function (node: VNodeWithData): string {
8-
const props = node.data.domProps
7+
export default function renderDOMProps (node: VNodeWithData): string {
8+
let props = node.data.domProps
99
let res = ''
10-
if (props) {
11-
for (const key in props) {
12-
if (key === 'innerHTML') {
13-
setText(node, props[key], true)
14-
} else if (key === 'textContent') {
15-
setText(node, props[key])
16-
} else {
17-
const attr = propsToAttrMap[key] || key.toLowerCase()
18-
if (isRenderableAttr(attr)) {
19-
res += renderAttr(attr, props[key])
20-
}
10+
11+
let parent = node.parent
12+
while (parent) {
13+
if (parent.data && parent.data.domProps) {
14+
props = Object.assign({}, props, parent.data.domProps)
15+
}
16+
parent = parent.parent
17+
}
18+
19+
if (!props) {
20+
return res
21+
}
22+
23+
for (const key in props) {
24+
if (key === 'innerHTML') {
25+
setText(node, props[key], true)
26+
} else if (key === 'textContent') {
27+
setText(node, props[key])
28+
} else {
29+
const attr = propsToAttrMap[key] || key.toLowerCase()
30+
if (isRenderableAttr(attr)) {
31+
res += renderAttr(attr, props[key])
2132
}
2233
}
2334
}

test/ssr/ssr-string.spec.js

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,42 @@ describe('SSR: renderToString', () => {
167167
})
168168
})
169169

170+
it('attrs merging on components', done => {
171+
const Test = {
172+
render: h => h('div', {
173+
attrs: { id: 'a' }
174+
})
175+
}
176+
renderVmWithOptions({
177+
render: h => h(Test, {
178+
attrs: { id: 'b', name: 'c' }
179+
})
180+
}, res => {
181+
expect(res).toContain(
182+
'<div id="b" server-rendered="true" name="c"></div>'
183+
)
184+
done()
185+
})
186+
})
187+
188+
it('domProps merging on components', done => {
189+
const Test = {
190+
render: h => h('div', {
191+
domProps: { innerHTML: 'a' }
192+
})
193+
}
194+
renderVmWithOptions({
195+
render: h => h(Test, {
196+
domProps: { innerHTML: 'b', value: 'c' }
197+
})
198+
}, res => {
199+
expect(res).toContain(
200+
'<div server-rendered="true" value="c">b</div>'
201+
)
202+
done()
203+
})
204+
})
205+
170206
it('text interpolation', done => {
171207
renderVmWithOptions({
172208
template: '<div>{{ foo }} side {{ bar }}</div>',

0 commit comments

Comments
 (0)