@@ -1429,6 +1429,348 @@ func TestCSSAtImportConditionsWithImportRecordsBundle(t *testing.T) {
14291429 })
14301430}
14311431
1432+ // From: https://github.com/romainmenke/css-import-tests. These test cases just
1433+ // serve to document any changes in esbuild's behavior. Any changes in behavior
1434+ // should be tested to ensure they don't cause any regressions. The easiest way
1435+ // to test the changes is to bundle https://github.com/evanw/css-import-tests
1436+ // and visually inspect a browser's rendering of the resulting CSS file.
1437+ func TestCSSAtImportConditionsFromExternalRepo (t * testing.T ) {
1438+ css_suite .expectBundled (t , bundled {
1439+ files : map [string ]string {
1440+ "/001/default/a.css" : `.box { background-color: green; }` ,
1441+ "/001/default/style.css" : `@import url("a.css");` ,
1442+
1443+ "/001/relative-url/a.css" : `.box { background-color: green; }` ,
1444+ "/001/relative-url/style.css" : `@import url("./a.css");` ,
1445+
1446+ "/at-charset/001/a.css" : `@charset "utf-8"; .box { background-color: red; }` ,
1447+ "/at-charset/001/b.css" : `@charset "utf-8"; .box { background-color: green; }` ,
1448+ "/at-charset/001/style.css" : `@charset "utf-8"; @import url("a.css"); @import url("b.css");` ,
1449+
1450+ "/at-keyframes/001/a.css" : `
1451+ .box { animation: BOX; animation-duration: 0s; animation-fill-mode: both; }
1452+ @keyframes BOX { 0%, 100% { background-color: green; } }
1453+ ` ,
1454+ "/at-keyframes/001/b.css" : `
1455+ .box { animation: BOX; animation-duration: 0s; animation-fill-mode: both; }
1456+ @keyframes BOX { 0%, 100% { background-color: red; } }
1457+ ` ,
1458+ "/at-keyframes/001/style.css" : `@import url("a.css") screen; @import url("b.css") print;` ,
1459+
1460+ "/at-layer/001/a.css" : `.box { background-color: red; }` ,
1461+ "/at-layer/001/b.css" : `.box { background-color: green; }` ,
1462+ "/at-layer/001/style.css" : `
1463+ @import url("a.css") layer(a);
1464+ @import url("b.css") layer(b);
1465+ @import url("a.css") layer(a);
1466+ ` ,
1467+
1468+ "/at-layer/002/a.css" : `.box { background-color: green; }` ,
1469+ "/at-layer/002/b.css" : `.box { background-color: red; }` ,
1470+ "/at-layer/002/style.css" : `
1471+ @import url("a.css") layer(a) print;
1472+ @import url("b.css") layer(b);
1473+ @import url("a.css") layer(a);
1474+ ` ,
1475+
1476+ // Note: This case is currently bundled incorrectly. Normal CSS takes
1477+ // effect at the position of the last "@import". However, "@layer" CSS
1478+ // takes effect at the position of the first "@import". This discrepancy
1479+ // in behavior is not currently handled.
1480+ "/at-layer/003/a.css" : `@layer a { .box { background-color: red; } }` ,
1481+ "/at-layer/003/b.css" : `@layer b { .box { background-color: green; } }` ,
1482+ "/at-layer/003/style.css" : `@import url("a.css"); @import url("b.css"); @import url("a.css");` ,
1483+
1484+ "/at-layer/004/a.css" : `@layer { .box { background-color: green; } }` ,
1485+ "/at-layer/004/b.css" : `@layer { .box { background-color: red; } }` ,
1486+ "/at-layer/004/style.css" : `@import url("a.css"); @import url("b.css"); @import url("a.css");` ,
1487+
1488+ "/at-layer/005/a.css" : `@import url("b.css") layer(b) (width: 1px);` ,
1489+ "/at-layer/005/b.css" : `.box { background-color: red; }` ,
1490+ "/at-layer/005/style.css" : `
1491+ @import url("a.css") layer(a) (min-width: 1px);
1492+ @layer a.c { .box { background-color: red; } }
1493+ @layer a.b { .box { background-color: green; } }
1494+ ` ,
1495+
1496+ "/at-layer/006/a.css" : `@import url("b.css") layer(b) (min-width: 1px);` ,
1497+ "/at-layer/006/b.css" : `.box { background-color: red; }` ,
1498+ "/at-layer/006/style.css" : `
1499+ @import url("a.css") layer(a) (min-width: 1px);
1500+ @layer a.c { .box { background-color: green; } }
1501+ @layer a.b { .box { background-color: red; } }
1502+ ` ,
1503+
1504+ "/at-layer/007/style.css" : `
1505+ @layer foo {}
1506+ @layer bar {}
1507+ @layer bar { .box { background-color: green; } }
1508+ @layer foo { .box { background-color: red; } }
1509+ ` ,
1510+
1511+ "/at-layer/008/a.css" : `@import "b.css" layer; .box { background-color: green; }` ,
1512+ "/at-layer/008/b.css" : `.box { background-color: red; }` ,
1513+ "/at-layer/008/style.css" : `@import url("a.css") layer;` ,
1514+
1515+ "/at-media/001/default/a.css" : `.box { background-color: green; }` ,
1516+ "/at-media/001/default/style.css" : `@import url("a.css") screen;` ,
1517+
1518+ "/at-media/002/a.css" : `.box { background-color: green; }` ,
1519+ "/at-media/002/b.css" : `.box { background-color: red; }` ,
1520+ "/at-media/002/style.css" : `@import url("a.css") screen; @import url("b.css") print;` ,
1521+
1522+ "/at-media/003/a.css" : `@import url("b.css") (min-width: 1px);` ,
1523+ "/at-media/003/b.css" : `.box { background-color: green; }` ,
1524+ "/at-media/003/style.css" : `@import url("a.css") screen;` ,
1525+
1526+ "/at-media/004/a.css" : `@import url("b.css") print;` ,
1527+ "/at-media/004/b.css" : `.box { background-color: red; }` ,
1528+ "/at-media/004/c.css" : `.box { background-color: green; }` ,
1529+ "/at-media/004/style.css" : `@import url("c.css"); @import url("a.css") print;` ,
1530+
1531+ "/at-media/005/a.css" : `@import url("b.css") (max-width: 1px);` ,
1532+ "/at-media/005/b.css" : `.box { background-color: red; }` ,
1533+ "/at-media/005/c.css" : `.box { background-color: green; }` ,
1534+ "/at-media/005/style.css" : `@import url("c.css"); @import url("a.css") (max-width: 1px);` ,
1535+
1536+ "/at-media/006/a.css" : `@import url("b.css") (min-width: 1px);` ,
1537+ "/at-media/006/b.css" : `.box { background-color: green; }` ,
1538+ "/at-media/006/style.css" : `@import url("a.css") (min-height: 1px);` ,
1539+
1540+ "/at-media/007/a.css" : `@import url("b.css") screen;` ,
1541+ "/at-media/007/b.css" : `.box { background-color: green; }` ,
1542+ "/at-media/007/style.css" : `@import url("a.css") all;` ,
1543+
1544+ "/at-media/008/a.css" : `@import url("green.css") layer(alpha) print;` ,
1545+ "/at-media/008/b.css" : `@import url("red.css") layer(beta) print;` ,
1546+ "/at-media/008/green.css" : `.box { background-color: green; }` ,
1547+ "/at-media/008/red.css" : `.box { background-color: red; }` ,
1548+ "/at-media/008/style.css" : `
1549+ @import url("a.css") layer(alpha) all;
1550+ @import url("b.css") layer(beta) all;
1551+ @layer beta { .box { background-color: green; } }
1552+ @layer alpha { .box { background-color: red; } }
1553+ ` ,
1554+
1555+ "/at-supports/001/a.css" : `.box { background-color: green; }` ,
1556+ "/at-supports/001/style.css" : `@import url("a.css") supports(display: block);` ,
1557+
1558+ "/at-supports/002/a.css" : `@import url("b.css") supports(width: 10px);` ,
1559+ "/at-supports/002/b.css" : `.box { background-color: green; }` ,
1560+ "/at-supports/002/style.css" : `@import url("a.css") supports(display: block);` ,
1561+
1562+ "/at-supports/003/a.css" : `@import url("b.css") supports(width: 10px);` ,
1563+ "/at-supports/003/b.css" : `.box { background-color: green; }` ,
1564+ "/at-supports/003/style.css" : `@import url("a.css") supports((display: block) or (display: inline));` ,
1565+
1566+ "/at-supports/004/a.css" : `@import url("b.css") layer(b) supports(width: 10px);` ,
1567+ "/at-supports/004/b.css" : `.box { background-color: green; }` ,
1568+ "/at-supports/004/style.css" : `@import url("a.css") layer(a) supports(display: block);` ,
1569+
1570+ "/at-supports/005/a.css" : `@import url("green.css") layer(alpha) supports(foo: bar);` ,
1571+ "/at-supports/005/b.css" : `@import url("red.css") layer(beta) supports(foo: bar);` ,
1572+ "/at-supports/005/green.css" : `.box { background-color: green; }` ,
1573+ "/at-supports/005/red.css" : `.box { background-color: red; }` ,
1574+ "/at-supports/005/style.css" : `
1575+ @import url("a.css") layer(alpha) supports(display: block);
1576+ @import url("b.css") layer(beta) supports(display: block);
1577+ @layer beta { .box { background-color: green; } }
1578+ @layer alpha { .box { background-color: red; } }
1579+ ` ,
1580+
1581+ "/cycles/001/style.css" : `@import url("style.css"); .box { background-color: green; }` ,
1582+
1583+ "/cycles/002/a.css" : `@import url("red.css"); @import url("b.css");` ,
1584+ "/cycles/002/b.css" : `@import url("green.css"); @import url("a.css");` ,
1585+ "/cycles/002/green.css" : `.box { background-color: green; }` ,
1586+ "/cycles/002/red.css" : `.box { background-color: red; }` ,
1587+ "/cycles/002/style.css" : `@import url("a.css");` ,
1588+
1589+ "/cycles/003/a.css" : `@import url("b.css"); .box { background-color: green; }` ,
1590+ "/cycles/003/b.css" : `@import url("a.css"); .box { background-color: red; }` ,
1591+ "/cycles/003/style.css" : `@import url("a.css");` ,
1592+
1593+ "/cycles/004/a.css" : `@import url("b.css"); .box { background-color: red; }` ,
1594+ "/cycles/004/b.css" : `@import url("a.css"); .box { background-color: green; }` ,
1595+ "/cycles/004/style.css" : `@import url("a.css"); @import url("b.css");` ,
1596+
1597+ "/cycles/005/a.css" : `@import url("b.css"); .box { background-color: green; }` ,
1598+ "/cycles/005/b.css" : `@import url("a.css"); .box { background-color: red; }` ,
1599+ "/cycles/005/style.css" : `@import url("a.css"); @import url("b.css"); @import url("a.css");` ,
1600+
1601+ "/cycles/006/a.css" : `@import url("red.css"); @import url("b.css");` ,
1602+ "/cycles/006/b.css" : `@import url("green.css"); @import url("a.css");` ,
1603+ "/cycles/006/c.css" : `@import url("a.css");` ,
1604+ "/cycles/006/green.css" : `.box { background-color: green; }` ,
1605+ "/cycles/006/red.css" : `.box { background-color: red; }` ,
1606+ "/cycles/006/style.css" : `@import url("b.css"); @import url("c.css");` ,
1607+
1608+ "/cycles/007/a.css" : `@import url("red.css"); @import url("b.css") screen;` ,
1609+ "/cycles/007/b.css" : `@import url("green.css"); @import url("a.css") all;` ,
1610+ "/cycles/007/c.css" : `@import url("a.css") not print;` ,
1611+ "/cycles/007/green.css" : `.box { background-color: green; }` ,
1612+ "/cycles/007/red.css" : `.box { background-color: red; }` ,
1613+ "/cycles/007/style.css" : `@import url("b.css"); @import url("c.css");` ,
1614+
1615+ "/cycles/008/a.css" : `@import url("red.css") layer; @import url("b.css");` ,
1616+ "/cycles/008/b.css" : `@import url("green.css") layer; @import url("a.css");` ,
1617+ "/cycles/008/c.css" : `@import url("a.css") layer;` ,
1618+ "/cycles/008/green.css" : `.box { background-color: green; }` ,
1619+ "/cycles/008/red.css" : `.box { background-color: red; }` ,
1620+ "/cycles/008/style.css" : `@import url("b.css"); @import url("c.css");` ,
1621+
1622+ "/data-urls/002/style.css" : `@import url('data:text/css;plain,.box%20%7B%0A%09background-color%3A%20green%3B%0A%7D%0A');` ,
1623+
1624+ "/data-urls/003/style.css" : `@import url('data:text/css,.box%20%7B%0A%09background-color%3A%20green%3B%0A%7D%0A');` ,
1625+
1626+ "/duplicates/001/a.css" : `.box { background-color: green; }` ,
1627+ "/duplicates/001/b.css" : `.box { background-color: red; }` ,
1628+ "/duplicates/001/style.css" : `@import url("a.css"); @import url("b.css"); @import url("a.css");` ,
1629+
1630+ "/duplicates/002/a.css" : `.box { background-color: green; }` ,
1631+ "/duplicates/002/b.css" : `.box { background-color: red; }` ,
1632+ "/duplicates/002/style.css" : `@import url("a.css"); @import url("b.css"); @import url("a.css"); @import url("b.css"); @import url("a.css");` ,
1633+
1634+ "/empty/001/empty.css" : `` ,
1635+ "/empty/001/style.css" : `@import url("./empty.css"); .box { background-color: green; }` ,
1636+
1637+ "/relative-paths/001/a/a.css" : `@import url("../b/b.css")` ,
1638+ "/relative-paths/001/b/b.css" : `.box { background-color: green; }` ,
1639+ "/relative-paths/001/style.css" : `@import url("./a/a.css");` ,
1640+
1641+ "/relative-paths/002/a/a.css" : `@import url("./../b/b.css")` ,
1642+ "/relative-paths/002/b/b.css" : `.box { background-color: green; }` ,
1643+ "/relative-paths/002/style.css" : `@import url("./a/a.css");` ,
1644+
1645+ "/subresource/001/something/images/green.png" : `...` ,
1646+ "/subresource/001/something/styles/green.css" : `.box { background-image: url("../images/green.png"); }` ,
1647+ "/subresource/001/style.css" : `@import url("./something/styles/green.css");` ,
1648+
1649+ "/subresource/002/green.png" : `...` ,
1650+ "/subresource/002/style.css" : `@import url("./styles/green.css");` ,
1651+ "/subresource/002/styles/green.css" : `.box { background-image: url("../green.png"); }` ,
1652+
1653+ "/subresource/004/style.css" : `@import url("./styles/green.css");` ,
1654+ "/subresource/004/styles/green.css" : `.box { background-image: url("green.png"); }` ,
1655+ "/subresource/004/styles/green.png" : `...` ,
1656+
1657+ "/subresource/005/style.css" : `@import url("./styles/green.css");` ,
1658+ "/subresource/005/styles/green.css" : `.box { background-image: url("./green.png"); }` ,
1659+ "/subresource/005/styles/green.png" : `...` ,
1660+
1661+ "/subresource/007/green.png" : `...` ,
1662+ "/subresource/007/style.css" : `.box { background-image: url("./green.png"); }` ,
1663+
1664+ "/url-format/001/default/a.css" : `.box { background-color: green; }` ,
1665+ "/url-format/001/default/style.css" : `@import url(a.css);` ,
1666+
1667+ "/url-format/001/relative-url/a.css" : `.box { background-color: green; }` ,
1668+ "/url-format/001/relative-url/style.css" : `@import url(./a.css);` ,
1669+
1670+ "/url-format/002/default/a.css" : `.box { background-color: green; }` ,
1671+ "/url-format/002/default/style.css" : `@import "a.css";` ,
1672+
1673+ "/url-format/002/relative-url/a.css" : `.box { background-color: green; }` ,
1674+ "/url-format/002/relative-url/style.css" : `@import "./a.css";` ,
1675+
1676+ "/url-format/003/default/a.css" : `.box { background-color: green; }` ,
1677+ "/url-format/003/default/style.css" : `@import url("a.css"` ,
1678+
1679+ "/url-format/003/relative-url/a.css" : `.box { background-color: green; }` ,
1680+ "/url-format/003/relative-url/style.css" : `@import url("./a.css"` ,
1681+
1682+ "/url-fragments/001/a.css" : `.box { background-color: green; }` ,
1683+ "/url-fragments/001/style.css" : `@import url("./a.css#foo");` ,
1684+
1685+ "/url-fragments/002/a.css" : `.box { background-color: green; }` ,
1686+ "/url-fragments/002/b.css" : `.box { background-color: red; }` ,
1687+ "/url-fragments/002/style.css" : `@import url("./a.css#1"); @import url("./b.css#2"); @import url("./a.css#3");` ,
1688+ },
1689+ entryPaths : []string {
1690+ "/001/default/style.css" ,
1691+ "/001/relative-url/style.css" ,
1692+
1693+ "/at-charset/001/style.css" ,
1694+
1695+ "/at-keyframes/001/style.css" ,
1696+
1697+ "/at-layer/001/style.css" ,
1698+ "/at-layer/002/style.css" ,
1699+ "/at-layer/003/style.css" ,
1700+ "/at-layer/004/style.css" ,
1701+ "/at-layer/005/style.css" ,
1702+ "/at-layer/006/style.css" ,
1703+ "/at-layer/007/style.css" ,
1704+ "/at-layer/008/style.css" ,
1705+
1706+ "/at-media/001/default/style.css" ,
1707+ "/at-media/002/style.css" ,
1708+ "/at-media/003/style.css" ,
1709+ "/at-media/004/style.css" ,
1710+ "/at-media/005/style.css" ,
1711+ "/at-media/006/style.css" ,
1712+ "/at-media/007/style.css" ,
1713+ "/at-media/008/style.css" ,
1714+
1715+ "/at-supports/001/style.css" ,
1716+ "/at-supports/002/style.css" ,
1717+ "/at-supports/003/style.css" ,
1718+ "/at-supports/004/style.css" ,
1719+ "/at-supports/005/style.css" ,
1720+
1721+ "/cycles/001/style.css" ,
1722+ "/cycles/002/style.css" ,
1723+ "/cycles/003/style.css" ,
1724+ "/cycles/004/style.css" ,
1725+ "/cycles/005/style.css" ,
1726+ "/cycles/006/style.css" ,
1727+ "/cycles/007/style.css" ,
1728+ "/cycles/008/style.css" ,
1729+
1730+ "/data-urls/002/style.css" ,
1731+ "/data-urls/003/style.css" ,
1732+
1733+ "/duplicates/001/style.css" ,
1734+ "/duplicates/002/style.css" ,
1735+
1736+ "/empty/001/style.css" ,
1737+
1738+ "/relative-paths/001/style.css" ,
1739+ "/relative-paths/002/style.css" ,
1740+
1741+ "/subresource/001/style.css" ,
1742+ "/subresource/002/style.css" ,
1743+ "/subresource/004/style.css" ,
1744+ "/subresource/005/style.css" ,
1745+ "/subresource/007/style.css" ,
1746+
1747+ "/url-format/001/default/style.css" ,
1748+ "/url-format/001/relative-url/style.css" ,
1749+ "/url-format/002/default/style.css" ,
1750+ "/url-format/002/relative-url/style.css" ,
1751+ "/url-format/003/default/style.css" ,
1752+ "/url-format/003/relative-url/style.css" ,
1753+ "/url-fragments/001/style.css" ,
1754+ "/url-fragments/002/style.css" ,
1755+ },
1756+ options : config.Options {
1757+ Mode : config .ModeBundle ,
1758+ AbsOutputDir : "/out" ,
1759+ ExtensionToLoader : map [string ]config.Loader {
1760+ ".css" : config .LoaderCSS ,
1761+ ".png" : config .LoaderBase64 ,
1762+ },
1763+ },
1764+ expectedScanLog : `relative-paths/001/a/a.css: WARNING: Expected ";" but found end of file
1765+ relative-paths/002/a/a.css: WARNING: Expected ";" but found end of file
1766+ url-format/003/default/style.css: WARNING: Expected ")" to go with "("
1767+ url-format/003/default/style.css: NOTE: The unbalanced "(" is here:
1768+ url-format/003/relative-url/style.css: WARNING: Expected ")" to go with "("
1769+ url-format/003/relative-url/style.css: NOTE: The unbalanced "(" is here:
1770+ ` ,
1771+ })
1772+ }
1773+
14321774// This test mainly just makes sure that this scenario doesn't crash
14331775func TestCSSAndJavaScriptCodeSplittingIssue1064 (t * testing.T ) {
14341776 css_suite .expectBundled (t , bundled {
0 commit comments