Skip to content

Commit 971f42b

Browse files
yyx990803hefeng
authored and
hefeng
committed
feat(ssr): renderToString return Promise
close vuejs#6160
1 parent e166c34 commit 971f42b

File tree

5 files changed

+93
-9
lines changed

5 files changed

+93
-9
lines changed

src/server/bundle-renderer/create-bundle-renderer.js

+10-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/* @flow */
22

3+
import { createPromiseCallback } from '../util'
34
import { createBundleRunner } from './create-bundle-runner'
45
import type { Renderer, RenderOptions } from '../create-renderer'
56
import { createSourceMapConsumers, rewriteErrorTrace } from './source-map-support'
@@ -85,11 +86,17 @@ export function createBundleRendererCreator (
8586
)
8687

8788
return {
88-
renderToString: (context?: Object, cb: (err: ?Error, res: ?string) => void) => {
89+
renderToString: (context?: Object, cb: any) => {
8990
if (typeof context === 'function') {
9091
cb = context
9192
context = {}
9293
}
94+
95+
let promise
96+
if (!cb) {
97+
({ promise, cb } = createPromiseCallback())
98+
}
99+
93100
run(context).catch(err => {
94101
rewriteErrorTrace(err, maps)
95102
cb(err)
@@ -101,6 +108,8 @@ export function createBundleRendererCreator (
101108
})
102109
}
103110
})
111+
112+
return promise
104113
},
105114

106115
renderToStream: (context?: Object) => {

src/server/create-renderer.js

+17-7
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,12 @@
33
import RenderStream from './render-stream'
44
import { createWriteFunction } from './write'
55
import { createRenderFunction } from './render'
6+
import { createPromiseCallback } from './util'
67
import TemplateRenderer from './template-renderer/index'
78
import type { ClientManifest } from './template-renderer/index'
89

910
export type Renderer = {
10-
renderToString: (component: Component, context: any, cb: any) => void;
11+
renderToString: (component: Component, context: any, cb: any) => ?Promise<string>;
1112
renderToStream: (component: Component, context?: Object) => stream$Readable;
1213
};
1314

@@ -52,30 +53,39 @@ export function createRenderer ({
5253
renderToString (
5354
component: Component,
5455
context: any,
55-
done: any
56-
): void {
56+
cb: any
57+
): ?Promise<string> {
5758
if (typeof context === 'function') {
58-
done = context
59+
cb = context
5960
context = {}
6061
}
6162
if (context) {
6263
templateRenderer.bindRenderFns(context)
6364
}
65+
66+
// no callback, return Promise
67+
let promise
68+
if (!cb) {
69+
({ promise, cb } = createPromiseCallback())
70+
}
71+
6472
let result = ''
6573
const write = createWriteFunction(text => {
6674
result += text
6775
return false
68-
}, done)
76+
}, cb)
6977
try {
7078
render(component, write, context, () => {
7179
if (template) {
7280
result = templateRenderer.renderSync(result, context)
7381
}
74-
done(null, result)
82+
cb(null, result)
7583
})
7684
} catch (e) {
77-
done(e)
85+
cb(e)
7886
}
87+
88+
return promise
7989
},
8090

8191
renderToStream (

src/server/util.js

+13
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,16 @@
33
export const isJS = (file: string): boolean => /\.js(\?[^.]+)?$/.test(file)
44

55
export const isCSS = (file: string): boolean => /\.css(\?[^.]+)?$/.test(file)
6+
7+
export function createPromiseCallback () {
8+
let resolve, reject
9+
const promise: Promise<string> = new Promise((_resolve, _reject) => {
10+
resolve = _resolve
11+
reject = _reject
12+
})
13+
const cb = (err: Error, res?: string) => {
14+
if (err) return reject(err)
15+
resolve(res || '')
16+
}
17+
return { promise, cb }
18+
}

test/ssr/ssr-bundle-render.spec.js

+30-1
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ function createAssertions (runInNewContext) {
9595
})
9696

9797
it('renderToStream catch Promise rejection', done => {
98-
createRenderer('error.js', { runInNewContext }, renderer => {
98+
createRenderer('promise-rejection.js', { runInNewContext }, renderer => {
9999
const stream = renderer.renderToStream()
100100
stream.on('error', err => {
101101
expect(err.message).toBe('foo')
@@ -277,4 +277,33 @@ function createAssertions (runInNewContext) {
277277
})
278278
})
279279
})
280+
281+
it('renderToString return Promise', done => {
282+
createRenderer('app.js', { runInNewContext }, renderer => {
283+
const context = { url: '/test' }
284+
renderer.renderToString(context).then(res => {
285+
expect(res).toBe('<div data-server-rendered="true">/test</div>')
286+
expect(context.msg).toBe('hello')
287+
done()
288+
})
289+
})
290+
})
291+
292+
it('renderToString return Promise (error)', done => {
293+
createRenderer('error.js', { runInNewContext }, renderer => {
294+
renderer.renderToString().catch(err => {
295+
expect(err.message).toBe('foo')
296+
done()
297+
})
298+
})
299+
})
300+
301+
it('renderToString return Promise (Promise rejection)', done => {
302+
createRenderer('promise-rejection.js', { runInNewContext }, renderer => {
303+
renderer.renderToString().catch(err => {
304+
expect(err.message).toBe('foo')
305+
done()
306+
})
307+
})
308+
})
280309
}

test/ssr/ssr-string.spec.js

+23
Original file line numberDiff line numberDiff line change
@@ -957,6 +957,29 @@ describe('SSR: renderToString', () => {
957957
done()
958958
})
959959
})
960+
961+
it('return Promise', done => {
962+
renderToString(new Vue({
963+
template: `<div>{{ foo }}</div>`,
964+
data: { foo: 'bar' }
965+
})).then(res => {
966+
expect(res).toBe(`<div data-server-rendered="true">bar</div>`)
967+
done()
968+
})
969+
})
970+
971+
it('should Promise (error)', done => {
972+
Vue.config.silent = true
973+
renderToString(new Vue({
974+
render () {
975+
throw new Error('foobar')
976+
}
977+
})).catch(err => {
978+
expect(err.toString()).toContain(`foobar`)
979+
Vue.config.silent = false
980+
done()
981+
})
982+
})
960983
})
961984

962985
function renderVmWithOptions (options, cb) {

0 commit comments

Comments
 (0)