ssrComponent.spec.ts 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. import { compile } from '../src'
  2. describe('ssr: components', () => {
  3. test('basic', () => {
  4. expect(compile(`<foo id="a" :prop="b" />`).code).toMatchInlineSnapshot(`
  5. "const { resolveComponent: _resolveComponent } = require(\\"vue\\")
  6. const { ssrRenderComponent: _ssrRenderComponent } = require(\\"@vue/server-renderer\\")
  7. return function ssrRender(_ctx, _push, _parent) {
  8. const _component_foo = _resolveComponent(\\"foo\\")
  9. _push(_ssrRenderComponent(_component_foo, {
  10. id: \\"a\\",
  11. prop: _ctx.b
  12. }, null, _parent))
  13. }"
  14. `)
  15. })
  16. test('dynamic component', () => {
  17. expect(compile(`<component is="foo" prop="b" />`).code)
  18. .toMatchInlineSnapshot(`
  19. "const { resolveComponent: _resolveComponent } = require(\\"vue\\")
  20. const { ssrRenderComponent: _ssrRenderComponent } = require(\\"@vue/server-renderer\\")
  21. return function ssrRender(_ctx, _push, _parent) {
  22. const _component_foo = _resolveComponent(\\"foo\\")
  23. _push(_ssrRenderComponent(_component_foo, { prop: \\"b\\" }, null, _parent))
  24. }"
  25. `)
  26. expect(compile(`<component :is="foo" prop="b" />`).code)
  27. .toMatchInlineSnapshot(`
  28. "const { resolveDynamicComponent: _resolveDynamicComponent } = require(\\"vue\\")
  29. const { ssrRenderComponent: _ssrRenderComponent } = require(\\"@vue/server-renderer\\")
  30. return function ssrRender(_ctx, _push, _parent) {
  31. _push(_ssrRenderComponent(_resolveDynamicComponent(_ctx.foo, _ctx.$), { prop: \\"b\\" }, null, _parent))
  32. }"
  33. `)
  34. })
  35. describe('slots', () => {
  36. test('implicit default slot', () => {
  37. expect(compile(`<foo>hello<div/></foo>`).code).toMatchInlineSnapshot(`
  38. "const { resolveComponent: _resolveComponent, createVNode: _createVNode, createTextVNode: _createTextVNode } = require(\\"vue\\")
  39. const { ssrRenderComponent: _ssrRenderComponent } = require(\\"@vue/server-renderer\\")
  40. return function ssrRender(_ctx, _push, _parent) {
  41. const _component_foo = _resolveComponent(\\"foo\\")
  42. _push(_ssrRenderComponent(_component_foo, null, {
  43. default: (_, _push, _parent, _scopeId) => {
  44. if (_push) {
  45. _push(\`hello<div\${_scopeId}></div>\`)
  46. } else {
  47. return [
  48. _createTextVNode(\\"hello\\"),
  49. _createVNode(\\"div\\")
  50. ]
  51. }
  52. },
  53. _: 1
  54. }, _parent))
  55. }"
  56. `)
  57. })
  58. test('explicit default slot', () => {
  59. expect(compile(`<foo v-slot="{ msg }">{{ msg + outer }}</foo>`).code)
  60. .toMatchInlineSnapshot(`
  61. "const { resolveComponent: _resolveComponent, createTextVNode: _createTextVNode } = require(\\"vue\\")
  62. const { ssrRenderComponent: _ssrRenderComponent, ssrInterpolate: _ssrInterpolate } = require(\\"@vue/server-renderer\\")
  63. return function ssrRender(_ctx, _push, _parent) {
  64. const _component_foo = _resolveComponent(\\"foo\\")
  65. _push(_ssrRenderComponent(_component_foo, null, {
  66. default: ({ msg }, _push, _parent, _scopeId) => {
  67. if (_push) {
  68. _push(\`\${_ssrInterpolate(msg + _ctx.outer)}\`)
  69. } else {
  70. return [
  71. _createTextVNode(_toDisplayString(msg + _ctx.outer))
  72. ]
  73. }
  74. },
  75. _: 1
  76. }, _parent))
  77. }"
  78. `)
  79. })
  80. test('named slots', () => {
  81. expect(
  82. compile(`<foo>
  83. <template v-slot>foo</template>
  84. <template v-slot:named>bar</template>
  85. </foo>`).code
  86. ).toMatchInlineSnapshot(`
  87. "const { resolveComponent: _resolveComponent, createTextVNode: _createTextVNode } = require(\\"vue\\")
  88. const { ssrRenderComponent: _ssrRenderComponent } = require(\\"@vue/server-renderer\\")
  89. return function ssrRender(_ctx, _push, _parent) {
  90. const _component_foo = _resolveComponent(\\"foo\\")
  91. _push(_ssrRenderComponent(_component_foo, null, {
  92. default: (_, _push, _parent, _scopeId) => {
  93. if (_push) {
  94. _push(\`foo\`)
  95. } else {
  96. return [
  97. _createTextVNode(\\"foo\\")
  98. ]
  99. }
  100. },
  101. named: (_, _push, _parent, _scopeId) => {
  102. if (_push) {
  103. _push(\`bar\`)
  104. } else {
  105. return [
  106. _createTextVNode(\\"bar\\")
  107. ]
  108. }
  109. },
  110. _: 1
  111. }, _parent))
  112. }"
  113. `)
  114. })
  115. test('v-if slot', () => {
  116. expect(
  117. compile(`<foo>
  118. <template v-slot:named v-if="ok">foo</template>
  119. </foo>`).code
  120. ).toMatchInlineSnapshot(`
  121. "const { resolveComponent: _resolveComponent, createTextVNode: _createTextVNode, createSlots: _createSlots } = require(\\"vue\\")
  122. const { ssrRenderComponent: _ssrRenderComponent } = require(\\"@vue/server-renderer\\")
  123. return function ssrRender(_ctx, _push, _parent) {
  124. const _component_foo = _resolveComponent(\\"foo\\")
  125. _push(_ssrRenderComponent(_component_foo, null, _createSlots({ _: 1 }, [
  126. (_ctx.ok)
  127. ? {
  128. name: \\"named\\",
  129. fn: (_, _push, _parent, _scopeId) => {
  130. if (_push) {
  131. _push(\`foo\`)
  132. } else {
  133. return [
  134. _createTextVNode(\\"foo\\")
  135. ]
  136. }
  137. }
  138. }
  139. : undefined
  140. ]), _parent))
  141. }"
  142. `)
  143. })
  144. test('v-for slot', () => {
  145. expect(
  146. compile(`<foo>
  147. <template v-for="key in names" v-slot:[key]="{ msg }">{{ msg + key + bar }}</template>
  148. </foo>`).code
  149. ).toMatchInlineSnapshot(`
  150. "const { resolveComponent: _resolveComponent, createTextVNode: _createTextVNode, renderList: _renderList, createSlots: _createSlots } = require(\\"vue\\")
  151. const { ssrRenderComponent: _ssrRenderComponent, ssrInterpolate: _ssrInterpolate } = require(\\"@vue/server-renderer\\")
  152. return function ssrRender(_ctx, _push, _parent) {
  153. const _component_foo = _resolveComponent(\\"foo\\")
  154. _push(_ssrRenderComponent(_component_foo, null, _createSlots({ _: 1 }, [
  155. _renderList(_ctx.names, (key) => {
  156. return {
  157. name: key,
  158. fn: ({ msg }, _push, _parent, _scopeId) => {
  159. if (_push) {
  160. _push(\`\${_ssrInterpolate(msg + key + _ctx.bar)}\`)
  161. } else {
  162. return [
  163. _createTextVNode(_toDisplayString(msg + _ctx.key + _ctx.bar))
  164. ]
  165. }
  166. }
  167. }
  168. })
  169. ]), _parent))
  170. }"
  171. `)
  172. })
  173. test('nested transform scoping in vnode branch', () => {
  174. expect(
  175. compile(`<foo>
  176. <template v-slot:foo="{ list }">
  177. <div v-if="ok">
  178. <span v-for="i in list"></span>
  179. </div>
  180. </template>
  181. <template v-slot:bar="{ ok }">
  182. <div v-if="ok">
  183. <span v-for="i in list"></span>
  184. </div>
  185. </template>
  186. </foo>`).code
  187. ).toMatchInlineSnapshot(`
  188. "const { resolveComponent: _resolveComponent, renderList: _renderList, Fragment: _Fragment, openBlock: _openBlock, createBlock: _createBlock, createVNode: _createVNode, createCommentVNode: _createCommentVNode } = require(\\"vue\\")
  189. const { ssrRenderComponent: _ssrRenderComponent, ssrRenderList: _ssrRenderList } = require(\\"@vue/server-renderer\\")
  190. return function ssrRender(_ctx, _push, _parent) {
  191. const _component_foo = _resolveComponent(\\"foo\\")
  192. _push(_ssrRenderComponent(_component_foo, null, {
  193. foo: ({ list }, _push, _parent, _scopeId) => {
  194. if (_push) {
  195. if (_ctx.ok) {
  196. _push(\`<div\${_scopeId}><!---->\`)
  197. _ssrRenderList(list, (i) => {
  198. _push(\`<span\${_scopeId}></span>\`)
  199. })
  200. _push(\`<!----></div>\`)
  201. } else {
  202. _push(\`<!---->\`)
  203. }
  204. } else {
  205. return [
  206. (_ctx.ok)
  207. ? (_openBlock(), _createBlock(\\"div\\", { key: 0 }, [
  208. (_openBlock(true), _createBlock(_Fragment, null, _renderList(list, (i) => {
  209. return (_openBlock(), _createBlock(\\"span\\"))
  210. }), 256 /* UNKEYED_FRAGMENT */))
  211. ]))
  212. : _createCommentVNode(\\"v-if\\", true)
  213. ]
  214. }
  215. },
  216. bar: ({ ok }, _push, _parent, _scopeId) => {
  217. if (_push) {
  218. if (ok) {
  219. _push(\`<div\${_scopeId}><!---->\`)
  220. _ssrRenderList(_ctx.list, (i) => {
  221. _push(\`<span\${_scopeId}></span>\`)
  222. })
  223. _push(\`<!----></div>\`)
  224. } else {
  225. _push(\`<!---->\`)
  226. }
  227. } else {
  228. return [
  229. ok
  230. ? (_openBlock(), _createBlock(\\"div\\", { key: 0 }, [
  231. (_openBlock(true), _createBlock(_Fragment, null, _renderList(_ctx.list, (i) => {
  232. return (_openBlock(), _createBlock(\\"span\\"))
  233. }), 256 /* UNKEYED_FRAGMENT */))
  234. ]))
  235. : _createCommentVNode(\\"v-if\\", true)
  236. ]
  237. }
  238. },
  239. _: 1
  240. }, _parent))
  241. }"
  242. `)
  243. })
  244. test('built-in fallthroughs', () => {
  245. // no fragment
  246. expect(compile(`<transition><div/></transition>`).code)
  247. .toMatchInlineSnapshot(`
  248. "
  249. return function ssrRender(_ctx, _push, _parent) {
  250. _push(\`<div></div>\`)
  251. }"
  252. `)
  253. // wrap with fragment
  254. expect(compile(`<transition-group><div/></transition-group>`).code)
  255. .toMatchInlineSnapshot(`
  256. "
  257. return function ssrRender(_ctx, _push, _parent) {
  258. _push(\`<!----><div></div><!---->\`)
  259. }"
  260. `)
  261. // no fragment
  262. expect(compile(`<keep-alive><foo/></keep-alive>`).code)
  263. .toMatchInlineSnapshot(`
  264. "const { resolveComponent: _resolveComponent } = require(\\"vue\\")
  265. const { ssrRenderComponent: _ssrRenderComponent } = require(\\"@vue/server-renderer\\")
  266. return function ssrRender(_ctx, _push, _parent) {
  267. const _component_foo = _resolveComponent(\\"foo\\")
  268. _push(_ssrRenderComponent(_component_foo, null, null, _parent))
  269. }"
  270. `)
  271. // wrap with fragment
  272. expect(compile(`<suspense><div/></suspense>`).code)
  273. .toMatchInlineSnapshot(`
  274. "
  275. return function ssrRender(_ctx, _push, _parent) {
  276. _push(\`<!----><div></div><!---->\`)
  277. }"
  278. `)
  279. })
  280. })
  281. })