Browse Source

annotate ssr code

dev
Evan You 9 years ago
parent
commit
6d712753d8
  1. 1
      .flowconfig
  2. 10
      flow/declarations.js
  3. 47
      src/server/create-renderer.js
  4. 21
      src/server/render-stream.js
  5. 27
      src/server/render.js

1
.flowconfig

@ -8,6 +8,7 @@
[include] [include]
[libs] [libs]
flow
[options] [options]
module.name_mapper='^compiler/\(.*\)$' -> '<PROJECT_ROOT>/src/compiler/\1' module.name_mapper='^compiler/\(.*\)$' -> '<PROJECT_ROOT>/src/compiler/\1'

10
flow/declarations.js

@ -0,0 +1,10 @@
declare class Vue {
_render: Function;
}
declare interface VNode {
tag: ?string;
text: ?string;
data: ?Object;
children: ?Array<VNode>;
}

47
src/server/create-renderer.js

@ -1,14 +1,23 @@
/* @flow */
import RenderStream from './render-stream' import RenderStream from './render-stream'
import { createRenderFunction } from './render' import { createRenderFunction } from './render'
import { warn } from 'core/util/debug' import { warn } from 'core/util/debug'
export const MAX_STACK_DEPTH = 1000 export const MAX_STACK_DEPTH = 10
export function createRenderer ({ export function createRenderer ({
modules = [], modules = [],
directives = {}, directives = {},
isUnaryTag = (() => false) isUnaryTag = (() => false)
} = {}) { }: {
modules: Array<Function>,
directives: Object,
isUnaryTag: Function
} = {}): {
renderToString: Function,
renderToStream: Function
} {
if (process.env.VUE_ENV !== 'server') { if (process.env.VUE_ENV !== 'server') {
warn( warn(
'You are using createRenderer without setting VUE_ENV enviroment variable to "server". ' + 'You are using createRenderer without setting VUE_ENV enviroment variable to "server". ' +
@ -17,35 +26,35 @@ export function createRenderer ({
) )
} }
const render = createRenderFunction(modules, directives, isUnaryTag) const render = createRenderFunction(modules, directives, isUnaryTag)
return { return {
renderToString (component, done) { renderToString (component: Vue, done: Function): void {
let result = '' let result = ''
let stackDepth = 0 let stackDepth = 0
const write = (str, next) => { const write = (str: string, next: Function) => {
result += str result += str
if (next) { if (stackDepth >= MAX_STACK_DEPTH) {
if (stackDepth >= MAX_STACK_DEPTH) { process.nextTick(() => {
process.nextTick(() => { try { next() } catch (e) {
try { next() } catch (e) { done(e)
done(e) }
} })
})
} else {
stackDepth++
next()
stackDepth--
}
} else { } else {
done(null, result) stackDepth++
next()
stackDepth--
} }
} }
try { try {
render(component, write) render(component, write, () => {
done(null, result)
})
} catch (e) { } catch (e) {
done(e) done(e)
} }
}, },
renderToStream (component) {
renderToStream (component: Vue): RenderStream {
return new RenderStream((write, done) => { return new RenderStream((write, done) => {
render(component, write, done) render(component, write, done)
}) })

21
src/server/render-stream.js

@ -1,3 +1,5 @@
/* @flow */
import stream from 'stream' import stream from 'stream'
import { MAX_STACK_DEPTH } from './create-renderer' import { MAX_STACK_DEPTH } from './create-renderer'
@ -7,13 +9,23 @@ import { MAX_STACK_DEPTH } from './create-renderer'
* Modified by Evan You (@yyx990803) * Modified by Evan You (@yyx990803)
*/ */
export default class RenderStream extends stream.Readable { export default class RenderStream extends stream.Readable {
constructor (render) { buffer: string;
render: Function;
expectedSize: number;
stackDepth: number;
write: Function;
next: Function;
end: Function;
done: boolean;
constructor (render: Function) {
super() super()
this.buffer = '' this.buffer = ''
this.render = render this.render = render
this.expectedSize = 0 this.expectedSize = 0
this.stackDepth = 0
this.write = (text, next) => { this.write = (text: string, next: Function) => {
const n = this.expectedSize const n = this.expectedSize
this.buffer += text this.buffer += text
if (this.buffer.length >= n) { if (this.buffer.length >= n) {
@ -43,7 +55,7 @@ export default class RenderStream extends stream.Readable {
} }
} }
pushBySize (n) { pushBySize (n: number) {
const bufferToPush = this.buffer.substring(0, n) const bufferToPush = this.buffer.substring(0, n)
this.buffer = this.buffer.substring(n) this.buffer = this.buffer.substring(n)
this.push(bufferToPush) this.push(bufferToPush)
@ -65,7 +77,7 @@ export default class RenderStream extends stream.Readable {
} }
} }
_read (n) { _read (n: number) {
this.expectedSize = n this.expectedSize = n
// it's possible that the last chunk added bumped the buffer up to > 2 * n, // it's possible that the last chunk added bumped the buffer up to > 2 * n,
// which means we will need to go through multiple read calls to drain it // which means we will need to go through multiple read calls to drain it
@ -79,7 +91,6 @@ export default class RenderStream extends stream.Readable {
return return
} }
if (!this.next) { if (!this.next) {
this.stackDepth = 0
// start the rendering chain. // start the rendering chain.
this.tryRender() this.tryRender()
} else { } else {

27
src/server/render.js

@ -1,7 +1,13 @@
/* @flow */
import { createComponentInstanceForVnode } from 'core/vdom/create-component' import { createComponentInstanceForVnode } from 'core/vdom/create-component'
export function createRenderFunction (modules, directives, isUnaryTag) { export function createRenderFunction (
function renderNode (node, write, next, isRoot) { modules: Array<Function>,
directives: Object,
isUnaryTag: Function
) {
function renderNode (node: VNode, write: Function, next: Function, isRoot: boolean) {
if (node.componentOptions) { if (node.componentOptions) {
const child = createComponentInstanceForVnode(node) const child = createComponentInstanceForVnode(node)
renderNode(child._render(), write, next, isRoot) renderNode(child._render(), write, next, isRoot)
@ -14,7 +20,7 @@ export function createRenderFunction (modules, directives, isUnaryTag) {
} }
} }
function renderElement (el, write, next, isRoot) { function renderElement (el: VNode, write: Function, next: Function, isRoot: boolean) {
if (isRoot) { if (isRoot) {
if (!el.data) el.data = {} if (!el.data) el.data = {}
if (!el.data.attrs) el.data.attrs = {} if (!el.data.attrs) el.data.attrs = {}
@ -27,27 +33,28 @@ export function createRenderFunction (modules, directives, isUnaryTag) {
} else if (!el.children || !el.children.length) { } else if (!el.children || !el.children.length) {
write(startTag + endTag, next) write(startTag + endTag, next)
} else { } else {
const children: Array<VNode> = el.children || []
write(startTag, () => { write(startTag, () => {
const total = el.children.length const total = children.length
let rendered = 0 let rendered = 0
function renderChild (child) { function renderChild (child: VNode) {
renderNode(child, write, () => { renderNode(child, write, () => {
rendered++ rendered++
if (rendered < total) { if (rendered < total) {
renderChild(el.children[rendered]) renderChild(children[rendered])
} else { } else {
write(endTag, next) write(endTag, next)
} }
}) }, false)
} }
renderChild(el.children[0]) renderChild(children[0])
}) })
} }
} }
function renderStartingTag (node) { function renderStartingTag (node: VNode) {
let markup = `<${node.tag}` let markup = `<${node.tag}`
if (node.data) { if (node.data) {
// check directives // check directives
@ -73,7 +80,7 @@ export function createRenderFunction (modules, directives, isUnaryTag) {
return markup + '>' return markup + '>'
} }
return function render (component, write, done) { return function render (component: Vue, write: Function, done: Function) {
renderNode(component._render(), write, done, true) renderNode(component._render(), write, done, true)
} }
} }

Loading…
Cancel
Save