ssr-bundle-render.spec.js 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. import { VueSSRServerPlugin } from 'vue-ssr-webpack-plugin'
  2. import { compileWithWebpack } from './compile-with-webpack'
  3. import { createBundleRenderer } from '../../packages/vue-server-renderer'
  4. export function createRenderer (file, options, cb) {
  5. if (typeof options === 'function') {
  6. cb = options
  7. options = undefined
  8. }
  9. const asBundle = !!(options && options.asBundle)
  10. if (options) delete options.asBundle
  11. compileWithWebpack(file, {
  12. target: 'node',
  13. devtool: asBundle ? '#source-map' : false,
  14. output: {
  15. path: '/',
  16. filename: 'bundle.js',
  17. libraryTarget: 'commonjs2'
  18. },
  19. externals: [require.resolve('../../dist/vue.runtime.common.js')],
  20. plugins: asBundle
  21. ? [new VueSSRServerPlugin()]
  22. : []
  23. }, fs => {
  24. const bundle = asBundle
  25. ? JSON.parse(fs.readFileSync('/vue-ssr-bundle.json', 'utf-8'))
  26. : fs.readFileSync('/bundle.js', 'utf-8')
  27. const renderer = createBundleRenderer(bundle, options)
  28. cb(renderer)
  29. })
  30. }
  31. describe('SSR: bundle renderer', () => {
  32. it('renderToString', done => {
  33. createRenderer('app.js', renderer => {
  34. const context = { url: '/test' }
  35. renderer.renderToString(context, (err, res) => {
  36. expect(err).toBeNull()
  37. expect(res).toBe('<div data-server-rendered="true">/test</div>')
  38. expect(context.msg).toBe('hello')
  39. done()
  40. })
  41. })
  42. })
  43. it('renderToStream', done => {
  44. createRenderer('app.js', renderer => {
  45. const context = { url: '/test' }
  46. const stream = renderer.renderToStream(context)
  47. let res = ''
  48. stream.on('data', chunk => {
  49. res += chunk.toString()
  50. })
  51. stream.on('end', () => {
  52. expect(res).toBe('<div data-server-rendered="true">/test</div>')
  53. expect(context.msg).toBe('hello')
  54. done()
  55. })
  56. })
  57. })
  58. it('renderToString catch error', done => {
  59. createRenderer('error.js', renderer => {
  60. renderer.renderToString(err => {
  61. expect(err.message).toBe('foo')
  62. done()
  63. })
  64. })
  65. })
  66. it('renderToStream catch error', done => {
  67. createRenderer('error.js', renderer => {
  68. const stream = renderer.renderToStream()
  69. stream.on('error', err => {
  70. expect(err.message).toBe('foo')
  71. done()
  72. })
  73. })
  74. })
  75. it('render with cache (get/set)', done => {
  76. const cache = {}
  77. const get = jasmine.createSpy('get')
  78. const set = jasmine.createSpy('set')
  79. const options = {
  80. cache: {
  81. // async
  82. get: (key, cb) => {
  83. setTimeout(() => {
  84. get(key)
  85. cb(cache[key])
  86. }, 0)
  87. },
  88. set: (key, val) => {
  89. set(key, val)
  90. cache[key] = val
  91. }
  92. }
  93. }
  94. createRenderer('cache.js', options, renderer => {
  95. const expected = '<div data-server-rendered="true">/test</div>'
  96. const key = 'app::1'
  97. renderer.renderToString((err, res) => {
  98. expect(err).toBeNull()
  99. expect(res).toBe(expected)
  100. expect(get).toHaveBeenCalledWith(key)
  101. expect(set).toHaveBeenCalledWith(key, expected)
  102. expect(cache[key]).toBe(expected)
  103. renderer.renderToString((err, res) => {
  104. expect(err).toBeNull()
  105. expect(res).toBe(expected)
  106. expect(get.calls.count()).toBe(2)
  107. expect(set.calls.count()).toBe(1)
  108. done()
  109. })
  110. })
  111. })
  112. })
  113. it('render with cache (get/set/has)', done => {
  114. const cache = {}
  115. const has = jasmine.createSpy('has')
  116. const get = jasmine.createSpy('get')
  117. const set = jasmine.createSpy('set')
  118. const options = {
  119. cache: {
  120. // async
  121. has: (key, cb) => {
  122. has(key)
  123. cb(!!cache[key])
  124. },
  125. // sync
  126. get: key => {
  127. get(key)
  128. return cache[key]
  129. },
  130. set: (key, val) => {
  131. set(key, val)
  132. cache[key] = val
  133. }
  134. }
  135. }
  136. createRenderer('cache.js', options, renderer => {
  137. const expected = '<div data-server-rendered="true">/test</div>'
  138. const key = 'app::1'
  139. renderer.renderToString((err, res) => {
  140. expect(err).toBeNull()
  141. expect(res).toBe(expected)
  142. expect(has).toHaveBeenCalledWith(key)
  143. expect(get).not.toHaveBeenCalled()
  144. expect(set).toHaveBeenCalledWith(key, expected)
  145. expect(cache[key]).toBe(expected)
  146. renderer.renderToString((err, res) => {
  147. expect(err).toBeNull()
  148. expect(res).toBe(expected)
  149. expect(has.calls.count()).toBe(2)
  150. expect(get.calls.count()).toBe(1)
  151. expect(set.calls.count()).toBe(1)
  152. done()
  153. })
  154. })
  155. })
  156. })
  157. it('renderToString (bundle format with code split)', done => {
  158. createRenderer('split.js', { asBundle: true }, renderer => {
  159. const context = { url: '/test' }
  160. renderer.renderToString(context, (err, res) => {
  161. expect(err).toBeNull()
  162. expect(res).toBe('<div data-server-rendered="true">/test<div>async test.woff2 test.png</div></div>')
  163. done()
  164. })
  165. })
  166. })
  167. it('renderToStream (bundle format with code split)', done => {
  168. createRenderer('split.js', { asBundle: true }, renderer => {
  169. const context = { url: '/test' }
  170. const stream = renderer.renderToStream(context)
  171. let res = ''
  172. stream.on('data', chunk => {
  173. res += chunk.toString()
  174. })
  175. stream.on('end', () => {
  176. expect(res).toBe('<div data-server-rendered="true">/test<div>async test.woff2 test.png</div></div>')
  177. done()
  178. })
  179. })
  180. })
  181. it('renderToString catch error (bundle format with source map)', done => {
  182. createRenderer('error.js', { asBundle: true }, renderer => {
  183. renderer.renderToString(err => {
  184. expect(err.stack).toContain('test/ssr/fixtures/error.js:1:6')
  185. expect(err.message).toBe('foo')
  186. done()
  187. })
  188. })
  189. })
  190. it('renderToString catch error (bundle format with source map)', done => {
  191. createRenderer('error.js', { asBundle: true }, renderer => {
  192. const stream = renderer.renderToStream()
  193. stream.on('error', err => {
  194. expect(err.stack).toContain('test/ssr/fixtures/error.js:1:6')
  195. expect(err.message).toBe('foo')
  196. done()
  197. })
  198. })
  199. })
  200. })