| 
									
										
										
										
											2017-03-30 15:19:13 +08:00
										 |  |  | import webpack from 'webpack' | 
					
						
							| 
									
										
										
										
											2017-03-30 12:10:43 +08:00
										 |  |  | import Vue from '../../dist/vue.runtime.common.js' | 
					
						
							| 
									
										
										
										
											2017-03-30 15:19:13 +08:00
										 |  |  | import { compileWithWebpack } from './compile-with-webpack' | 
					
						
							| 
									
										
										
										
											2017-03-30 12:10:43 +08:00
										 |  |  | import { createRenderer } from '../../packages/vue-server-renderer' | 
					
						
							| 
									
										
										
										
											2017-04-16 21:43:50 +08:00
										 |  |  | import VueSSRClientPlugin from '../../packages/vue-server-renderer/client-plugin' | 
					
						
							| 
									
										
										
										
											2017-03-30 12:10:43 +08:00
										 |  |  | import { createRenderer as createBundleRenderer } from './ssr-bundle-render.spec.js' | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-30 15:19:13 +08:00
										 |  |  | const defaultTemplate = `<html><head></head><body><!--vue-ssr-outlet--></body></html>` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function generateClientManifest (file, cb) { | 
					
						
							|  |  |  |   compileWithWebpack(file, { | 
					
						
							|  |  |  |     output: { | 
					
						
							|  |  |  |       path: '/', | 
					
						
							|  |  |  |       filename: '[name].js' | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     plugins: [ | 
					
						
							|  |  |  |       new webpack.optimize.CommonsChunkPlugin({ | 
					
						
							|  |  |  |         name: 'manifest', | 
					
						
							|  |  |  |         minChunks: Infinity | 
					
						
							|  |  |  |       }), | 
					
						
							|  |  |  |       new VueSSRClientPlugin() | 
					
						
							|  |  |  |     ] | 
					
						
							|  |  |  |   }, fs => { | 
					
						
							|  |  |  |     cb(JSON.parse(fs.readFileSync('/vue-ssr-client-manifest.json', 'utf-8'))) | 
					
						
							|  |  |  |   }) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-02 15:38:26 +08:00
										 |  |  | function createRendererWithManifest (file, options, cb) { | 
					
						
							|  |  |  |   if (typeof options === 'function') { | 
					
						
							|  |  |  |     cb = options | 
					
						
							|  |  |  |     options = null | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-03-30 15:19:13 +08:00
										 |  |  |   generateClientManifest(file, clientManifest => { | 
					
						
							| 
									
										
										
										
											2017-04-02 15:38:26 +08:00
										 |  |  |     createBundleRenderer(file, Object.assign({ | 
					
						
							| 
									
										
										
										
											2017-03-30 15:19:13 +08:00
										 |  |  |       asBundle: true, | 
					
						
							|  |  |  |       template: defaultTemplate, | 
					
						
							| 
									
										
										
										
											2017-04-02 15:38:26 +08:00
										 |  |  |       clientManifest | 
					
						
							|  |  |  |     }, options), cb) | 
					
						
							| 
									
										
										
										
											2017-03-30 15:19:13 +08:00
										 |  |  |   }) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-30 12:10:43 +08:00
										 |  |  | describe('SSR: template option', () => { | 
					
						
							|  |  |  |   it('renderToString', done => { | 
					
						
							|  |  |  |     const renderer = createRenderer({ | 
					
						
							| 
									
										
										
										
											2017-03-30 15:19:13 +08:00
										 |  |  |       template: defaultTemplate | 
					
						
							| 
									
										
										
										
											2017-03-30 12:10:43 +08:00
										 |  |  |     }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const context = { | 
					
						
							|  |  |  |       head: '<meta name="viewport" content="width=device-width">', | 
					
						
							|  |  |  |       styles: '<style>h1 { color: red }</style>', | 
					
						
							|  |  |  |       state: { a: 1 } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     renderer.renderToString(new Vue({ | 
					
						
							|  |  |  |       template: '<div>hi</div>' | 
					
						
							|  |  |  |     }), (err, res) => { | 
					
						
							|  |  |  |       expect(err).toBeNull() | 
					
						
							|  |  |  |       expect(res).toContain( | 
					
						
							|  |  |  |         `<html><head>${context.head}${context.styles}</head><body>` + | 
					
						
							|  |  |  |         `<div data-server-rendered="true">hi</div>` + | 
					
						
							|  |  |  |         `<script>window.__INITIAL_STATE__={"a":1}</script>` + | 
					
						
							|  |  |  |         `</body></html>` | 
					
						
							|  |  |  |       ) | 
					
						
							|  |  |  |       done() | 
					
						
							|  |  |  |     }, context) | 
					
						
							|  |  |  |   }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('renderToStream', done => { | 
					
						
							|  |  |  |     const renderer = createRenderer({ | 
					
						
							| 
									
										
										
										
											2017-03-30 15:19:13 +08:00
										 |  |  |       template: defaultTemplate | 
					
						
							| 
									
										
										
										
											2017-03-30 12:10:43 +08:00
										 |  |  |     }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const context = { | 
					
						
							|  |  |  |       head: '<meta name="viewport" content="width=device-width">', | 
					
						
							|  |  |  |       styles: '<style>h1 { color: red }</style>', | 
					
						
							|  |  |  |       state: { a: 1 } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const stream = renderer.renderToStream(new Vue({ | 
					
						
							|  |  |  |       template: '<div>hi</div>' | 
					
						
							|  |  |  |     }), context) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     let res = '' | 
					
						
							|  |  |  |     stream.on('data', chunk => { | 
					
						
							|  |  |  |       res += chunk | 
					
						
							|  |  |  |     }) | 
					
						
							|  |  |  |     stream.on('end', () => { | 
					
						
							|  |  |  |       expect(res).toContain( | 
					
						
							|  |  |  |         `<html><head>${context.head}${context.styles}</head><body>` + | 
					
						
							|  |  |  |         `<div data-server-rendered="true">hi</div>` + | 
					
						
							|  |  |  |         `<script>window.__INITIAL_STATE__={"a":1}</script>` + | 
					
						
							|  |  |  |         `</body></html>` | 
					
						
							|  |  |  |       ) | 
					
						
							|  |  |  |       done() | 
					
						
							|  |  |  |     }) | 
					
						
							|  |  |  |   }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('bundleRenderer + renderToString', done => { | 
					
						
							| 
									
										
										
										
											2017-03-30 15:19:13 +08:00
										 |  |  |     createBundleRenderer('app.js', { | 
					
						
							|  |  |  |       asBundle: true, | 
					
						
							|  |  |  |       template: defaultTemplate | 
					
						
							|  |  |  |     }, renderer => { | 
					
						
							| 
									
										
										
										
											2017-03-30 12:10:43 +08:00
										 |  |  |       const context = { | 
					
						
							|  |  |  |         head: '<meta name="viewport" content="width=device-width">', | 
					
						
							|  |  |  |         styles: '<style>h1 { color: red }</style>', | 
					
						
							|  |  |  |         state: { a: 1 }, | 
					
						
							|  |  |  |         url: '/test' | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       renderer.renderToString(context, (err, res) => { | 
					
						
							|  |  |  |         expect(err).toBeNull() | 
					
						
							|  |  |  |         expect(res).toContain( | 
					
						
							|  |  |  |           `<html><head>${context.head}${context.styles}</head><body>` + | 
					
						
							|  |  |  |           `<div data-server-rendered="true">/test</div>` + | 
					
						
							|  |  |  |           `<script>window.__INITIAL_STATE__={"a":1}</script>` + | 
					
						
							|  |  |  |           `</body></html>` | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |         expect(context.msg).toBe('hello') | 
					
						
							|  |  |  |         done() | 
					
						
							|  |  |  |       }) | 
					
						
							|  |  |  |     }) | 
					
						
							|  |  |  |   }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   it('bundleRenderer + renderToStream', done => { | 
					
						
							| 
									
										
										
										
											2017-03-30 15:19:13 +08:00
										 |  |  |     createBundleRenderer('app.js', { | 
					
						
							|  |  |  |       asBundle: true, | 
					
						
							|  |  |  |       template: defaultTemplate | 
					
						
							|  |  |  |     }, renderer => { | 
					
						
							| 
									
										
										
										
											2017-03-30 12:10:43 +08:00
										 |  |  |       const context = { | 
					
						
							|  |  |  |         head: '<meta name="viewport" content="width=device-width">', | 
					
						
							|  |  |  |         styles: '<style>h1 { color: red }</style>', | 
					
						
							|  |  |  |         state: { a: 1 }, | 
					
						
							|  |  |  |         url: '/test' | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       const stream = renderer.renderToStream(context) | 
					
						
							|  |  |  |       let res = '' | 
					
						
							|  |  |  |       stream.on('data', chunk => { | 
					
						
							|  |  |  |         res += chunk.toString() | 
					
						
							|  |  |  |       }) | 
					
						
							|  |  |  |       stream.on('end', () => { | 
					
						
							|  |  |  |         expect(res).toContain( | 
					
						
							|  |  |  |           `<html><head>${context.head}${context.styles}</head><body>` + | 
					
						
							|  |  |  |           `<div data-server-rendered="true">/test</div>` + | 
					
						
							|  |  |  |           `<script>window.__INITIAL_STATE__={"a":1}</script>` + | 
					
						
							|  |  |  |           `</body></html>` | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |         expect(context.msg).toBe('hello') | 
					
						
							|  |  |  |         done() | 
					
						
							|  |  |  |       }) | 
					
						
							| 
									
										
										
										
											2017-03-30 15:19:13 +08:00
										 |  |  |     }) | 
					
						
							|  |  |  |   }) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-31 17:42:56 +08:00
										 |  |  |   const expectedHTMLWithManifest = preloadOtherAssets => | 
					
						
							| 
									
										
										
										
											2017-03-30 15:19:13 +08:00
										 |  |  |     `<html><head>` + | 
					
						
							|  |  |  |       // used chunks should have preload
 | 
					
						
							|  |  |  |       `<link rel="preload" href="/manifest.js" as="script">` + | 
					
						
							|  |  |  |       `<link rel="preload" href="/main.js" as="script">` + | 
					
						
							|  |  |  |       `<link rel="preload" href="/0.js" as="script">` + | 
					
						
							| 
									
										
										
										
											2017-03-31 17:42:56 +08:00
										 |  |  |       // images and fonts are only preloaded when explicitly asked for
 | 
					
						
							|  |  |  |       (preloadOtherAssets ? `<link rel="preload" href="/test.png" as="image">` : ``) + | 
					
						
							|  |  |  |       (preloadOtherAssets ? `<link rel="preload" href="/test.woff2" as="font" type="font/woff2" crossorigin>` : ``) + | 
					
						
							| 
									
										
										
										
											2017-03-30 15:19:13 +08:00
										 |  |  |       // unused chunks should have prefetch
 | 
					
						
							|  |  |  |       `<link rel="prefetch" href="/1.js" as="script">` + | 
					
						
							|  |  |  |     `</head><body>` + | 
					
						
							| 
									
										
										
										
											2017-03-30 21:34:39 +08:00
										 |  |  |       `<div data-server-rendered="true"><div>async test.woff2 test.png</div></div>` + | 
					
						
							| 
									
										
										
										
											2017-03-30 15:19:13 +08:00
										 |  |  |       // manifest chunk should be first
 | 
					
						
							|  |  |  |       `<script src="/manifest.js"></script>` + | 
					
						
							|  |  |  |       // async chunks should be before main chunk
 | 
					
						
							|  |  |  |       `<script src="/0.js"></script>` + | 
					
						
							|  |  |  |       `<script src="/main.js"></script>` + | 
					
						
							|  |  |  |     `</body></html>` | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-14 16:26:12 +08:00
										 |  |  |   createClientManifestAssertions(true) | 
					
						
							|  |  |  |   createClientManifestAssertions(false) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-16 20:04:42 +08:00
										 |  |  |   function createClientManifestAssertions (runInNewContext) { | 
					
						
							| 
									
										
										
										
											2017-04-14 16:26:12 +08:00
										 |  |  |     it('bundleRenderer + renderToString + clientManifest', done => { | 
					
						
							| 
									
										
										
										
											2017-04-16 20:04:42 +08:00
										 |  |  |       createRendererWithManifest('split.js', { runInNewContext }, renderer => { | 
					
						
							| 
									
										
										
										
											2017-04-14 16:26:12 +08:00
										 |  |  |         renderer.renderToString({}, (err, res) => { | 
					
						
							|  |  |  |           expect(err).toBeNull() | 
					
						
							|  |  |  |           expect(res).toContain(expectedHTMLWithManifest(false)) | 
					
						
							|  |  |  |           done() | 
					
						
							|  |  |  |         }) | 
					
						
							| 
									
										
										
										
											2017-03-30 15:19:13 +08:00
										 |  |  |       }) | 
					
						
							|  |  |  |     }) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-14 16:26:12 +08:00
										 |  |  |     it('bundleRenderer + renderToStream + clientManifest + shouldPreload', done => { | 
					
						
							|  |  |  |       createRendererWithManifest('split.js', { | 
					
						
							| 
									
										
										
										
											2017-04-16 20:04:42 +08:00
										 |  |  |         runInNewContext, | 
					
						
							| 
									
										
										
										
											2017-04-14 16:26:12 +08:00
										 |  |  |         shouldPreload: (file, type) => { | 
					
						
							|  |  |  |           if (type === 'image' || type === 'script' || type === 'font') { | 
					
						
							|  |  |  |             return true | 
					
						
							|  |  |  |           } | 
					
						
							| 
									
										
										
										
											2017-04-02 15:38:26 +08:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2017-04-14 16:26:12 +08:00
										 |  |  |       }, renderer => { | 
					
						
							|  |  |  |         const stream = renderer.renderToStream({}) | 
					
						
							|  |  |  |         let res = '' | 
					
						
							|  |  |  |         stream.on('data', chunk => { | 
					
						
							|  |  |  |           res += chunk.toString() | 
					
						
							|  |  |  |         }) | 
					
						
							|  |  |  |         stream.on('end', () => { | 
					
						
							|  |  |  |           expect(res).toContain(expectedHTMLWithManifest(true)) | 
					
						
							|  |  |  |           done() | 
					
						
							|  |  |  |         }) | 
					
						
							| 
									
										
										
										
											2017-03-30 15:19:13 +08:00
										 |  |  |       }) | 
					
						
							| 
									
										
										
										
											2017-04-02 15:38:26 +08:00
										 |  |  |     }) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-14 16:26:12 +08:00
										 |  |  |     it('bundleRenderer + renderToString + clientManifest + no template', done => { | 
					
						
							|  |  |  |       createRendererWithManifest('split.js', { | 
					
						
							| 
									
										
										
										
											2017-04-16 20:04:42 +08:00
										 |  |  |         runInNewContext, | 
					
						
							| 
									
										
										
										
											2017-04-14 16:26:12 +08:00
										 |  |  |         template: null | 
					
						
							|  |  |  |       }, renderer => { | 
					
						
							|  |  |  |         const context = {} | 
					
						
							|  |  |  |         renderer.renderToString(context, (err, res) => { | 
					
						
							|  |  |  |           expect(err).toBeNull() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           const customOutput = | 
					
						
							|  |  |  |             `<html><head>${ | 
					
						
							|  |  |  |               context.renderPreloadLinks() + | 
					
						
							|  |  |  |               context.renderPrefetchLinks() | 
					
						
							|  |  |  |             }</head><body>${ | 
					
						
							|  |  |  |               res + | 
					
						
							|  |  |  |               context.renderScripts() | 
					
						
							|  |  |  |             }</body></html>` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           expect(customOutput).toContain(expectedHTMLWithManifest(false)) | 
					
						
							|  |  |  |           done() | 
					
						
							|  |  |  |         }) | 
					
						
							| 
									
										
										
										
											2017-04-02 15:38:26 +08:00
										 |  |  |       }) | 
					
						
							| 
									
										
										
										
											2017-03-30 12:10:43 +08:00
										 |  |  |     }) | 
					
						
							| 
									
										
										
										
											2017-04-14 16:26:12 +08:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2017-03-30 12:10:43 +08:00
										 |  |  | }) |