Repository: vuejs/vue
Pull request: fix SSR v-show render.

<!-- PULL REQUEST TEMPLATE -->
<!-- (Update "[ ]" to "[x]" to check a box) -->

**What kind of change does this PR introduce?** (check at least one)

- [x] Bugfix
- [ ] Feature
- [ ] Code style update
- [ ] Refactor
- [ ] Build-related changes
- [ ] Other, please describe:

**Does this PR introduce a breaking change?** (check one)

- [ ] Yes
- [x] No

If yes, please describe the impact and migration path for existing applications:

**The PR fulfills these requirements:**

- [x] It's submitted to the `dev` branch for v2.x (or to a previous version branch), _not_ the `master` branch
- [ ] When resolving a specific issue, it's referenced in the PR's title (e.g. `fix #xxx[,#xxx]`, where "xxx" is the issue number)
- [x] All tests are passing: https://github.com/vuejs/vue/blob/dev/.github/CONTRIBUTING.md#development-setup
- [x] New/updated tests are included

If adding a **new feature**, the PR's description includes:
- [ ] A convincing reason for adding this feature (to avoid wasting your time, it's best to open a suggestion issue first and wait for approval before working on it)

**Other information:**

SSR `v-show` directive should be merged from parent to child component.

It could be reproduced via this [github repo](https://github.com/defcc/v-show-ssr-bug/). 

And the demo code is bellow:

```js
var Vue = require('vue/dist/vue.common.js')
var createRenderer = require('vue-server-renderer').createRenderer
var renderToString = createRenderer().renderToString

const vm = new Vue({
  template: `
    <foo v-show="false"></foo>
  `,
  components: {
    foo: {
      render: h => h('bar'),
      components: {
        bar: {
          render: h => h('div', 'inner')
        }
      }
    }

  }
})

renderToString(vm, (err, res) => {
  console.log(res)
})
```

The result is `<div server-rendered="true">inner</div>`, it should be `<div server-rendered="true" style="display:none;">inner</div>`





Changed files:
filename: src/server/render.js
patch: @@ -144,6 +144,22 @@ function hasAncestorData (node: VNode) {
   return parentNode && (parentNode.data || hasAncestorData(parentNode))
 }
 
+function getVShowDirectiveInfo (node: VNode): ?VNodeDirective {
+  let dir: VNodeDirective
+  let tmp
+
+  while (node) {
+    if (node.data && node.data.directives) {
+      tmp = node.data.directives.find(dir => dir.name === 'show')
+      if (tmp) {
+        dir = tmp
+      }
+    }
+    node = node.parent
+  }
+  return dir
+}
+
 function renderStartingTag (node: VNode, context) {
   let markup = `<${node.tag}`
   const { directives, modules } = context
@@ -158,14 +174,22 @@ function renderStartingTag (node: VNode, context) {
     const dirs = node.data.directives
     if (dirs) {
       for (let i = 0; i < dirs.length; i++) {
-        const dirRenderer = directives[dirs[i].name]
-        if (dirRenderer) {
+        const name = dirs[i].name
+        const dirRenderer = directives[name]
+        if (dirRenderer && name !== 'show') {
           // directives mutate the node's data
           // which then gets rendered by modules
           dirRenderer(node, dirs[i])
         }
       }
     }
+
+    // v-show directive needs to be merged from parent to child
+    const vshowDirectiveInfo = getVShowDirectiveInfo(node)
+    if (vshowDirectiveInfo) {
+      directives.show(node, vshowDirectiveInfo)
+    }
+
     // apply other modules
     for (let i = 0; i < modules.length; i++) {
       const res = modules[i](node)

filename: test/ssr/ssr-string.spec.js
patch: @@ -240,6 +240,75 @@ describe('SSR: renderToString', () => {
     })
   })
 
+  it('v-show directive render', done => {
+    renderVmWithOptions({
+      template: '<div v-show="false"><span>inner</span></div>'
+    }, res => {
+      expect(res).toContain(
+        '<div server-rendered="true" style="display:none;"><span>inner</span></div>'
+      )
+      done()
+    })
+  })
+
+  it('v-show directive not passed to child', done => {
+    renderVmWithOptions({
+      template: '<foo v-show="false"></foo>',
+      components: {
+        foo: {
+          template: '<div><span>inner</span></div>'
+        }
+      }
+    }, res => {
+      expect(res).toContain(
+        '<div server-rendered="true" style="display:none;"><span>inner</span></div>'
+      )
+      done()
+    })
+  })
+
+  it('v-show directive not passed to slot', done => {
+    renderVmWithOptions({
+      template: '<foo v-show="false"><span>inner</span></foo>',
+      components: {
+        foo: {
+          template: '<div><slot></slot></div>'
+        }
+      }
+    }, res => {
+      expect(res).toContain(
+        '<div server-rendered="true" style="display:none;"><span>inner</span></div>'
+      )
+      done()
+    })
+  })
+
+  it('v-show directive merging on components', done => {
+    renderVmWithOptions({
+      template: '<foo v-show="false"></foo>',
+      components: {
+        foo: {
+          render: h => h('bar', {
+            directives: [{
+              name: 'show',
+              value: true
+            }]
+          }),
+          components: {
+            bar: {
+              render: h => h('div', 'inner')
+            }
+          }
+        }
+      }
+    }, res => {
+      expect(res).toContain(
+        '<div server-rendered="true" style="display:none;">inner</div>'
+      )
+      done()
+    })
+  })
+
   it('text interpolation', done => {
     renderVmWithOptions({
       template: '<div>{{ foo }} side {{ bar }}</div>',