Skip to content

Commit 0ed753f

Browse files
feat(ssr): add ability to cleanup after request
close vuejs#9463
1 parent 8a80086 commit 0ed753f

File tree

4 files changed

+125
-2
lines changed

4 files changed

+125
-2
lines changed

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

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ type RenderBundle = {
2828
modules?: { [filename: string]: Array<string> };
2929
};
3030

31+
function getRenderArguments(app) {
32+
return app && app._isVue ? { app, onComplete: null } : app
33+
}
34+
3135
export function createBundleRendererCreator (
3236
createRenderer: (options?: RenderOptions) => Renderer
3337
) {
@@ -100,12 +104,16 @@ export function createBundleRendererCreator (
100104
run(context).catch(err => {
101105
rewriteErrorTrace(err, maps)
102106
cb(err)
103-
}).then(app => {
107+
}).then(args => {
108+
const { app, onRequestComplete } = getRenderArguments(args)
104109
if (app) {
105110
renderer.renderToString(app, context, (err, res) => {
106111
rewriteErrorTrace(err, maps)
112+
onRequestComplete && onRequestComplete()
107113
cb(err, res)
108114
})
115+
} else {
116+
onRequestComplete && onRequestComplete()
109117
}
110118
})
111119

@@ -121,7 +129,8 @@ export function createBundleRendererCreator (
121129
process.nextTick(() => {
122130
res.emit('error', err)
123131
})
124-
}).then(app => {
132+
}).then(args => {
133+
const { app, onComplete } = getRenderArguments(args)
125134
if (app) {
126135
const renderStream = renderer.renderToStream(app, context)
127136

@@ -140,7 +149,15 @@ export function createBundleRendererCreator (
140149
})
141150
}
142151

152+
if (onComplete) {
153+
renderStream.on('end', () => {
154+
onComplete()
155+
})
156+
}
157+
143158
renderStream.pipe(res)
159+
} else {
160+
onComplete && onComplete()
144161
}
145162
})
146163

test/ssr/fixtures/app-callback.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import Vue from '../../../dist/vue.runtime.common.js'
2+
3+
export default context => {
4+
return new Promise(resolve => {
5+
const app = new Vue({
6+
render (h) {
7+
return h('div', context.url)
8+
}
9+
})
10+
const onComplete = () => { context.msg = 'hello' }
11+
resolve({ app, onComplete })
12+
})
13+
}

test/ssr/fixtures/split-callback.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import Vue from '../../../dist/vue.runtime.common.js'
2+
3+
// async component!
4+
const Foo = () => import('./async-foo')
5+
const Bar = () => import('./async-bar') // eslint-disable-line
6+
7+
export default context => {
8+
return new Promise(resolve => {
9+
const vm = new Vue({
10+
render (h) {
11+
return h('div', [
12+
context.url,
13+
h(Foo)
14+
])
15+
}
16+
})
17+
18+
const onComplete = () => { context.msg = 'hello' }
19+
20+
// simulate router.onReady
21+
Foo().then(comp => {
22+
// resolve now to make the render sync
23+
Foo.resolved = Vue.extend(comp.default)
24+
resolve({ app: vm, onComplete })
25+
})
26+
})
27+
}

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

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,33 @@ function createAssertions (runInNewContext) {
6666
})
6767
})
6868

69+
it('renderToString with callback', done => {
70+
createRenderer('app-callback.js', { runInNewContext }, renderer => {
71+
const context = { url: '/test' }
72+
renderer.renderToString(context, (err, res) => {
73+
expect(res).toBe('<div data-server-rendered="true">/test</div>')
74+
expect(context.msg).toBe('hello')
75+
done()
76+
})
77+
})
78+
})
79+
80+
it('renderToStream with callback', done => {
81+
createRenderer('app-callback.js', { runInNewContext }, renderer => {
82+
const context = { url: '/test' }
83+
const stream = renderer.renderToStream(context)
84+
let res = ''
85+
stream.on('data', chunk => {
86+
res += chunk.toString()
87+
})
88+
stream.on('end', () => {
89+
expect(res).toBe('<div data-server-rendered="true">/test</div>')
90+
expect(context.msg).toBe('hello')
91+
done()
92+
})
93+
})
94+
})
95+
6996
it('renderToString catch error', done => {
7097
createRenderer('error.js', { runInNewContext }, renderer => {
7198
renderer.renderToString(err => {
@@ -295,6 +322,34 @@ function createAssertions (runInNewContext) {
295322
})
296323
})
297324

325+
it('renderToString with callback (bundle format with code split)', done => {
326+
createRenderer('split-callback.js', { runInNewContext, asBundle: true }, renderer => {
327+
const context = { url: '/test' }
328+
renderer.renderToString(context, (err, res) => {
329+
expect(err).toBeNull()
330+
expect(res).toBe('<div data-server-rendered="true">/test<div>async test.woff2 test.png</div></div>')
331+
expect(context.msg).toBe('hello')
332+
done()
333+
})
334+
})
335+
})
336+
337+
it('renderToStream with callback (bundle format with code split)', done => {
338+
createRenderer('split-callback.js', { runInNewContext, asBundle: true }, renderer => {
339+
const context = { url: '/test' }
340+
const stream = renderer.renderToStream(context)
341+
let res = ''
342+
stream.on('data', chunk => {
343+
res += chunk.toString()
344+
})
345+
stream.on('end', () => {
346+
expect(res).toBe('<div data-server-rendered="true">/test<div>async test.woff2 test.png</div></div>')
347+
expect(context.msg).toBe('hello')
348+
done()
349+
})
350+
})
351+
})
352+
298353
it('renderToString catch error (bundle format with source map)', done => {
299354
createRenderer('error.js', { runInNewContext, asBundle: true }, renderer => {
300355
renderer.renderToString(err => {
@@ -327,6 +382,17 @@ function createAssertions (runInNewContext) {
327382
})
328383
})
329384

385+
it('renderToString return Promise (callback)', done => {
386+
createRenderer('app-callback.js', { runInNewContext }, renderer => {
387+
const context = { url: '/test' }
388+
renderer.renderToString(context).then(res => {
389+
expect(res).toBe('<div data-server-rendered="true">/test</div>')
390+
expect(context.msg).toBe('hello')
391+
done()
392+
})
393+
})
394+
})
395+
330396
it('renderToString return Promise (error)', done => {
331397
createRenderer('error.js', { runInNewContext }, renderer => {
332398
renderer.renderToString().catch(err => {

0 commit comments

Comments
 (0)