diff --git a/src/server/render.js b/src/server/render.js index 05ba588006d..f1023b3dbc1 100644 --- a/src/server/render.js +++ b/src/server/render.js @@ -201,6 +201,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) } @@ -364,7 +369,7 @@ 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]) } } } diff --git a/test/ssr/ssr-string.spec.js b/test/ssr/ssr-string.spec.js index e18ca2aead9..d483aa69b40 100644 --- a/test/ssr/ssr-string.spec.js +++ b/test/ssr/ssr-string.spec.js @@ -829,7 +829,7 @@ describe('SSR: renderToString', () => { }) }) - it('custom directives', done => { + it('custom directives on raw element', done => { const renderer = createRenderer({ directives: { 'class-prefixer': (node, dir) => { @@ -861,6 +861,80 @@ describe('SSR: renderToString', () => { }) }) + it('custom directives on component', done => { + const Test = { + template: 'hello world' + } + 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: '

', + components: { Test }, + }), (err, result) => { + expect(err).toBeNull() + expect(result).toContain('

hello world

') + done() + }) + }) + + it('custom directives on element root of a component', done => { + const Test = { + template: 'hello world' + } + 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: '

', + components: { Test }, + }), (err, result) => { + expect(err).toBeNull() + expect(result).toContain('

hello world

') + 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: '

hello world

', + }), (err, result) => { + expect(err).toBeNull() + expect(result).toContain('

hello world

') + done() + }) + }) + it('should not warn for custom directives that do not have server-side implementation', done => { renderToString(new Vue({ directives: {