diff --git a/.flowconfig b/.flowconfig index 6ea1eeaa..97177440 100644 --- a/.flowconfig +++ b/.flowconfig @@ -8,6 +8,7 @@ [include] [libs] +flow [options] module.name_mapper='^compiler/\(.*\)$' -> '/src/compiler/\1' diff --git a/flow/declarations.js b/flow/declarations.js new file mode 100644 index 00000000..2784c298 --- /dev/null +++ b/flow/declarations.js @@ -0,0 +1,10 @@ +declare class Vue { + _render: Function; +} + +declare interface VNode { + tag: ?string; + text: ?string; + data: ?Object; + children: ?Array; +} diff --git a/src/server/create-renderer.js b/src/server/create-renderer.js index bdb0d5ff..e750d048 100644 --- a/src/server/create-renderer.js +++ b/src/server/create-renderer.js @@ -1,14 +1,23 @@ +/* @flow */ + import RenderStream from './render-stream' import { createRenderFunction } from './render' import { warn } from 'core/util/debug' -export const MAX_STACK_DEPTH = 1000 +export const MAX_STACK_DEPTH = 10 export function createRenderer ({ modules = [], directives = {}, isUnaryTag = (() => false) -} = {}) { +}: { + modules: Array, + directives: Object, + isUnaryTag: Function +} = {}): { + renderToString: Function, + renderToStream: Function +} { if (process.env.VUE_ENV !== 'server') { warn( '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) + return { - renderToString (component, done) { + renderToString (component: Vue, done: Function): void { let result = '' let stackDepth = 0 - const write = (str, next) => { + const write = (str: string, next: Function) => { result += str - if (next) { - if (stackDepth >= MAX_STACK_DEPTH) { - process.nextTick(() => { - try { next() } catch (e) { - done(e) - } - }) - } else { - stackDepth++ - next() - stackDepth-- - } + if (stackDepth >= MAX_STACK_DEPTH) { + process.nextTick(() => { + try { next() } catch (e) { + done(e) + } + }) } else { - done(null, result) + stackDepth++ + next() + stackDepth-- } } try { - render(component, write) + render(component, write, () => { + done(null, result) + }) } catch (e) { done(e) } }, - renderToStream (component) { + + renderToStream (component: Vue): RenderStream { return new RenderStream((write, done) => { render(component, write, done) }) diff --git a/src/server/render-stream.js b/src/server/render-stream.js index dab34c73..951b7a6f 100644 --- a/src/server/render-stream.js +++ b/src/server/render-stream.js @@ -1,3 +1,5 @@ +/* @flow */ + import stream from 'stream' import { MAX_STACK_DEPTH } from './create-renderer' @@ -7,13 +9,23 @@ import { MAX_STACK_DEPTH } from './create-renderer' * Modified by Evan You (@yyx990803) */ 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() this.buffer = '' this.render = render this.expectedSize = 0 + this.stackDepth = 0 - this.write = (text, next) => { + this.write = (text: string, next: Function) => { const n = this.expectedSize this.buffer += text 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) this.buffer = this.buffer.substring(n) this.push(bufferToPush) @@ -65,7 +77,7 @@ export default class RenderStream extends stream.Readable { } } - _read (n) { + _read (n: number) { this.expectedSize = 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 @@ -79,7 +91,6 @@ export default class RenderStream extends stream.Readable { return } if (!this.next) { - this.stackDepth = 0 // start the rendering chain. this.tryRender() } else { diff --git a/src/server/render.js b/src/server/render.js index 4bdcd287..dbe9646c 100644 --- a/src/server/render.js +++ b/src/server/render.js @@ -1,7 +1,13 @@ +/* @flow */ + import { createComponentInstanceForVnode } from 'core/vdom/create-component' -export function createRenderFunction (modules, directives, isUnaryTag) { - function renderNode (node, write, next, isRoot) { +export function createRenderFunction ( + modules: Array, + directives: Object, + isUnaryTag: Function +) { + function renderNode (node: VNode, write: Function, next: Function, isRoot: boolean) { if (node.componentOptions) { const child = createComponentInstanceForVnode(node) 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 (!el.data) el.data = {} if (!el.data.attrs) el.data.attrs = {} @@ -27,27 +33,28 @@ export function createRenderFunction (modules, directives, isUnaryTag) { } else if (!el.children || !el.children.length) { write(startTag + endTag, next) } else { + const children: Array = el.children || [] write(startTag, () => { - const total = el.children.length + const total = children.length let rendered = 0 - function renderChild (child) { + function renderChild (child: VNode) { renderNode(child, write, () => { rendered++ if (rendered < total) { - renderChild(el.children[rendered]) + renderChild(children[rendered]) } else { write(endTag, next) } - }) + }, false) } - renderChild(el.children[0]) + renderChild(children[0]) }) } } - function renderStartingTag (node) { + function renderStartingTag (node: VNode) { let markup = `<${node.tag}` if (node.data) { // check directives @@ -73,7 +80,7 @@ export function createRenderFunction (modules, directives, isUnaryTag) { return markup + '>' } - return function render (component, write, done) { + return function render (component: Vue, write: Function, done: Function) { renderNode(component._render(), write, done, true) } }