import postcss from 'postcss' import { parseSourceMaps } from './util/source-maps' import { runWithSourceMaps as run, html, css, map } from './util/run' test('apply generates source maps', async () => { let config = { content: [ { raw: html`
`, }, ], corePlugins: { preflight: false }, } let input = css` .with-declaration { background-color: red; @apply h-4 w-4 bg-green-500; } .with-comment { /* sourcemap will work here too */ @apply h-4 w-4 bg-red-500; } .just-apply { @apply h-4 w-4 bg-black; } ` let result = await run(input, config) let { sources, annotations } = parseSourceMaps(result) // All CSS generated by Tailwind CSS should be annotated with source maps // And always be able to point to the original source file expect(sources).not.toContain('') expect(sources.length).toBe(2) expect(annotations).toMatchInlineSnapshot(` [ "2:4 -> 1:0", "2:2-20 -> 2:2-20", "3:2-23 -> 3:2-23", "4:2-57 -> 4:2-57", "5:2-13 -> 5:2-13", "6:2-14 -> 6:2-14", "7:0 -> 7:0", "7:4 -> 9:0", "10:2-20 -> 10:2-20", "11:2-57 -> 11:2-57", "12:2-13 -> 12:2-13", "13:2-14 -> 13:2-14", "14:0 -> 14:0", "13:6 -> 16:0", "17:2-20 -> 17:2-20", "18:2-53 -> 18:2-53", "19:2-13 -> 19:2-13", "20:2-14 -> 20:2-14", "21:0 -> 21:0", ] `) }) test('preflight + base have source maps', async () => { let config = { content: [], } let input = css` @tailwind base; ` let result = await run(input, config) let { sources, annotations } = parseSourceMaps(result) // All CSS generated by Tailwind CSS should be annotated with source maps // And always be able to point to the original source file expect(sources).not.toContain('') expect(sources.length).toBe(2) expect(annotations).toMatchInlineSnapshot(` [ "2:4 -> 1:0", "2:2-24 -> 2:2-24", "3:2-25 -> 3:2-25", "4:0 -> 4:0", "2:4 -> 6:0", "7:2-18 -> 7:2-18", "8:0 -> 8:0", "2:4 -> 10:0", "11:2-32 -> 11:2-32", "12:2-13 -> 12:2-13", "13:2-31 -> 13:2-31", "14:2-33 -> 14:2-33", "15:2-208 -> 15:2-208", "16:2-18 -> 16:2-18", "17:0 -> 17:0", "2:4 -> 19:0", "20:2-22 -> 20:2-22", "21:2-11 -> 21:2-11", "22:0 -> 22:0", "2:4 -> 24:0", "25:2-16 -> 25:2-16", "26:2-23 -> 26:2-23", "27:2-11 -> 27:2-11", "28:0 -> 28:0", "2:4 -> 30:0", "31:2-35 -> 31:2-35", "32:0 -> 32:0", "2:4 -> 34:0", "35:2-20 -> 35:2-20", "36:2-22 -> 36:2-22", "37:0 -> 37:0", "2:4 -> 39:0", "40:2-16 -> 40:2-16", "41:2-26 -> 41:2-26", "42:0 -> 42:0", "2:4 -> 44:0", "45:2-21 -> 45:2-21", "46:0 -> 46:0", "2:4 -> 48:0", "49:2-109 -> 49:2-109", "50:2-16 -> 50:2-16", "51:0 -> 51:0", "2:4 -> 53:0", "54:2-16 -> 54:2-16", "55:0 -> 55:0", "2:4 -> 57:0", "58:2-26 -> 58:2-26", "59:2-16 -> 59:2-16", "60:2-16 -> 60:2-16", "61:2-20 -> 61:2-20", "62:0 -> 62:0", "2:4 -> 64:0", "65:2-16 -> 65:2-16", "66:0 -> 66:0", "2:4 -> 68:0", "69:2-12 -> 69:2-12", "70:0 -> 70:0", "2:4 -> 72:0", "73:2-16 -> 73:2-16", "74:2-23 -> 74:2-23", "75:2-27 -> 75:2-27", "76:0 -> 76:0", "2:4 -> 78:0", "79:2-32 -> 79:2-32", "80:2-34 -> 80:2-34", "81:2-22 -> 81:2-22", "82:2-17 -> 82:2-17", "83:2-22 -> 83:2-22", "84:2-22 -> 84:2-22", "85:2-16 -> 85:2-16", "86:2-11 -> 86:2-11", "87:2-12 -> 87:2-12", "88:0 -> 88:0", "2:4 -> 90:0", "91:2-22 -> 91:2-22", "92:0 -> 92:0", "2:4 -> 94:0", "95:2-28 -> 95:2-28", "96:2-25 -> 96:2-25", "97:2-24 -> 97:2-24", "98:0 -> 98:0", "2:4 -> 100:0", "101:2-15 -> 101:2-15", "102:0 -> 102:0", "2:4 -> 104:0", "105:2-18 -> 105:2-18", "106:0 -> 106:0", "2:4 -> 108:0", "109:2-26 -> 109:2-26", "110:0 -> 110:0", "2:4 -> 112:0", "113:2-14 -> 113:2-14", "114:0 -> 114:0", "2:4 -> 116:0", "117:2-31 -> 117:2-31", "118:2-22 -> 118:2-22", "119:0 -> 119:0", "2:4 -> 121:0", "122:2-26 -> 122:2-26", "123:0 -> 123:0", "2:4 -> 125:0", "126:2-28 -> 126:2-28", "127:2-15 -> 127:2-15", "128:0 -> 128:0", "2:4 -> 130:0", "131:2-20 -> 131:2-20", "132:0 -> 132:0", "2:4 -> 134:0", "135:2-11 -> 135:2-11", "136:0 -> 136:0", "2:4 -> 138:0", "139:2-11 -> 139:2-11", "140:2-12 -> 140:2-12", "141:0 -> 141:0", "2:4 -> 143:0", "144:2-12 -> 144:2-12", "145:0 -> 145:0", "2:4 -> 147:0", "148:2-11 -> 148:2-11", "149:2-12 -> 149:2-12", "150:2-18 -> 150:2-18", "151:0 -> 151:0", "2:4 -> 153:0", "154:2-12 -> 154:2-12", "155:0 -> 155:0", "2:4 -> 157:0", "158:2-18 -> 158:2-18", "159:0 -> 159:0", "2:4 -> 161:0", "162:2-12 -> 162:2-12", "163:2-16 -> 163:2-16", "164:0 -> 164:0", "2:4 -> 166:0", "167:2-17 -> 167:2-17", "168:0 -> 168:0", "2:4 -> 170:0", "171:2-17 -> 171:2-17", "172:0 -> 172:0", "2:4 -> 174:0", "175:2-24 -> 175:2-24", "176:2-16 -> 176:2-16", "177:0 -> 177:0", "2:4 -> 179:0", "180:2-17 -> 180:2-17", "181:2-14 -> 181:2-14", "182:0 -> 182:0", "2:4 -> 184:0", "185:2-15 -> 185:2-15", "186:0 -> 186:0", "2:4 -> 188:0", "189:2-26 -> 189:2-26", "190:2-26 -> 190:2-26", "191:2-21 -> 191:2-21", "192:2-21 -> 192:2-21", "193:2-16 -> 193:2-16", "194:2-16 -> 194:2-16", "195:2-16 -> 195:2-16", "196:2-17 -> 196:2-17", "197:2-17 -> 197:2-17", "198:2-14 -> 198:2-14", "199:2-14 -> 199:2-14", "200:2-19 -> 200:2-19", "201:2-40 -> 201:2-40", "202:2-31 -> 202:2-31", "203:2-30 -> 203:2-30", "204:2-29 -> 204:2-29", "205:2-16 -> 205:2-16", "206:2-21 -> 206:2-21", "207:2-23 -> 207:2-23", "208:2-24 -> 208:2-24", "209:2-25 -> 209:2-25", "210:2-19 -> 210:2-19", "211:2-29 -> 211:2-29", "212:2-30 -> 212:2-30", "213:2-28 -> 213:2-28", "214:2-36 -> 214:2-36", "215:2-29 -> 215:2-29", "216:2-24 -> 216:2-24", "217:2-32 -> 217:2-32", "218:2-13 -> 218:2-13", "219:2-19 -> 219:2-19", "220:2-17 -> 220:2-17", "221:2-18 -> 221:2-18", "222:2-19 -> 222:2-19", "223:2-15 -> 223:2-15", "224:2-17 -> 224:2-17", "225:2-14 -> 225:2-14", "226:2-20 -> 226:2-20", "227:2-22 -> 227:2-22", "228:2-28 -> 228:2-28", "229:2-26 -> 229:2-26", "230:2-27 -> 230:2-27", "231:2-28 -> 231:2-28", "232:2-24 -> 232:2-24", "233:2-25 -> 233:2-25", "234:2-26 -> 234:2-26", "235:2-23 -> 235:2-23", "236:0 -> 236:0", ] `) }) test('utilities have source maps', async () => { let config = { content: [{ raw: `text-red-500` }], } let input = css` @tailwind utilities; ` let result = await run(input, config) let { sources, annotations } = parseSourceMaps(result) // All CSS generated by Tailwind CSS should be annotated with source maps // And always be able to point to the original source file expect(sources).not.toContain('') expect(sources.length).toBe(2) expect(annotations).toMatchInlineSnapshot(` [ "2:4 -> 1:0", "2:2-22 -> 2:2-22", "3:2-48 -> 3:2-48", "4:0 -> 4:0", ] `) }) test('components have source maps', async () => { let config = { content: [{ raw: `container` }], } let input = css` @tailwind components; ` let result = await run(input, config) let { sources, annotations } = parseSourceMaps(result) // All CSS generated by Tailwind CSS should be annotated with source maps // And always be able to point to the original source file expect(sources).not.toContain('') expect(sources.length).toBe(2) expect(annotations).toMatchInlineSnapshot(` [ "2:4 -> 1:0", "2:2-13 -> 2:2-13", "3:0 -> 3:0", "2:4 -> 5:0", "2:4 -> 6:2", "7:4-20 -> 7:4-20", "8:2 -> 8:2", "9:0 -> 9:0", "2:4 -> 11:0", "2:4 -> 12:2", "13:4-20 -> 13:4-20", "14:2 -> 14:2", "15:0 -> 15:0", "2:4 -> 17:0", "2:4 -> 18:2", "19:4-21 -> 19:4-21", "20:2 -> 20:2", "21:0 -> 21:0", "2:4 -> 23:0", "2:4 -> 24:2", "25:4-21 -> 25:4-21", "26:2 -> 26:2", "27:0 -> 27:0", "2:4 -> 29:0", "2:4 -> 30:2", "31:4-21 -> 31:4-21", "32:2 -> 32:2", "33:0 -> 33:0", ] `) }) test('source maps for layer rules are not rewritten to point to @tailwind directives', async () => { let config = { content: [{ raw: `font-normal foo hover:foo` }], } let utilitiesFile = postcss.parse( css` @tailwind utilities; `, { from: 'components.css', map: { prev: map } } ) let mainCssFile = postcss.parse( css` @layer utilities { .foo { background-color: red; } } `, { from: 'input.css', map: { prev: map } } ) // Just pretend that there's an @import in `mainCssFile` that imports the nodes from `utilitiesFile` let input = postcss.root({ nodes: [...utilitiesFile.nodes, ...mainCssFile.nodes], source: mainCssFile.source, }) let result = await run(input, config) let { sources, annotations } = parseSourceMaps(result) // All CSS generated by Tailwind CSS should be annotated with source maps // And always be able to point to the original source file expect(sources).not.toContain('') // And we should see that the source map for the layer rule is not rewritten // to point to the @tailwind directive but instead points to the original expect(sources.length).toBe(3) expect(sources).toMatchInlineSnapshot(` [ "components.css", "source-maps.test.js%3Ftest=c291cmNlIG1hcHMgZm9yIGxheWVyIHJ1bGVzIGFyZSBub3QgcmV3cml0dGVuIHRvIHBvaW50IHRvIEB0YWlsd2luZCBkaXJlY3RpdmVz", "input.css", ] `) expect(annotations).toMatchInlineSnapshot(` [ "2:6 -> 1:0", "2:2-18 -> 2:2-18", "3:0 -> 3:0", "3:8 -> 5:0", "6:2-23 -> 6:2-23", "7:0 -> 7:0", ] `) }) test('it handles `map: true` correctly', async () => { let config = { content: [{ raw: `text-red-500` }], } let input = css` @tailwind utilities; ` let result = await run(input, config, { map: true, }) let { sources, annotations } = parseSourceMaps(result) // All CSS generated by Tailwind CSS should be annotated with source maps // And always be able to point to the original source file expect(sources).not.toContain('') expect(sources.length).toBe(2) expect(annotations).toMatchInlineSnapshot(` [ "2:4 -> 1:0", "2:2-22 -> 2:2-22", "3:2-48 -> 3:2-48", "4:0 -> 4:0", ] `) }) test('it handles `map: { inline: true }` correctly', async () => { let config = { content: [{ raw: `text-red-500` }], } let input = css` @tailwind utilities; ` let result = await run(input, config, { map: { inline: true, }, }) let { sources, annotations } = parseSourceMaps(result) // All CSS generated by Tailwind CSS should be annotated with source maps // And always be able to point to the original source file expect(sources).not.toContain('') expect(sources.length).toBe(2) expect(annotations).toMatchInlineSnapshot(` [ "2:4 -> 1:0", "2:2-22 -> 2:2-22", "3:2-48 -> 3:2-48", "4:0 -> 4:0", ] `) })