fix(ssr): fix on-component directives rendering (#12661)

fix #10733
This commit is contained in:
Alexander Lichter 2022-08-18 10:22:55 +02:00 committed by GitHub
parent bba6b3d6b4
commit 165a14a6c6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 103 additions and 2 deletions

View File

@ -206,6 +206,11 @@ function renderComponentInner(node, isRoot, context) {
type: 'Component',
prevActive
})
if (isDef(node.data) && isDef(node.data.directives)) {
childNode.data = childNode.data || {}
childNode.data.directives = node.data.directives
childNode.isComponentRootElement = true
}
renderNode(childNode, isRoot, context)
}
@ -372,7 +377,10 @@ function renderStartingTag(node: VNode, context) {
if (dirRenderer) {
// directives mutate the node's data
// which then gets rendered by modules
dirRenderer(node, dirs[i])
dirRenderer(
node.isComponentRootElement ? node.parent : node,
dirs[i]
)
}
}
}

View File

@ -1086,7 +1086,7 @@ describe('SSR: renderToString', () => {
)
})
it('custom directives', done => {
it('custom directives on raw element', done => {
const renderer = createRenderer({
directives: {
'class-prefixer': (node, dir) => {
@ -1129,6 +1129,98 @@ describe('SSR: renderToString', () => {
)
})
it('custom directives on component', done => {
const Test = {
template: '<span>hello world</span>'
}
const renderer = createRenderer({
directives: {
'class-prefixer': (node, dir) => {
if (node.data.class) {
node.data.class = `${dir.value}-${node.data.class}`
}
if (node.data.staticClass) {
node.data.staticClass = `${dir.value}-${node.data.staticClass}`
}
}
}
})
renderer.renderToString(
new Vue({
template:
'<p><Test v-class-prefixer="\'my\'" class="class1" :class="\'class2\'" /></p>',
components: { Test }
}),
(err, result) => {
expect(err).toBeNull()
expect(result).toContain(
'<p data-server-rendered="true"><span class="my-class1 my-class2">hello world</span></p>'
)
done()
}
)
})
it('custom directives on element root of a component', done => {
const Test = {
template:
'<span v-class-prefixer="\'my\'" class="class1" :class="\'class2\'">hello world</span>'
}
const renderer = createRenderer({
directives: {
'class-prefixer': (node, dir) => {
if (node.data.class) {
node.data.class = `${dir.value}-${node.data.class}`
}
if (node.data.staticClass) {
node.data.staticClass = `${dir.value}-${node.data.staticClass}`
}
}
}
})
renderer.renderToString(
new Vue({
template: '<p><Test /></p>',
components: { Test }
}),
(err, result) => {
expect(err).toBeNull()
expect(result).toContain(
'<p data-server-rendered="true"><span class="my-class1 my-class2">hello world</span></p>'
)
done()
}
)
})
it('custom directives on element with parent element', done => {
const renderer = createRenderer({
directives: {
'class-prefixer': (node, dir) => {
if (node.data.class) {
node.data.class = `${dir.value}-${node.data.class}`
}
if (node.data.staticClass) {
node.data.staticClass = `${dir.value}-${node.data.staticClass}`
}
}
}
})
renderer.renderToString(
new Vue({
template:
'<p><span v-class-prefixer="\'my\'" class="class1" :class="\'class2\'">hello world</span></p>'
}),
(err, result) => {
expect(err).toBeNull()
expect(result).toContain(
'<p data-server-rendered="true"><span class="my-class1 my-class2">hello world</span></p>'
)
done()
}
)
})
it('should not warn for custom directives that do not have server-side implementation', done => {
renderToString(
new Vue({

View File

@ -33,6 +33,7 @@ export default class VNode {
fnOptions?: ComponentOptions | null // for SSR caching
devtoolsMeta?: Object | null // used to store functional render context for devtools
fnScopeId?: string | null // functional scope id support
isComponentRootElement?: boolean | null // for SSR directives
constructor(
tag?: string,