Explorar el Código

add server-rendered mark for ssr output

Evan You hace 10 años
padre
commit
38540b07e4

+ 11 - 4
src/platforms/web/server/modules/attrs.js

@@ -1,12 +1,16 @@
-import { isBooleanAttr, isEnumeratedAttr } from 'web/util/index'
+import { isBooleanAttr, isEnumeratedAttr, propsToAttrMap } from 'web/util/index'
 
 
 export default function renderAttrs (node) {
 export default function renderAttrs (node) {
-  if (node.data.attrs || node.data.staticAttrs) {
-    return serialize(node.data.staticAttrs) + serialize(node.data.attrs)
+  if (node.data.attrs || node.data.props || node.data.staticAttrs) {
+    return (
+      serialize(node.data.staticAttrs) +
+      serialize(node.data.attrs) +
+      serialize(node.data.props, true)
+    )
   }
   }
 }
 }
 
 
-function serialize (attrs) {
+function serialize (attrs, asProps) {
   let res = ''
   let res = ''
   if (!attrs) {
   if (!attrs) {
     return res
     return res
@@ -16,6 +20,9 @@ function serialize (attrs) {
       // leave it to the style module
       // leave it to the style module
       continue
       continue
     }
     }
+    if (asProps) {
+      key = propsToAttrMap[key] || key.toLowerCase()
+    }
     if (attrs[key] != null) {
     if (attrs[key] != null) {
       if (isBooleanAttr(key)) {
       if (isBooleanAttr(key)) {
         res += ` ${key}="${key}"`
         res += ` ${key}="${key}"`

+ 7 - 0
src/platforms/web/util/attrs.js

@@ -14,5 +14,12 @@ export const isBooleanAttr = makeMap(
   'truespeed,typemustmatch,visible'
   'truespeed,typemustmatch,visible'
 )
 )
 
 
+export const propsToAttrMap = {
+  acceptCharset: 'accept-charset',
+  className: 'class',
+  htmlFor: 'for',
+  httpEquiv: 'http-equiv',
+}
+
 export const xlinkNS = 'http://www.w3.org/1999/xlink'
 export const xlinkNS = 'http://www.w3.org/1999/xlink'
 export const isXlink = name => name.charAt(5) === ':' && name.slice(0, 5) === 'xlink'
 export const isXlink = name => name.charAt(5) === ':' && name.slice(0, 5) === 'xlink'

+ 12 - 7
src/server/create-streaming-renderer.js

@@ -2,25 +2,30 @@ import RenderStream from './render-stream'
 import { renderStartingTag } from './render-starting-tag'
 import { renderStartingTag } from './render-starting-tag'
 
 
 export function createStreamingRenderer (modules, directives, isUnaryTag) {
 export function createStreamingRenderer (modules, directives, isUnaryTag) {
-  function renderComponent (component, write, next) {
+  function renderComponent (component, write, next, isRoot) {
     component.$mount()
     component.$mount()
-    renderNode(component._vnode, write, next)
+    renderNode(component._vnode, write, next, isRoot)
   }
   }
 
 
-  function renderNode (node, write, next) {
+  function renderNode (node, write, next, isRoot) {
     if (node.componentOptions) {
     if (node.componentOptions) {
       node.data.hook.init(node)
       node.data.hook.init(node)
-      renderComponent(node.child, write, next)
+      renderComponent(node.child, write, next, isRoot)
     } else {
     } else {
       if (node.tag) {
       if (node.tag) {
-        renderElement(node, write, next)
+        renderElement(node, write, next, isRoot)
       } else {
       } else {
         write(node.text, next)
         write(node.text, next)
       }
       }
     }
     }
   }
   }
 
 
-  function renderElement (el, write, next) {
+  function renderElement (el, write, next, isRoot) {
+    if (isRoot) {
+      if (!el.data) el.data = {}
+      if (!el.data.attrs) el.data.attrs = {}
+      el.data.attrs['server-rendered'] = true
+    }
     const startTag = renderStartingTag(el, modules, directives)
     const startTag = renderStartingTag(el, modules, directives)
     const endTag = `</${el.tag}>`
     const endTag = `</${el.tag}>`
     if (isUnaryTag(el.tag)) {
     if (isUnaryTag(el.tag)) {
@@ -50,7 +55,7 @@ export function createStreamingRenderer (modules, directives, isUnaryTag) {
 
 
   return function renderToStream (component) {
   return function renderToStream (component) {
     return new RenderStream((write, done) => {
     return new RenderStream((write, done) => {
-      renderComponent(component, write, done)
+      renderComponent(component, write, done, true)
     })
     })
   }
   }
 }
 }

+ 22 - 11
src/server/create-sync-renderer.js

@@ -1,33 +1,44 @@
 import { renderStartingTag } from './render-starting-tag'
 import { renderStartingTag } from './render-starting-tag'
 
 
 export function createSyncRenderer (modules, directives, isUnaryTag) {
 export function createSyncRenderer (modules, directives, isUnaryTag) {
-  function renderComponent (component) {
+  function renderComponent (component, isRoot) {
     component.$mount()
     component.$mount()
-    return renderNode(component._vnode)
+    return renderNode(component._vnode, isRoot)
   }
   }
 
 
-  function renderNode (node) {
+  function renderNode (node, isRoot) {
     if (node.componentOptions) {
     if (node.componentOptions) {
       node.data.hook.init(node)
       node.data.hook.init(node)
-      return renderComponent(node.child)
+      return renderComponent(node.child, isRoot)
     } else {
     } else {
       return node.tag
       return node.tag
-        ? renderElement(node)
+        ? renderElement(node, isRoot)
         : node.text
         : node.text
     }
     }
   }
   }
 
 
-  function renderElement (el) {
+  function renderElement (el, isRoot) {
+    if (isRoot) {
+      if (!el.data) el.data = {}
+      if (!el.data.attrs) el.data.attrs = {}
+      el.data.attrs['server-rendered'] = true
+    }
     const startTag = renderStartingTag(el, modules, directives)
     const startTag = renderStartingTag(el, modules, directives)
+    const endTag = `</${el.tag}>`
     if (isUnaryTag(el.tag)) {
     if (isUnaryTag(el.tag)) {
       return startTag
       return startTag
+    } else if (!el.children || !el.children.length) {
+      return startTag + endTag
     } else {
     } else {
-      const children = el.children
-        ? el.children.map(renderNode).join('')
-        : ''
-      return startTag + children + `</${el.tag}>`
+      let children = ''
+      for (let i = 0; i < el.children.length; i++) {
+        children += renderNode(el.children[i])
+      }
+      return startTag + children + endTag
     }
     }
   }
   }
 
 
-  return renderComponent
+  return function renderToString (component) {
+    return renderComponent(component, true)
+  }
 }
 }

+ 10 - 1
test/ssr/ssr.stream.spec.js

@@ -10,6 +10,7 @@ describe('SSR: renderToStream', () => {
           <p class="hi">yoyo</p>
           <p class="hi">yoyo</p>
           <div id="ho" :class="{ red: isRed }"></div>
           <div id="ho" :class="{ red: isRed }"></div>
           <span>{{ test }}</span>
           <span>{{ test }}</span>
+          <input :value="test">
           <test></test>
           <test></test>
         </div>
         </div>
       `,
       `,
@@ -31,7 +32,15 @@ describe('SSR: renderToStream', () => {
       res += chunk
       res += chunk
     })
     })
     stream.on('end', () => {
     stream.on('end', () => {
-      expect(res).toContain('<div><p class="hi">yoyo</p><div id="ho" class="red"></div><span>hi</span><div class="a">hahahaha</div></div>')
+      expect(res).toContain(
+        '<div server-rendered="true">' +
+          '<p class="hi">yoyo</p>' +
+          '<div id="ho" class="red"></div>' +
+          '<span>hi</span>' +
+          '<input value="hi">' +
+          '<div class="a">hahahaha</div>' +
+        '</div>'
+      )
       done()
       done()
     })
     })
   })
   })

+ 18 - 9
test/ssr/ssr.sync.spec.js

@@ -6,13 +6,13 @@ describe('SSR: renderToString', () => {
   it('static attributes', () => {
   it('static attributes', () => {
     expect(renderVmWithOptions({
     expect(renderVmWithOptions({
       template: '<div id="foo" bar="123"></div>'
       template: '<div id="foo" bar="123"></div>'
-    })).toContain('<div id="foo" bar="123"></div>')
+    })).toContain('<div id="foo" bar="123" server-rendered="true"></div>')
   })
   })
 
 
   it('unary tags', () => {
   it('unary tags', () => {
     expect(renderVmWithOptions({
     expect(renderVmWithOptions({
       template: '<input value="123">'
       template: '<input value="123">'
-    })).toContain('<input value="123">')
+    })).toContain('<input value="123" server-rendered="true">')
   })
   })
 
 
   it('dynamic attributes', () => {
   it('dynamic attributes', () => {
@@ -22,13 +22,13 @@ describe('SSR: renderToString', () => {
         foo: 'hi',
         foo: 'hi',
         baz: 123
         baz: 123
       }
       }
-    })).toContain('<div qux="quux" id="hi" bar="123"></div>')
+    })).toContain('<div qux="quux" id="hi" bar="123" server-rendered="true"></div>')
   })
   })
 
 
   it('static class', () => {
   it('static class', () => {
     expect(renderVmWithOptions({
     expect(renderVmWithOptions({
       template: '<div class="foo bar"></div>'
       template: '<div class="foo bar"></div>'
-    })).toContain('<div class="foo bar"></div>')
+    })).toContain('<div server-rendered="true" class="foo bar"></div>')
   })
   })
 
 
   it('dynamic class', () => {
   it('dynamic class', () => {
@@ -39,7 +39,7 @@ describe('SSR: renderToString', () => {
         hasQux: true,
         hasQux: true,
         hasQuux: false
         hasQuux: false
       }
       }
-    })).toContain('<div class="foo bar baz qux"></div>')
+    })).toContain('<div server-rendered="true" class="foo bar baz qux"></div>')
   })
   })
 
 
   it('dynamic style', () => {
   it('dynamic style', () => {
@@ -49,7 +49,7 @@ describe('SSR: renderToString', () => {
         fontSize: 14,
         fontSize: 14,
         color: 'red'
         color: 'red'
       }
       }
-    })).toContain('<div style="font-size:14px;color:red;background-color:black"></div>')
+    })).toContain('<div server-rendered="true" style="font-size:14px;color:red;background-color:black"></div>')
   })
   })
 
 
   it('text interpolation', () => {
   it('text interpolation', () => {
@@ -59,7 +59,7 @@ describe('SSR: renderToString', () => {
         foo: 'server',
         foo: 'server',
         bar: 'rendering'
         bar: 'rendering'
       }
       }
-    })).toContain('<div>server side rendering</div>')
+    })).toContain('<div server-rendered="true">server side rendering</div>')
   })
   })
 
 
   it('child component (hoc)', () => {
   it('child component (hoc)', () => {
@@ -84,7 +84,7 @@ describe('SSR: renderToString', () => {
           }
           }
         }
         }
       }
       }
