Skip to content

Commit

Permalink
feat(ssr): renderToString return Promise
Browse files Browse the repository at this point in the history
close #6160
  • Loading branch information
yyx990803 committed Oct 6, 2017
1 parent 2cba6d4 commit f881dd1
Show file tree
Hide file tree
Showing 5 changed files with 93 additions and 9 deletions.
11 changes: 10 additions & 1 deletion src/server/bundle-renderer/create-bundle-renderer.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/* @flow */

import { createPromiseCallback } from '../util'
import { createBundleRunner } from './create-bundle-runner'
import type { Renderer, RenderOptions } from '../create-renderer'
import { createSourceMapConsumers, rewriteErrorTrace } from './source-map-support'
Expand Down Expand Up @@ -85,11 +86,17 @@ export function createBundleRendererCreator (
)

return {
renderToString: (context?: Object, cb: (err: ?Error, res: ?string) => void) => {
renderToString: (context?: Object, cb: any) => {
if (typeof context === 'function') {
cb = context
context = {}
}

let promise
if (!cb) {
({ promise, cb } = createPromiseCallback())
}

run(context).catch(err => {
rewriteErrorTrace(err, maps)
cb(err)
Expand All @@ -101,6 +108,8 @@ export function createBundleRendererCreator (
})
}
})

return promise
},

renderToStream: (context?: Object) => {
Expand Down
24 changes: 17 additions & 7 deletions src/server/create-renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@
import RenderStream from './render-stream'
import { createWriteFunction } from './write'
import { createRenderFunction } from './render'
import { createPromiseCallback } from './util'
import TemplateRenderer from './template-renderer/index'
import type { ClientManifest } from './template-renderer/index'

export type Renderer = {
renderToString: (component: Component, context: any, cb: any) => void;
renderToString: (component: Component, context: any, cb: any) => ?Promise<string>;
renderToStream: (component: Component, context?: Object) => stream$Readable;
};

Expand Down Expand Up @@ -52,30 +53,39 @@ export function createRenderer ({
renderToString (
component: Component,
context: any,
done: any
): void {
cb: any
): ?Promise<string> {
if (typeof context === 'function') {
done = context
cb = context
context = {}
}
if (context) {
templateRenderer.bindRenderFns(context)
}

// no callback, return Promise
let promise
if (!cb) {
({ promise, cb } = createPromiseCallback())
}

let result = ''
const write = createWriteFunction(text => {
result += text
return false
}, done)
}, cb)
try {
render(component, write, context, () => {
if (template) {
result = templateRenderer.renderSync(result, context)
}
done(null, result)
cb(null, result)
})
} catch (e) {
done(e)
cb(e)
}

return promise
},

renderToStream (
Expand Down
13 changes: 13 additions & 0 deletions src/server/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,16 @@
export const isJS = (file: string): boolean => /\.js(\?[^.]+)?$/.test(file)

export const isCSS = (file: string): boolean => /\.css(\?[^.]+)?$/.test(file)

export function createPromiseCallback () {
let resolve, reject
const promise: Promise<string> = new Promise((_resolve, _reject) => {
resolve = _resolve
reject = _reject
})
const cb = (err: Error, res?: string) => {
if (err) return reject(err)
resolve(res || '')
}
return { promise, cb }
}
31 changes: 30 additions & 1 deletion test/ssr/ssr-bundle-render.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ function createAssertions (runInNewContext) {
})

it('renderToStream catch Promise rejection', done => {
createRenderer('error.js', { runInNewContext }, renderer => {
createRenderer('promise-rejection.js', { runInNewContext }, renderer => {
const stream = renderer.renderToStream()
stream.on('error', err => {
expect(err.message).toBe('foo')
Expand Down Expand Up @@ -277,4 +277,33 @@ function createAssertions (runInNewContext) {
})
})
})

it('renderToString return Promise', done => {
createRenderer('app.js', { runInNewContext }, renderer => {
const context = { url: '/test' }
renderer.renderToString(context).then(res => {
expect(res).toBe('<div data-server-rendered="true">/test</div>')
expect(context.msg).toBe('hello')
done()
})
})
})

it('renderToString return Promise (error)', done => {
createRenderer('error.js', { runInNewContext }, renderer => {
renderer.renderToString().catch(err => {
expect(err.message).toBe('foo')
done()
})
})
})

it('renderToString return Promise (Promise rejection)', done => {
createRenderer('promise-rejection.js', { runInNewContext }, renderer => {
renderer.renderToString().catch(err => {
expect(err.message).toBe('foo')
done()
})
})
})
}
23 changes: 23 additions & 0 deletions test/ssr/ssr-string.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -957,6 +957,29 @@ describe('SSR: renderToString', () => {
done()
})
})

it('return Promise', done => {
renderToString(new Vue({
template: `<div>{{ foo }}</div>`,
data: { foo: 'bar' }
})).then(res => {
expect(res).toBe(`<div data-server-rendered="true">bar</div>`)
done()
})
})

it('should Promise (error)', done => {
Vue.config.silent = true
renderToString(new Vue({
render () {
throw new Error('foobar')
}
})).catch(err => {
expect(err.toString()).toContain(`foobar`)
Vue.config.silent = false
done()
})
})
})

function renderVmWithOptions (options, cb) {
Expand Down

0 comments on commit f881dd1

Please sign in to comment.