ssr-bundle-render.spec.js 6.3 KB

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