cssVars.spec.ts 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. import { compileStyle } from '../src'
  2. import { mockId, compileSFCScript, assertCode } from './utils'
  3. describe('CSS vars injection', () => {
  4. test('generating correct code for nested paths', () => {
  5. const { content } = compileSFCScript(
  6. `<script>const a = 1</script>\n` +
  7. `<style>div{
  8. color: v-bind(color);
  9. font-size: v-bind('font.size');
  10. }</style>`
  11. )
  12. expect(content).toMatch(`_useCssVars(_ctx => ({
  13. "${mockId}-color": (_ctx.color),
  14. "${mockId}-font_size": (_ctx.font.size)
  15. })`)
  16. assertCode(content)
  17. })
  18. test('w/ normal <script> binding analysis', () => {
  19. const { content } = compileSFCScript(
  20. `<script>
  21. export default {
  22. setup() {
  23. return {
  24. size: ref('100px')
  25. }
  26. }
  27. }
  28. </script>\n` +
  29. `<style>
  30. div {
  31. font-size: v-bind(size);
  32. }
  33. </style>`
  34. )
  35. expect(content).toMatch(`_useCssVars(_ctx => ({
  36. "${mockId}-size": (_ctx.size)
  37. })`)
  38. expect(content).toMatch(`import { useCssVars as _useCssVars } from 'vue'`)
  39. assertCode(content)
  40. })
  41. test('w/ <script setup> binding analysis', () => {
  42. const { content } = compileSFCScript(
  43. `<script setup>
  44. import { defineProps, ref } from 'vue'
  45. const color = 'red'
  46. const size = ref('10px')
  47. defineProps({
  48. foo: String
  49. })
  50. </script>\n` +
  51. `<style>
  52. div {
  53. color: v-bind(color);
  54. font-size: v-bind(size);
  55. border: v-bind(foo);
  56. }
  57. </style>`
  58. )
  59. // should handle:
  60. // 1. local const bindings
  61. // 2. local potential ref bindings
  62. // 3. props bindings (analyzed)
  63. expect(content).toMatch(`_useCssVars(_ctx => ({
  64. "${mockId}-color": (color),
  65. "${mockId}-size": (size.value),
  66. "${mockId}-foo": (__props.foo)
  67. })`)
  68. expect(content).toMatch(
  69. `import { useCssVars as _useCssVars, unref as _unref } from 'vue'`
  70. )
  71. assertCode(content)
  72. })
  73. test('should rewrite CSS vars in compileStyle', () => {
  74. const { code } = compileStyle({
  75. source: `.foo {
  76. color: v-bind(color);
  77. font-size: v-bind('font.size');
  78. }`,
  79. filename: 'test.css',
  80. id: 'data-v-test'
  81. })
  82. expect(code).toMatchInlineSnapshot(`
  83. ".foo {
  84. color: var(--test-color);
  85. font-size: var(--test-font_size);
  86. }"
  87. `)
  88. })
  89. test('prod mode', () => {
  90. const { content } = compileSFCScript(
  91. `<script>const a = 1</script>\n` +
  92. `<style>div{
  93. color: v-bind(color);
  94. font-size: v-bind('font.size');
  95. }</style>`,
  96. { isProd: true }
  97. )
  98. expect(content).toMatch(`_useCssVars(_ctx => ({
  99. "4003f1a6": (_ctx.color),
  100. "41b6490a": (_ctx.font.size)
  101. }))}`)
  102. const { code } = compileStyle({
  103. source: `.foo {
  104. color: v-bind(color);
  105. font-size: v-bind('font.size');
  106. }`,
  107. filename: 'test.css',
  108. id: mockId,
  109. isProd: true
  110. })
  111. expect(code).toMatchInlineSnapshot(`
  112. ".foo {
  113. color: var(--4003f1a6);
  114. font-size: var(--41b6490a);
  115. }"
  116. `)
  117. })
  118. describe('codegen', () => {
  119. test('<script> w/ no default export', () => {
  120. assertCode(
  121. compileSFCScript(
  122. `<script>const a = 1</script>\n` +
  123. `<style>div{ color: v-bind(color); }</style>`
  124. ).content
  125. )
  126. })
  127. test('<script> w/ default export', () => {
  128. assertCode(
  129. compileSFCScript(
  130. `<script>export default { setup() {} }</script>\n` +
  131. `<style>div{ color: v-bind(color); }</style>`
  132. ).content
  133. )
  134. })
  135. test('<script> w/ default export in strings/comments', () => {
  136. assertCode(
  137. compileSFCScript(
  138. `<script>
  139. // export default {}
  140. export default {}
  141. </script>\n` + `<style>div{ color: v-bind(color); }</style>`
  142. ).content
  143. )
  144. })
  145. test('w/ <script setup>', () => {
  146. assertCode(
  147. compileSFCScript(
  148. `<script setup>const color = 'red'</script>\n` +
  149. `<style>div{ color: v-bind(color); }</style>`
  150. ).content
  151. )
  152. })
  153. //#4185
  154. test('should ignore comments', () => {
  155. const { content } = compileSFCScript(
  156. `<script setup>const color = 'red';const width = 100</script>\n` +
  157. `<style>
  158. /* comment **/
  159. div{ /* color: v-bind(color); */ width:20; }
  160. div{ width: v-bind(width); }
  161. /* comment */
  162. </style>`
  163. )
  164. expect(content).not.toMatch(`"${mockId}-color": (color)`)
  165. expect(content).toMatch(`"${mockId}-width": (width)`)
  166. assertCode(content)
  167. })
  168. test('w/ <script setup> using the same var multiple times', () => {
  169. const { content } = compileSFCScript(
  170. `<script setup>
  171. const color = 'red'
  172. </script>\n` +
  173. `<style>
  174. div {
  175. color: v-bind(color);
  176. }
  177. p {
  178. color: v-bind(color);
  179. }
  180. </style>`
  181. )
  182. // color should only be injected once, even if it is twice in style
  183. expect(content).toMatch(`_useCssVars(_ctx => ({
  184. "${mockId}-color": (color)
  185. })`)
  186. assertCode(content)
  187. })
  188. })
  189. })