From 0ed753fddb704ae23a60ad29f25c9f89e051d878 Mon Sep 17 00:00:00 2001 From: Ronald Rogers Date: Mon, 11 Feb 2019 20:40:12 -0500 Subject: [PATCH 1/2] feat(ssr): add ability to cleanup after request close #9463 --- .../bundle-renderer/create-bundle-renderer.js | 21 +++++- test/ssr/fixtures/app-callback.js | 13 ++++ test/ssr/fixtures/split-callback.js | 27 ++++++++ test/ssr/ssr-bundle-render.spec.js | 66 +++++++++++++++++++ 4 files changed, 125 insertions(+), 2 deletions(-) create mode 100644 test/ssr/fixtures/app-callback.js create mode 100644 test/ssr/fixtures/split-callback.js diff --git a/src/server/bundle-renderer/create-bundle-renderer.js b/src/server/bundle-renderer/create-bundle-renderer.js index 05c60c35740..8e42a5ddc12 100644 --- a/src/server/bundle-renderer/create-bundle-renderer.js +++ b/src/server/bundle-renderer/create-bundle-renderer.js @@ -28,6 +28,10 @@ type RenderBundle = { modules?: { [filename: string]: Array }; }; +function getRenderArguments(app) { + return app && app._isVue ? { app, onComplete: null } : app +} + export function createBundleRendererCreator ( createRenderer: (options?: RenderOptions) => Renderer ) { @@ -100,12 +104,16 @@ export function createBundleRendererCreator ( run(context).catch(err => { rewriteErrorTrace(err, maps) cb(err) - }).then(app => { + }).then(args => { + const { app, onRequestComplete } = getRenderArguments(args) if (app) { renderer.renderToString(app, context, (err, res) => { rewriteErrorTrace(err, maps) + onRequestComplete && onRequestComplete() cb(err, res) }) + } else { + onRequestComplete && onRequestComplete() } }) @@ -121,7 +129,8 @@ export function createBundleRendererCreator ( process.nextTick(() => { res.emit('error', err) }) - }).then(app => { + }).then(args => { + const { app, onComplete } = getRenderArguments(args) if (app) { const renderStream = renderer.renderToStream(app, context) @@ -140,7 +149,15 @@ export function createBundleRendererCreator ( }) } + if (onComplete) { + renderStream.on('end', () => { + onComplete() + }) + } + renderStream.pipe(res) + } else { + onComplete && onComplete() } }) diff --git a/test/ssr/fixtures/app-callback.js b/test/ssr/fixtures/app-callback.js new file mode 100644 index 00000000000..337b338c878 --- /dev/null +++ b/test/ssr/fixtures/app-callback.js @@ -0,0 +1,13 @@ +import Vue from '../../../dist/vue.runtime.common.js' + +export default context => { + return new Promise(resolve => { + const app = new Vue({ + render (h) { + return h('div', context.url) + } + }) + const onComplete = () => { context.msg = 'hello' } + resolve({ app, onComplete }) + }) +} diff --git a/test/ssr/fixtures/split-callback.js b/test/ssr/fixtures/split-callback.js new file mode 100644 index 00000000000..b091eba77a2 --- /dev/null +++ b/test/ssr/fixtures/split-callback.js @@ -0,0 +1,27 @@ +import Vue from '../../../dist/vue.runtime.common.js' + +// async component! +const Foo = () => import('./async-foo') +const Bar = () => import('./async-bar') // eslint-disable-line + +export default context => { + return new Promise(resolve => { + const vm = new Vue({ + render (h) { + return h('div', [ + context.url, + h(Foo) + ]) + } + }) + + const onComplete = () => { context.msg = 'hello' } + + // simulate router.onReady + Foo().then(comp => { + // resolve now to make the render sync + Foo.resolved = Vue.extend(comp.default) + resolve({ app: vm, onComplete }) + }) + }) +} diff --git a/test/ssr/ssr-bundle-render.spec.js b/test/ssr/ssr-bundle-render.spec.js index ce7f8780a90..dfb2063f776 100644 --- a/test/ssr/ssr-bundle-render.spec.js +++ b/test/ssr/ssr-bundle-render.spec.js @@ -66,6 +66,33 @@ function createAssertions (runInNewContext) { }) }) + it('renderToString with callback', done => { + createRenderer('app-callback.js', { runInNewContext }, renderer => { + const context = { url: '/test' } + renderer.renderToString(context, (err, res) => { + expect(res).toBe('
/test
') + expect(context.msg).toBe('hello') + done() + }) + }) + }) + + it('renderToStream with callback', done => { + createRenderer('app-callback.js', { runInNewContext }, renderer => { + const context = { url: '/test' } + const stream = renderer.renderToStream(context) + let res = '' + stream.on('data', chunk => { + res += chunk.toString() + }) + stream.on('end', () => { + expect(res).toBe('
/test
') + expect(context.msg).toBe('hello') + done() + }) + }) + }) + it('renderToString catch error', done => { createRenderer('error.js', { runInNewContext }, renderer => { renderer.renderToString(err => { @@ -295,6 +322,34 @@ function createAssertions (runInNewContext) { }) }) + it('renderToString with callback (bundle format with code split)', done => { + createRenderer('split-callback.js', { runInNewContext, asBundle: true }, renderer => { + const context = { url: '/test' } + renderer.renderToString(context, (err, res) => { + expect(err).toBeNull() + expect(res).toBe('
/test
async test.woff2 test.png
') + expect(context.msg).toBe('hello') + done() + }) + }) + }) + + it('renderToStream with callback (bundle format with code split)', done => { + createRenderer('split-callback.js', { runInNewContext, asBundle: true }, renderer => { + const context = { url: '/test' } + const stream = renderer.renderToStream(context) + let res = '' + stream.on('data', chunk => { + res += chunk.toString() + }) + stream.on('end', () => { + expect(res).toBe('
/test
async test.woff2 test.png
') + expect(context.msg).toBe('hello') + done() + }) + }) + }) + it('renderToString catch error (bundle format with source map)', done => { createRenderer('error.js', { runInNewContext, asBundle: true }, renderer => { renderer.renderToString(err => { @@ -327,6 +382,17 @@ function createAssertions (runInNewContext) { }) }) + it('renderToString return Promise (callback)', done => { + createRenderer('app-callback.js', { runInNewContext }, renderer => { + const context = { url: '/test' } + renderer.renderToString(context).then(res => { + expect(res).toBe('
/test
') + expect(context.msg).toBe('hello') + done() + }) + }) + }) + it('renderToString return Promise (error)', done => { createRenderer('error.js', { runInNewContext }, renderer => { renderer.renderToString().catch(err => { From 0b9c5a0272e73f63c16dd66d050df04d70951a6a Mon Sep 17 00:00:00 2001 From: Ronald Rogers Date: Mon, 11 Feb 2019 21:58:38 -0500 Subject: [PATCH 2/2] feat(ssr): fix tests --- src/server/bundle-renderer/create-bundle-renderer.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/server/bundle-renderer/create-bundle-renderer.js b/src/server/bundle-renderer/create-bundle-renderer.js index 8e42a5ddc12..a23134a52bf 100644 --- a/src/server/bundle-renderer/create-bundle-renderer.js +++ b/src/server/bundle-renderer/create-bundle-renderer.js @@ -105,15 +105,15 @@ export function createBundleRendererCreator ( rewriteErrorTrace(err, maps) cb(err) }).then(args => { - const { app, onRequestComplete } = getRenderArguments(args) + const { app, onComplete } = getRenderArguments(args) if (app) { renderer.renderToString(app, context, (err, res) => { rewriteErrorTrace(err, maps) - onRequestComplete && onRequestComplete() + onComplete && onComplete() cb(err, res) }) } else { - onRequestComplete && onRequestComplete() + onComplete && onComplete() } })