| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274 |
- import path from 'path'
- import webpack from 'webpack'
- import MemoeryFS from 'memory-fs'
- import VueSSRPlugin from 'vue-ssr-webpack-plugin'
- import { createBundleRenderer } from '../../packages/vue-server-renderer'
- function createRenderer (file, cb, options) {
- const asBundle = !!(options && options.asBundle)
- if (options) delete options.asBundle
- const config = {
- target: 'node',
- entry: path.resolve(__dirname, 'fixtures', file),
- devtool: asBundle ? '#source-map' : false,
- output: {
- path: '/',
- filename: 'bundle.js',
- libraryTarget: 'commonjs2'
- },
- module: {
- rules: [{ test: /\.js$/, loader: 'babel-loader' }]
- },
- externals: [require.resolve('../../dist/vue.runtime.common.js')],
- plugins: asBundle
- ? [new VueSSRPlugin()]
- : []
- }
- const compiler = webpack(config)
- const fs = new MemoeryFS()
- compiler.outputFileSystem = fs
- compiler.run((err, stats) => {
- expect(err).toBeFalsy()
- expect(stats.errors).toBeFalsy()
- const bundle = asBundle
- ? JSON.parse(fs.readFileSync('/vue-ssr-bundle.json', 'utf-8'))
- : fs.readFileSync('/bundle.js', 'utf-8')
- const renderer = createBundleRenderer(bundle, options)
- cb(renderer)
- })
- }
- describe('SSR: bundle renderer', () => {
- it('renderToString', done => {
- createRenderer('app.js', renderer => {
- const context = { url: '/test' }
- renderer.renderToString(context, (err, res) => {
- expect(err).toBeNull()
- expect(res).toBe('<div server-rendered="true">/test</div>')
- expect(context.msg).toBe('hello')
- done()
- })
- })
- })
- it('renderToStream', done => {
- createRenderer('app.js', 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('<div server-rendered="true">/test</div>')
- expect(context.msg).toBe('hello')
- done()
- })
- })
- })
- it('renderToString catch error', done => {
- createRenderer('error.js', renderer => {
- renderer.renderToString(err => {
- expect(err.message).toBe('foo')
- done()
- })
- })
- })
- it('renderToStream catch error', done => {
- createRenderer('error.js', renderer => {
- const stream = renderer.renderToStream()
- stream.on('error', err => {
- expect(err.message).toBe('foo')
- done()
- })
- })
- })
- it('render with cache (get/set)', done => {
- const cache = {}
- const get = jasmine.createSpy('get')
- const set = jasmine.createSpy('set')
- const options = {
- cache: {
- // async
- get: (key, cb) => {
- setTimeout(() => {
- get(key)
- cb(cache[key])
- }, 0)
- },
- set: (key, val) => {
- set(key, val)
- cache[key] = val
- }
- }
- }
- createRenderer('cache.js', renderer => {
- const expected = '<div server-rendered="true">/test</div>'
- const key = 'app::1'
- renderer.renderToString((err, res) => {
- expect(err).toBeNull()
- expect(res).toBe(expected)
- expect(get).toHaveBeenCalledWith(key)
- expect(set).toHaveBeenCalledWith(key, expected)
- expect(cache[key]).toBe(expected)
- renderer.renderToString((err, res) => {
- expect(err).toBeNull()
- expect(res).toBe(expected)
- expect(get.calls.count()).toBe(2)
- expect(set.calls.count()).toBe(1)
- done()
- })
- })
- }, options)
- })
- it('render with cache (get/set/has)', done => {
- const cache = {}
- const has = jasmine.createSpy('has')
- const get = jasmine.createSpy('get')
- const set = jasmine.createSpy('set')
- const options = {
- cache: {
- // async
- has: (key, cb) => {
- has(key)
- cb(!!cache[key])
- },
- // sync
- get: key => {
- get(key)
- return cache[key]
- },
- set: (key, val) => {
- set(key, val)
- cache[key] = val
- }
- }
- }
- createRenderer('cache.js', renderer => {
- const expected = '<div server-rendered="true">/test</div>'
- const key = 'app::1'
- renderer.renderToString((err, res) => {
- expect(err).toBeNull()
- expect(res).toBe(expected)
- expect(has).toHaveBeenCalledWith(key)
- expect(get).not.toHaveBeenCalled()
- expect(set).toHaveBeenCalledWith(key, expected)
- expect(cache[key]).toBe(expected)
- renderer.renderToString((err, res) => {
- expect(err).toBeNull()
- expect(res).toBe(expected)
- expect(has.calls.count()).toBe(2)
- expect(get.calls.count()).toBe(1)
- expect(set.calls.count()).toBe(1)
- done()
- })
- })
- }, options)
- })
- it('renderToString (bundle format with code split)', done => {
- createRenderer('split.js', renderer => {
- const context = { url: '/test' }
- renderer.renderToString(context, (err, res) => {
- expect(err).toBeNull()
- expect(res).toBe('<div server-rendered="true">/test<div>async</div></div>')
- done()
- })
- }, { asBundle: true })
- })
- it('renderToStream (bundle format with code split)', done => {
- createRenderer('split.js', 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('<div server-rendered="true">/test<div>async</div></div>')
- done()
- })
- }, { asBundle: true })
- })
- it('renderToString catch error (bundle format with source map)', done => {
- createRenderer('error.js', renderer => {
- renderer.renderToString(err => {
- expect(err.stack).toContain('test/ssr/fixtures/error.js:1:6')
- expect(err.message).toBe('foo')
- done()
- })
- }, { asBundle: true })
- })
- it('renderToString catch error (bundle format with source map)', done => {
- createRenderer('error.js', renderer => {
- const stream = renderer.renderToStream()
- stream.on('error', err => {
- expect(err.stack).toContain('test/ssr/fixtures/error.js:1:6')
- expect(err.message).toBe('foo')
- done()
- })
- }, { asBundle: true })
- })
- it('renderToString with template', done => {
- createRenderer('app.js', renderer => {
- 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 server-rendered="true">/test</div>` +
- `<script>window.__INITIAL_STATE__={"a":1}</script>` +
- `</body></html>`
- )
- expect(context.msg).toBe('hello')
- done()
- })
- }, {
- template: `<html><head></head><body><!--vue-ssr-outlet--></body></html>`
- })
- })
- it('renderToStream with template', done => {
- createRenderer('app.js', renderer => {
- 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 server-rendered="true">/test</div>` +
- `<script>window.__INITIAL_STATE__={"a":1}</script>` +
- `</body></html>`
- )
- expect(context.msg).toBe('hello')
- done()
- })
- }, {
- template: `<html><head></head><body><!--vue-ssr-outlet--></body></html>`
- })
- })
- })
|