templateTransformSrcset.spec.ts 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. import {
  2. type TransformOptions,
  3. baseParse,
  4. generate,
  5. transform,
  6. } from '@vue/compiler-core'
  7. import {
  8. createSrcsetTransformWithOptions,
  9. transformSrcset,
  10. } from '../src/template/transformSrcset'
  11. import { transformElement } from '../../compiler-core/src/transforms/transformElement'
  12. import { transformBind } from '../../compiler-core/src/transforms/vBind'
  13. import {
  14. type AssetURLOptions,
  15. normalizeOptions,
  16. } from '../src/template/transformAssetUrl'
  17. import { stringifyStatic } from '../../compiler-dom/src/transforms/stringifyStatic'
  18. function compileWithSrcset(
  19. template: string,
  20. options?: AssetURLOptions,
  21. transformOptions?: TransformOptions,
  22. ) {
  23. const ast = baseParse(template)
  24. const srcsetTransform = options
  25. ? createSrcsetTransformWithOptions(normalizeOptions(options))
  26. : transformSrcset
  27. transform(ast, {
  28. hoistStatic: true,
  29. nodeTransforms: [srcsetTransform, transformElement],
  30. directiveTransforms: {
  31. bind: transformBind,
  32. },
  33. ...transformOptions,
  34. })
  35. return generate(ast, { mode: 'module' })
  36. }
  37. const src = `
  38. <img src="./logo.png" srcset=""/>
  39. <img src="./logo.png" srcset="./logo.png"/>
  40. <img src="./logo.png" srcset="./logo.png 2x"/>
  41. <img src="./logo.png" srcset="./logo.png 2x"/>
  42. <img src="./logo.png" srcset="./logo.png, ./logo.png 2x"/>
  43. <img src="./logo.png" srcset="./logo.png 2x, ./logo.png"/>
  44. <img src="./logo.png" srcset="./logo.png 2x, ./logo.png 3x"/>
  45. <img src="./logo.png" srcset="./logo.png, ./logo.png 2x, ./logo.png 3x"/>
  46. <img src="/logo.png" srcset="/logo.png, /logo.png 2x"/>
  47. <img src="https://example.com/logo.png" srcset="https://example.com/logo.png, https://example.com/logo.png 2x"/>
  48. <img src="/logo.png" srcset="/logo.png, ./logo.png 2x"/>
  49. <img src="data:image/png;base64,i" srcset="data:image/png;base64,i 1x, data:image/png;base64,i 2x"/>
  50. `
  51. describe('compiler sfc: transform srcset', () => {
  52. test('transform srcset', () => {
  53. expect(compileWithSrcset(src).code).toMatchSnapshot()
  54. })
  55. test('transform srcset w/ base', () => {
  56. expect(
  57. compileWithSrcset(src, {
  58. base: '/foo',
  59. }).code,
  60. ).toMatchSnapshot()
  61. })
  62. test('transform srcset w/ includeAbsolute: true', () => {
  63. expect(
  64. compileWithSrcset(src, {
  65. includeAbsolute: true,
  66. }).code,
  67. ).toMatchSnapshot()
  68. })
  69. test('transform empty srcset w/ includeAbsolute: true', () => {
  70. expect(
  71. compileWithSrcset(`<img srcset=" " />`, {
  72. includeAbsolute: true,
  73. }).code,
  74. ).toMatchSnapshot()
  75. })
  76. test('transform srcset w/ stringify', () => {
  77. const code = compileWithSrcset(
  78. `<div>${src}</div>`,
  79. {
  80. includeAbsolute: true,
  81. },
  82. {
  83. hoistStatic: true,
  84. transformHoist: stringifyStatic,
  85. },
  86. ).code
  87. expect(code).toMatch(`_createStaticVNode`)
  88. expect(code).toMatchSnapshot()
  89. })
  90. test('srcset w/ explicit base option', () => {
  91. const code = compileWithSrcset(
  92. `
  93. <img srcset="@/logo.png, @/logo.png 2x"/>
  94. <img srcset="@/logo.png 1x, ./logo.png 2x"/>
  95. `,
  96. { base: '/foo/' },
  97. { hoistStatic: true },
  98. ).code
  99. expect(code).toMatchSnapshot()
  100. })
  101. test('should transform subpath import paths starting with #', () => {
  102. const code = compileWithSrcset(
  103. `<img srcset="#src/assets/vue.svg" />` +
  104. `<img srcset="#/src/assets/vue.svg 2x" />`,
  105. ).code
  106. expect(code).toContain(`_imports_0 from '#src/assets/vue.svg'`)
  107. expect(code).toContain(`_imports_1 from '#/src/assets/vue.svg'`)
  108. expect(code).toContain(`const _hoisted_1 = _imports_0`)
  109. expect(code).toContain(`const _hoisted_2 = _imports_1 + ' 2x'`)
  110. })
  111. test('should preserve svg fragments in srcset URLs', () => {
  112. const code = compileWithSrcset(
  113. `<img srcset="./icons.svg#icon-heart" />` +
  114. `<img srcset="./icons.svg#icon-star 2x" />`,
  115. ).code
  116. expect(code).toContain(`_imports_0 from './icons.svg'`)
  117. expect(code).toContain(`const _hoisted_1 = _imports_0 + '#icon-heart'`)
  118. expect(code).toContain(
  119. `const _hoisted_2 = _imports_0 + '#icon-star' + ' 2x'`,
  120. )
  121. })
  122. test('should not throw for malformed percent-encoding in srcset paths', () => {
  123. const code = compileWithSrcset(`<img srcset="./foo%.png 2x" />`).code
  124. expect(code).toContain(`import _imports_0 from './foo%.png'`)
  125. expect(code).toContain(`const _hoisted_1 = _imports_0 + ' 2x'`)
  126. })
  127. })