-    })).toContain('<div class="foo bar">hello bar</div>')
+    })).toContain('<div server-rendered="true" class="foo bar">hello bar</div>')
   })
   })
 
 
   it('everything together', () => {
   it('everything together', () => {
@@ -94,6 +94,7 @@ describe('SSR: renderToString', () => {
           <p class="hi">yoyo</p>
           <p class="hi">yoyo</p>
           <div id="ho" :class="{ red: isRed }"></div>
           <div id="ho" :class="{ red: isRed }"></div>
           <span>{{ test }}</span>
           <span>{{ test }}</span>
+          <input :value="test">
           <test></test>
           <test></test>
         </div>
         </div>
       `,
       `,
@@ -108,7 +109,15 @@ describe('SSR: renderToString', () => {
           }
           }
         }
         }
       }
       }
-    })).toContain('<div><p class="hi">yoyo</p><div id="ho" class="red"></div><span>hi</span><div class="a">hahahaha</div></div>')
+    })).toContain(
+      '<div server-rendered="true">' +
+        '<p class="hi">yoyo</p>' +
+        '<div id="ho" class="red"></div>' +
+        '<span>hi</span>' +
+        '<input value="hi">' +
+        '<div class="a">hahahaha</div>' +
+      '</div>'
+    )
   })
   })
 })
 })