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-43 -> 31:2-43", "32:2-35 -> 32:2-35", "33:0 -> 33:0", "2:4 -> 35:0", "36:2-20 -> 36:2-20", "37:2-22 -> 37:2-22", "38:0 -> 38:0", "2:4 -> 40:0", "41:2-16 -> 41:2-16", "42:2-34 -> 42:2-34", "43:2-26 -> 43:2-26", "44:0 -> 44:0", "2:4 -> 46:0", "47:2-21 -> 47:2-21", "48:0 -> 48:0", "2:4 -> 50:0", "51:2-109 -> 51:2-109", "52:2-16 -> 52:2-16", "53:0 -> 53:0", "2:4 -> 55:0", "56:2-16 -> 56:2-16", "57:0 -> 57:0", "2:4 -> 59:0", "60:2-26 -> 60:2-26", "61:2-16 -> 61:2-16", "62:2-16 -> 62:2-16", "63:2-20 -> 63:2-20", "64:0 -> 64:0", "2:4 -> 66:0", "67:2-16 -> 67:2-16", "68:0 -> 68:0", "2:4 -> 70:0", "71:2-12 -> 71:2-12", "72:0 -> 72:0", "2:4 -> 74:0", "75:2-16 -> 75:2-16", "76:2-23 -> 76:2-23", "77:2-27 -> 77:2-27", "78:0 -> 78:0", "2:4 -> 80:0", "81:2-32 -> 81:2-32", "82:2-34 -> 82:2-34", "83:2-22 -> 83:2-22", "84:2-17 -> 84:2-17", "85:2-22 -> 85:2-22", "86:2-22 -> 86:2-22", "87:2-16 -> 87:2-16", "88:2-11 -> 88:2-11", "89:2-12 -> 89:2-12", "90:0 -> 90:0", "2:4 -> 92:0", "93:2-22 -> 93:2-22", "94:0 -> 94:0", "2:4 -> 96:0", "97:2-28 -> 97:2-28", "98:2-25 -> 98:2-25", "99:2-24 -> 99:2-24", "100:0 -> 100:0", "2:4 -> 102:0", "103:2-15 -> 103:2-15", "104:0 -> 104:0", "2:4 -> 106:0", "107:2-18 -> 107:2-18", "108:0 -> 108:0", "2:4 -> 110:0", "111:2-26 -> 111:2-26", "112:0 -> 112:0", "2:4 -> 114:0", "115:2-14 -> 115:2-14", "116:0 -> 116:0", "2:4 -> 118:0", "119:2-31 -> 119:2-31", "120:2-22 -> 120:2-22", "121:0 -> 121:0", "2:4 -> 123:0", "124:2-26 -> 124:2-26", "125:0 -> 125:0", "2:4 -> 127:0", "128:2-28 -> 128:2-28", "129:2-15 -> 129:2-15", "130:0 -> 130:0", "2:4 -> 132:0", "133:2-20 -> 133:2-20", "134:0 -> 134:0", "2:4 -> 136:0", "137:2-11 -> 137:2-11", "138:0 -> 138:0", "2:4 -> 140:0", "141:2-11 -> 141:2-11", "142:2-12 -> 142:2-12", "143:0 -> 143:0", "2:4 -> 145:0", "146:2-12 -> 146:2-12", "147:0 -> 147:0", "2:4 -> 149:0", "150:2-11 -> 150:2-11", "151:2-12 -> 151:2-12", "152:2-18 -> 152:2-18", "153:0 -> 153:0", "2:4 -> 155:0", "156:2-12 -> 156:2-12", "157:0 -> 157:0", "2:4 -> 159:0", "160:2-18 -> 160:2-18", "161:0 -> 161:0", "2:4 -> 163:0", "164:2-12 -> 164:2-12", "165:2-16 -> 165:2-16", "166:0 -> 166:0", "2:4 -> 168:0", "169:2-17 -> 169:2-17", "170:0 -> 170:0", "2:4 -> 172:0", "173:2-17 -> 173:2-17", "174:0 -> 174:0", "2:4 -> 176:0", "177:2-24 -> 177:2-24", "178:2-16 -> 178:2-16", "179:0 -> 179:0", "2:4 -> 181:0", "182:2-17 -> 182:2-17", "183:2-14 -> 183:2-14", "184:0 -> 184:0", "2:4 -> 186:0", "187:2-15 -> 187:2-15", "188:0 -> 188:0", "2:4 -> 190:0", "191:2-26 -> 191:2-26", "192:2-26 -> 192:2-26", "193:2-21 -> 193:2-21", "194:2-21 -> 194:2-21", "195:2-16 -> 195:2-16", "196:2-16 -> 196:2-16", "197:2-16 -> 197:2-16", "198:2-17 -> 198:2-17", "199:2-17 -> 199:2-17", "200:2-14 -> 200:2-14", "201:2-14 -> 201:2-14", "202:2-19 -> 202:2-19", "203:2-40 -> 203:2-40", "204:2-31 -> 204:2-31", "205:2-30 -> 205:2-30", "206:2-29 -> 206:2-29", "207:2-16 -> 207:2-16", "208:2-21 -> 208:2-21", "209:2-23 -> 209:2-23", "210:2-24 -> 210:2-24", "211:2-25 -> 211:2-25", "212:2-19 -> 212:2-19", "213:2-29 -> 213:2-29", "214:2-30 -> 214:2-30", "215:2-28 -> 215:2-28", "216:2-36 -> 216:2-36", "217:2-29 -> 217:2-29", "218:2-24 -> 218:2-24", "219:2-32 -> 219:2-32", "220:2-13 -> 220:2-13", "221:2-19 -> 221:2-19", "222:2-17 -> 222:2-17", "223:2-18 -> 223:2-18", "224:2-19 -> 224:2-19", "225:2-15 -> 225:2-15", "226:2-17 -> 226:2-17", "227:2-14 -> 227:2-14", "228:2-20 -> 228:2-20", "229:2-22 -> 229:2-22", "230:2-28 -> 230:2-28", "231:2-26 -> 231:2-26", "232:2-27 -> 232:2-27", "233:2-28 -> 233:2-28", "234:2-24 -> 234:2-24", "235:2-25 -> 235:2-25", "236:2-26 -> 236:2-26", "237:2-23 -> 237:2-23", "238:0 -> 238:0", "2:4 -> 240:0", "241:2-26 -> 241:2-26", "242:2-26 -> 242:2-26", "243:2-21 -> 243:2-21", "244:2-21 -> 244:2-21", "245:2-16 -> 245:2-16", "246:2-16 -> 246:2-16", "247:2-16 -> 247:2-16", "248:2-17 -> 248:2-17", "249:2-17 -> 249:2-17", "250:2-14 -> 250:2-14", "251:2-14 -> 251:2-14", "252:2-19 -> 252:2-19", "253:2-40 -> 253:2-40", "254:2-31 -> 254:2-31", "255:2-30 -> 255:2-30", "256:2-29 -> 256:2-29", "257:2-16 -> 257:2-16", "258:2-21 -> 258:2-21", "259:2-23 -> 259:2-23", "260:2-24 -> 260:2-24", "261:2-25 -> 261:2-25", "262:2-19 -> 262:2-19", "263:2-29 -> 263:2-29", "264:2-30 -> 264:2-30", "265:2-28 -> 265:2-28", "266:2-36 -> 266:2-36", "267:2-29 -> 267:2-29", "268:2-24 -> 268:2-24", "269:2-32 -> 269:2-32", "270:2-13 -> 270:2-13", "271:2-19 -> 271:2-19", "272:2-17 -> 272:2-17", "273:2-18 -> 273:2-18", "274:2-19 -> 274:2-19", "275:2-15 -> 275:2-15", "276:2-17 -> 276:2-17", "277:2-14 -> 277:2-14", "278:2-20 -> 278:2-20", "279:2-22 -> 279:2-22", "280:2-28 -> 280:2-28", "281:2-26 -> 281:2-26", "282:2-27 -> 282:2-27", "283:2-28 -> 283:2-28", "284:2-24 -> 284:2-24", "285:2-25 -> 285:2-25", "286:2-26 -> 286:2-26", "287:2-23 -> 287:2-23", "288:0 -> 288:0", "2:4 -> 290:0", "291:2-26 -> 291:2-26", "292:2-26 -> 292:2-26", "293:2-21 -> 293:2-21", "294:2-21 -> 294:2-21", "295:2-16 -> 295:2-16", "296:2-16 -> 296:2-16", "297:2-16 -> 297:2-16", "298:2-17 -> 298:2-17", "299:2-17 -> 299:2-17", "300:2-14 -> 300:2-14", "301:2-14 -> 301:2-14", "302:2-19 -> 302:2-19", "303:2-40 -> 303:2-40", "304:2-31 -> 304:2-31", "305:2-30 -> 305:2-30", "306:2-29 -> 306:2-29", "307:2-16 -> 307:2-16", "308:2-21 -> 308:2-21", "309:2-23 -> 309:2-23", "310:2-24 -> 310:2-24", "311:2-25 -> 311:2-25", "312:2-19 -> 312:2-19", "313:2-29 -> 313:2-29", "314:2-30 -> 314:2-30", "315:2-28 -> 315:2-28", "316:2-36 -> 316:2-36", "317:2-29 -> 317:2-29", "318:2-24 -> 318:2-24", "319:2-32 -> 319:2-32", "320:2-13 -> 320:2-13", "321:2-19 -> 321:2-19", "322:2-17 -> 322:2-17", "323:2-18 -> 323:2-18", "324:2-19 -> 324:2-19", "325:2-15 -> 325:2-15", "326:2-17 -> 326:2-17", "327:2-14 -> 327:2-14", "328:2-20 -> 328:2-20", "329:2-22 -> 329:2-22", "330:2-28 -> 330:2-28", "331:2-26 -> 331:2-26", "332:2-27 -> 332:2-27", "333:2-28 -> 333:2-28", "334:2-24 -> 334:2-24", "335:2-25 -> 335:2-25", "336:2-26 -> 336:2-26", "337:2-23 -> 337:2-23", "338:0 -> 338: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", ] `) })