compileTemplate.spec.ts 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. import { parse } from '../src/parse'
  2. import { SFCBlock } from '../src/parseComponent'
  3. import { compileTemplate } from '../src/compileTemplate'
  4. import Vue from 'vue'
  5. function mockRender(code: string, mocks: Record<string, any> = {}) {
  6. const fn = new Function(
  7. `require`,
  8. `${code}; return { render, staticRenderFns }`
  9. )
  10. const vm = new Vue(
  11. Object.assign(
  12. {},
  13. fn((id: string) => mocks[id])
  14. )
  15. )
  16. vm.$mount()
  17. return (vm as any)._vnode
  18. }
  19. test('should work', () => {
  20. const source = `<div><p>{{ render }}</p></div>`
  21. const result = compileTemplate({
  22. filename: 'example.vue',
  23. source
  24. })
  25. expect(result.errors.length).toBe(0)
  26. expect(result.source).toBe(source)
  27. // should expose render fns
  28. expect(result.code).toMatch(`var render = function`)
  29. expect(result.code).toMatch(`var staticRenderFns = []`)
  30. // should mark with stripped
  31. expect(result.code).toMatch(`render._withStripped = true`)
  32. // should prefix bindings
  33. expect(result.code).toMatch(`_vm.render`)
  34. expect(result.ast).not.toBeUndefined()
  35. })
  36. test('preprocess pug', () => {
  37. const template = parse({
  38. source:
  39. '<template lang="pug">\n' +
  40. 'body\n' +
  41. ' h1 Pug Examples\n' +
  42. ' div.container\n' +
  43. ' p Cool Pug example!\n' +
  44. '</template>\n',
  45. filename: 'example.vue',
  46. sourceMap: true
  47. }).template as SFCBlock
  48. const result = compileTemplate({
  49. filename: 'example.vue',
  50. source: template.content,
  51. preprocessLang: template.lang
  52. })
  53. expect(result.errors.length).toBe(0)
  54. })
  55. /**
  56. * vuejs/component-compiler-utils#22 Support uri fragment in transformed require
  57. */
  58. test('supports uri fragment in transformed require', () => {
  59. const source = '<svg>\
  60. <use href="~@svg/file.svg#fragment"></use>\
  61. </svg>' //
  62. const result = compileTemplate({
  63. filename: 'svgparticle.html',
  64. source: source,
  65. transformAssetUrls: {
  66. use: 'href'
  67. }
  68. })
  69. expect(result.errors.length).toBe(0)
  70. expect(result.code).toMatch(
  71. /href: require\("@svg\/file.svg"\) \+ "#fragment"/
  72. )
  73. })
  74. /**
  75. * vuejs/component-compiler-utils#22 Support uri fragment in transformed require
  76. */
  77. test('when too short uri then empty require', () => {
  78. const source = '<svg>\
  79. <use href="~"></use>\
  80. </svg>' //
  81. const result = compileTemplate({
  82. filename: 'svgparticle.html',
  83. source: source,
  84. transformAssetUrls: {
  85. use: 'href'
  86. }
  87. })
  88. expect(result.errors.length).toBe(0)
  89. expect(result.code).toMatch(/href: require\(""\)/)
  90. })
  91. test('warn missing preprocessor', () => {
  92. const template = parse({
  93. source: '<template lang="unknownLang">\n' + '</template>\n',
  94. filename: 'example.vue',
  95. sourceMap: true
  96. }).template as SFCBlock
  97. const result = compileTemplate({
  98. filename: 'example.vue',
  99. source: template.content,
  100. preprocessLang: template.lang
  101. })
  102. expect(result.errors.length).toBe(1)
  103. })
  104. test('transform assetUrls', () => {
  105. const source = `
  106. <div>
  107. <img src="./logo.png">
  108. <img src="~fixtures/logo.png">
  109. <img src="~/fixtures/logo.png">
  110. </div>
  111. `
  112. const result = compileTemplate({
  113. filename: 'example.vue',
  114. source,
  115. transformAssetUrls: true
  116. })
  117. expect(result.errors.length).toBe(0)
  118. const vnode = mockRender(result.code, {
  119. './logo.png': 'a',
  120. 'fixtures/logo.png': 'b'
  121. })
  122. expect(vnode.children[0].data.attrs.src).toBe('a')
  123. expect(vnode.children[2].data.attrs.src).toBe('b')
  124. expect(vnode.children[4].data.attrs.src).toBe('b')
  125. })
  126. test('transform srcset', () => {
  127. const source = `
  128. <div>
  129. <img src="./logo.png">
  130. <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink= "http://www.w3.org/1999/xlink">
  131. <image xlink:href="./logo.png" />
  132. </svg>
  133. <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink= "http://www.w3.org/1999/xlink">
  134. <use xlink:href="./logo.png"/>
  135. </svg>
  136. </svg>
  137. <img src="./logo.png" srcset="./logo.png">
  138. <img src="./logo.png" srcset="./logo.png 2x">
  139. <img src="./logo.png" srcset="./logo.png, ./logo.png 2x">
  140. <img src="./logo.png" srcset="./logo.png 2x, ./logo.png">
  141. <img src="./logo.png" srcset="./logo.png 2x, ./logo.png 3x">
  142. <img src="./logo.png" srcset="./logo.png, ./logo.png 2x, ./logo.png 3x">
  143. <img
  144. src="./logo.png"
  145. srcset="
  146. ./logo.png 2x,
  147. ./logo.png 3x
  148. ">
  149. </div>
  150. `
  151. const result = compileTemplate({
  152. filename: 'example.vue',
  153. source,
  154. transformAssetUrls: true
  155. })
  156. expect(result.errors.length).toBe(0)
  157. const vnode = mockRender(result.code, {
  158. './logo.png': 'test-url'
  159. })
  160. // img tag
  161. expect(vnode.children[0].data.attrs.src).toBe('test-url')
  162. // image tag (SVG)
  163. expect(vnode.children[2].children[0].data.attrs['xlink:href']).toBe(
  164. 'test-url'
  165. )
  166. // use tag (SVG)
  167. expect(vnode.children[4].children[0].data.attrs['xlink:href']).toBe(
  168. 'test-url'
  169. )
  170. // image tag with srcset
  171. expect(vnode.children[6].data.attrs.srcset).toBe('test-url')
  172. expect(vnode.children[8].data.attrs.srcset).toBe('test-url 2x')
  173. // image tag with multiline srcset
  174. expect(vnode.children[10].data.attrs.srcset).toBe('test-url, test-url 2x')
  175. expect(vnode.children[12].data.attrs.srcset).toBe('test-url 2x, test-url')
  176. expect(vnode.children[14].data.attrs.srcset).toBe('test-url 2x, test-url 3x')
  177. expect(vnode.children[16].data.attrs.srcset).toBe(
  178. 'test-url, test-url 2x, test-url 3x'
  179. )
  180. expect(vnode.children[18].data.attrs.srcset).toBe('test-url 2x, test-url 3x')
  181. })
  182. test('transform assetUrls and srcset with base option', () => {
  183. const source = `
  184. <div>
  185. <img src="./logo.png">
  186. <img src="~fixtures/logo.png">
  187. <img src="~/fixtures/logo.png">
  188. <img src="./logo.png" srcset="./logo.png 2x, ./logo.png 3x">
  189. <img src="@/fixtures/logo.png">
  190. </div>
  191. `
  192. const result = compileTemplate({
  193. filename: 'example.vue',
  194. source,
  195. transformAssetUrls: true,
  196. transformAssetUrlsOptions: { base: '/base/' }
  197. })
  198. expect(result.errors.length).toBe(0)
  199. const vnode = mockRender(result.code, {
  200. '@/fixtures/logo.png': 'aliased'
  201. })
  202. expect(vnode.children[0].data.attrs.src).toBe('/base/logo.png')
  203. expect(vnode.children[2].data.attrs.src).toBe('/base/fixtures/logo.png')
  204. expect(vnode.children[4].data.attrs.src).toBe('/base/fixtures/logo.png')
  205. expect(vnode.children[6].data.attrs.srcset).toBe(
  206. '/base/logo.png 2x, /base/logo.png 3x'
  207. )
  208. expect(vnode.children[8].data.attrs.src).toBe('aliased')
  209. })
  210. test('transform with includeAbsolute', () => {
  211. const source = `
  212. <div>
  213. <img src="./logo.png">
  214. <img src="/logo.png">
  215. <img src="https://foo.com/logo.png">
  216. </div>
  217. `
  218. const result = compileTemplate({
  219. filename: 'example.vue',
  220. source,
  221. transformAssetUrls: true,
  222. transformAssetUrlsOptions: { includeAbsolute: true }
  223. })
  224. expect(result.errors.length).toBe(0)
  225. const vnode = mockRender(result.code, {
  226. './logo.png': 'relative',
  227. '/logo.png': 'absolute'
  228. })
  229. expect(vnode.children[0].data.attrs.src).toBe('relative')
  230. expect(vnode.children[2].data.attrs.src).toBe('absolute')
  231. expect(vnode.children[4].data.attrs.src).toBe('https://foo.com/logo.png')
  232. })