From 5eeb9de5e7607bb8d246c687e13a746bf9d1a404 Mon Sep 17 00:00:00 2001 From: Evan You Date: Fri, 14 Apr 2017 16:26:12 +0800 Subject: [PATCH] ssr: repeat all test cases for directMode --- .../bundle-renderer/create-bundle-runner.js | 39 ++++---- test/ssr/ssr-bundle-render.spec.js | 30 ++++--- test/ssr/ssr-template.spec.js | 89 ++++++++++--------- 3 files changed, 89 insertions(+), 69 deletions(-) diff --git a/src/server/bundle-renderer/create-bundle-runner.js b/src/server/bundle-renderer/create-bundle-runner.js index 2b4ad5d5..a55727ca 100644 --- a/src/server/bundle-renderer/create-bundle-runner.js +++ b/src/server/bundle-renderer/create-bundle-runner.js @@ -92,30 +92,33 @@ export function createBundleRunner (entry, files, basedir, direct) { // default mode: creates a fresh context and re-evaluate the bundle // on each render. Ensures entire application state is fresh for each // render, but incurs extra evaluation cost. - return (_context = {}) => new Promise((resolve, reject) => { - _context._registeredComponents = new Set() - const res = evaluate(entry, createContext(_context)) - resolve(typeof res === 'function' ? res(_context) : res) + return (userContext = {}) => new Promise(resolve => { + userContext._registeredComponents = new Set() + const res = evaluate(entry, createContext(userContext)) + resolve(typeof res === 'function' ? res(userContext) : res) }) } else { // direct mode: instead of re-evaluating the whole bundle on // each render, it simply calls the exported function. This avoids the // module evaluation costs but requires the source code to be structured // slightly differently. - const initialExposedContext = {} - const context = createContext(initialExposedContext) - const runner = evaluate(entry, context) - if (typeof runner !== 'function') { - throw new Error('direct mode expects bundle export to be a function.') - } - return (_context = {}) => { - context.__VUE_SSR_CONTEXT__ = _context - _context._registeredComponents = new Set() - // vue-style-loader styles imported outside of component lifecycle hooks - if (initialExposedContext._styles) { - _context._styles = deepClone(initialExposedContext._styles) + const initialContext = {} + const sharedContext = createContext(initialContext) + let runner // lazy creation so that errors can be caught by user + return (userContext = {}) => new Promise(resolve => { + if (!runner) { + runner = evaluate(entry, sharedContext) + if (typeof runner !== 'function') { + throw new Error('direct mode expects bundle export to be a function.') + } } - return runner(_context) - } + sharedContext.__VUE_SSR_CONTEXT__ = userContext + userContext._registeredComponents = new Set() + // vue-style-loader styles imported outside of component lifecycle hooks + if (initialContext._styles) { + userContext._styles = deepClone(initialContext._styles) + } + resolve(runner(userContext)) + }) } } diff --git a/test/ssr/ssr-bundle-render.spec.js b/test/ssr/ssr-bundle-render.spec.js index a888142f..a63ad821 100644 --- a/test/ssr/ssr-bundle-render.spec.js +++ b/test/ssr/ssr-bundle-render.spec.js @@ -33,8 +33,13 @@ export function createRenderer (file, options, cb) { } describe('SSR: bundle renderer', () => { + createAssertions(true) + createAssertions(false) +}) + +function createAssertions (directMode) { it('renderToString', done => { - createRenderer('app.js', renderer => { + createRenderer('app.js', { directMode }, renderer => { const context = { url: '/test' } renderer.renderToString(context, (err, res) => { expect(err).toBeNull() @@ -46,7 +51,7 @@ describe('SSR: bundle renderer', () => { }) it('renderToStream', done => { - createRenderer('app.js', renderer => { + createRenderer('app.js', { directMode }, renderer => { const context = { url: '/test' } const stream = renderer.renderToStream(context) let res = '' @@ -62,7 +67,7 @@ describe('SSR: bundle renderer', () => { }) it('renderToString catch error', done => { - createRenderer('error.js', renderer => { + createRenderer('error.js', { directMode }, renderer => { renderer.renderToString(err => { expect(err.message).toBe('foo') done() @@ -71,7 +76,7 @@ describe('SSR: bundle renderer', () => { }) it('renderToStream catch error', done => { - createRenderer('error.js', renderer => { + createRenderer('error.js', { directMode }, renderer => { const stream = renderer.renderToStream() stream.on('error', err => { expect(err.message).toBe('foo') @@ -85,6 +90,7 @@ describe('SSR: bundle renderer', () => { const get = jasmine.createSpy('get') const set = jasmine.createSpy('set') const options = { + directMode, cache: { // async get: (key, cb) => { @@ -127,6 +133,7 @@ describe('SSR: bundle renderer', () => { const get = jasmine.createSpy('get') const set = jasmine.createSpy('set') const options = { + directMode, cache: { // async has: (key, cb) => { @@ -172,7 +179,10 @@ describe('SSR: bundle renderer', () => { const cache = LRU({ maxAge: Infinity }) spyOn(cache, 'get').and.callThrough() spyOn(cache, 'set').and.callThrough() - const options = { cache } + const options = { + cache, + directMode + } createRenderer('nested-cache.js', options, renderer => { const expected = '
/test
' const key = 'app::1' @@ -203,7 +213,7 @@ describe('SSR: bundle renderer', () => { }) it('renderToString (bundle format with code split)', done => { - createRenderer('split.js', { asBundle: true }, renderer => { + createRenderer('split.js', { directMode, asBundle: true }, renderer => { const context = { url: '/test' } renderer.renderToString(context, (err, res) => { expect(err).toBeNull() @@ -214,7 +224,7 @@ describe('SSR: bundle renderer', () => { }) it('renderToStream (bundle format with code split)', done => { - createRenderer('split.js', { asBundle: true }, renderer => { + createRenderer('split.js', { directMode, asBundle: true }, renderer => { const context = { url: '/test' } const stream = renderer.renderToStream(context) let res = '' @@ -229,7 +239,7 @@ describe('SSR: bundle renderer', () => { }) it('renderToString catch error (bundle format with source map)', done => { - createRenderer('error.js', { asBundle: true }, renderer => { + createRenderer('error.js', { directMode, asBundle: true }, renderer => { renderer.renderToString(err => { expect(err.stack).toContain('test/ssr/fixtures/error.js:1:6') expect(err.message).toBe('foo') @@ -239,7 +249,7 @@ describe('SSR: bundle renderer', () => { }) it('renderToString catch error (bundle format with source map)', done => { - createRenderer('error.js', { asBundle: true }, renderer => { + createRenderer('error.js', { directMode, asBundle: true }, renderer => { const stream = renderer.renderToStream() stream.on('error', err => { expect(err.stack).toContain('test/ssr/fixtures/error.js:1:6') @@ -248,4 +258,4 @@ describe('SSR: bundle renderer', () => { }) }) }) -}) +} diff --git a/test/ssr/ssr-template.spec.js b/test/ssr/ssr-template.spec.js index 5f233be4..d5670aa0 100644 --- a/test/ssr/ssr-template.spec.js +++ b/test/ssr/ssr-template.spec.js @@ -169,56 +169,63 @@ describe('SSR: template option', () => { `` + `` - it('bundleRenderer + renderToString + clientManifest', done => { - createRendererWithManifest('split.js', renderer => { - renderer.renderToString({}, (err, res) => { - expect(err).toBeNull() - expect(res).toContain(expectedHTMLWithManifest(false)) - done() + createClientManifestAssertions(true) + createClientManifestAssertions(false) + + function createClientManifestAssertions (directMode) { + it('bundleRenderer + renderToString + clientManifest', done => { + createRendererWithManifest('split.js', { directMode }, renderer => { + renderer.renderToString({}, (err, res) => { + expect(err).toBeNull() + expect(res).toContain(expectedHTMLWithManifest(false)) + done() + }) }) }) - }) - it('bundleRenderer + renderToStream + clientManifest + shouldPreload', done => { - createRendererWithManifest('split.js', { - shouldPreload: (file, type) => { - if (type === 'image' || type === 'script' || type === 'font') { - return true + it('bundleRenderer + renderToStream + clientManifest + shouldPreload', done => { + createRendererWithManifest('split.js', { + directMode, + shouldPreload: (file, type) => { + if (type === 'image' || type === 'script' || type === 'font') { + return true + } } - } - }, renderer => { - const stream = renderer.renderToStream({}) - let res = '' - stream.on('data', chunk => { - res += chunk.toString() - }) - stream.on('end', () => { - expect(res).toContain(expectedHTMLWithManifest(true)) - done() + }, renderer => { + const stream = renderer.renderToStream({}) + let res = '' + stream.on('data', chunk => { + res += chunk.toString() + }) + stream.on('end', () => { + expect(res).toContain(expectedHTMLWithManifest(true)) + done() + }) }) }) - }) - it('bundleRenderer + renderToString + clientManifest + no template', done => { - createRendererWithManifest('split.js', { - template: null - }, renderer => { - const context = {} - renderer.renderToString(context, (err, res) => { - expect(err).toBeNull() + it('bundleRenderer + renderToString + clientManifest + no template', done => { + createRendererWithManifest('split.js', { + directMode, + template: null + }, renderer => { + const context = {} + renderer.renderToString(context, (err, res) => { + expect(err).toBeNull() - const customOutput = - `${ - context.renderPreloadLinks() + - context.renderPrefetchLinks() - }${ - res + - context.renderScripts() - }` + const customOutput = + `${ + context.renderPreloadLinks() + + context.renderPrefetchLinks() + }${ + res + + context.renderScripts() + }` - expect(customOutput).toContain(expectedHTMLWithManifest(false)) - done() + expect(customOutput).toContain(expectedHTMLWithManifest(false)) + done() + }) }) }) - }) + } })