import { VueSSRServerPlugin } from 'vue-ssr-webpack-plugin'
import { compileWithWebpack } from './compile-with-webpack'
import { createBundleRenderer } from '../../packages/vue-server-renderer'
export function createRenderer (file, options, cb) {
if (typeof options === 'function') {
cb = options
options = undefined
}
const asBundle = !!(options && options.asBundle)
if (options) delete options.asBundle
compileWithWebpack(file, {
target: 'node',
devtool: asBundle ? '#source-map' : false,
output: {
path: '/',
filename: 'bundle.js',
libraryTarget: 'commonjs2'
},
externals: [require.resolve('../../dist/vue.runtime.common.js')],
plugins: asBundle
? [new VueSSRServerPlugin()]
: []
}, fs => {
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('
/test
')
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('/test
')
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', options, renderer => {
const expected = '/test
'
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()
})
})
})
})
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', options, renderer => {
const expected = '/test
'
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()
})
})
})
})
it('renderToString (bundle format with code split)', done => {
createRenderer('split.js', { asBundle: true }, renderer => {
const context = { url: '/test' }
renderer.renderToString(context, (err, res) => {
expect(err).toBeNull()
expect(res).toBe('/test
async test.woff2 test.png
')
done()
})
})
})
it('renderToStream (bundle format with code split)', done => {
createRenderer('split.js', { 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
')
done()
})
})
})
it('renderToString catch error (bundle format with source map)', done => {
createRenderer('error.js', { asBundle: true }, renderer => {
renderer.renderToString(err => {
expect(err.stack).toContain('test/ssr/fixtures/error.js:1:6')
expect(err.message).toBe('foo')
done()
})
})
})
it('renderToString catch error (bundle format with source map)', done => {
createRenderer('error.js', { asBundle: true }, 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()
})
})
})
})