@csszyx/unplugin 0.14.5 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/README.md +4 -3
  2. package/dist/index.cjs +8 -7
  3. package/dist/index.d.cts +70 -3
  4. package/dist/index.d.mts +70 -3
  5. package/dist/index.mjs +4 -4
  6. package/dist/next-config.d.cts +1 -2
  7. package/dist/next-config.d.mts +1 -2
  8. package/dist/next-prebuild.cjs +9 -5
  9. package/dist/next-prebuild.d.cts +4 -2
  10. package/dist/next-prebuild.d.mts +4 -2
  11. package/dist/next-prebuild.mjs +8 -4
  12. package/dist/next-turbo-loader.cjs +20 -14
  13. package/dist/next-turbo-loader.d.cts +1 -1
  14. package/dist/next-turbo-loader.d.mts +1 -1
  15. package/dist/next-turbo-loader.mjs +19 -13
  16. package/dist/next-watcher.cjs +2 -2
  17. package/dist/next-watcher.d.cts +2 -2
  18. package/dist/next-watcher.d.mts +2 -2
  19. package/dist/next-watcher.mjs +2 -2
  20. package/dist/postcss.cjs +124 -0
  21. package/dist/postcss.d.cts +42 -0
  22. package/dist/postcss.d.mts +42 -0
  23. package/dist/postcss.mjs +107 -0
  24. package/dist/shared/{unplugin.NlPvn5P4.mjs → unplugin.AGR7mihU.mjs} +2 -6
  25. package/dist/shared/{unplugin.BnRf0Tvd.mjs → unplugin.BGufkSFT.mjs} +297 -173
  26. package/dist/shared/{unplugin.BXYakiXt.d.cts → unplugin.BHfqCocB.d.cts} +53 -55
  27. package/dist/shared/{unplugin.BXYakiXt.d.mts → unplugin.BHfqCocB.d.mts} +53 -55
  28. package/dist/shared/{unplugin.RGzhYt-D.cjs → unplugin.BLbrShMZ.cjs} +344 -221
  29. package/dist/shared/{unplugin.DVbPNK3W.cjs → unplugin.BbBYWFGT.cjs} +6 -6
  30. package/dist/shared/{unplugin.BZPdvVcj.mjs → unplugin.BourSpnZ.mjs} +105 -127
  31. package/dist/shared/{unplugin.CPEWNSA0.d.cts → unplugin.C2ilavL1.d.cts} +2 -0
  32. package/dist/shared/{unplugin.CPEWNSA0.d.mts → unplugin.C2ilavL1.d.mts} +2 -0
  33. package/dist/shared/{unplugin.D8BxOOkA.cjs → unplugin.C7i0agiO.cjs} +121 -142
  34. package/dist/shared/{unplugin.CdZxp0x-.d.mts → unplugin.CXCaQ3-s.d.cts} +1 -1
  35. package/dist/shared/{unplugin.xeED_qwh.d.cts → unplugin.CbNydVwv.d.mts} +1 -1
  36. package/dist/shared/unplugin.CqJS0BbD.mjs +211 -0
  37. package/dist/shared/{unplugin.VtXstzEh.cjs → unplugin.DX3rYT4P.cjs} +6 -11
  38. package/dist/shared/{unplugin.Cji6O5jv.cjs → unplugin.Dai5wlZ3.cjs} +27 -19
  39. package/dist/shared/{unplugin.DN95k991.mjs → unplugin.Dbc26ty6.mjs} +2 -2
  40. package/dist/shared/{unplugin.BU0O4IkX.mjs → unplugin.DmCOQc-b.mjs} +22 -16
  41. package/dist/shared/unplugin.KnDCM-sr.cjs +241 -0
  42. package/dist/vite.cjs +4 -4
  43. package/dist/vite.d.cts +2 -2
  44. package/dist/vite.d.mts +1 -1
  45. package/dist/vite.mjs +4 -4
  46. package/dist/webpack.cjs +4 -4
  47. package/dist/webpack.d.cts +2 -1
  48. package/dist/webpack.d.mts +1 -1
  49. package/dist/webpack.mjs +4 -4
  50. package/package.json +19 -9
  51. package/dist/shared/unplugin.B3XoSRB8.mjs +0 -40
  52. package/dist/shared/unplugin.BkRah5Ot.cjs +0 -48
@@ -13,10 +13,10 @@ const svelteAdapter = require('@csszyx/svelte-adapter');
13
13
  const types = require('@csszyx/types');
14
14
  const vueAdapter = require('@csszyx/vue-adapter');
15
15
  const unplugin$1 = require('unplugin');
16
- const transformCache = require('./unplugin.VtXstzEh.cjs');
16
+ const transformCache = require('./unplugin.DX3rYT4P.cjs');
17
17
  const cssMangler = require('../css-mangler.cjs');
18
- const themeGroupsFile = require('./unplugin.D8BxOOkA.cjs');
19
- const htmlEscape = require('./unplugin.BkRah5Ot.cjs');
18
+ const themeGroupsFile = require('./unplugin.C7i0agiO.cjs');
19
+ const safelistSource = require('./unplugin.KnDCM-sr.cjs');
20
20
  const node_zlib = require('node:zlib');
21
21
  const postcss = require('postcss');
22
22
  const valueParser = require('postcss-value-parser');
@@ -37,7 +37,9 @@ function _interopNamespaceCompat(e) {
37
37
  }
38
38
 
39
39
  const fs__namespace = /*#__PURE__*/_interopNamespaceCompat(fs);
40
+ const fs__default = /*#__PURE__*/_interopDefaultCompat(fs);
40
41
  const path__namespace = /*#__PURE__*/_interopNamespaceCompat(path);
42
+ const path__default = /*#__PURE__*/_interopDefaultCompat(path);
41
43
  const postcss__default = /*#__PURE__*/_interopDefaultCompat(postcss);
42
44
  const valueParser__default = /*#__PURE__*/_interopDefaultCompat(valueParser);
43
45
 
@@ -168,7 +170,7 @@ function scanGlobalVarCss(css, options = {}) {
168
170
  filePath,
169
171
  definitions,
170
172
  references,
171
- registered: htmlEscape.sortStrings(registered),
173
+ registered: safelistSource.sortStrings(registered),
172
174
  thirdParty: isThirdPartyCssPath(filePath)
173
175
  };
174
176
  }
@@ -187,7 +189,7 @@ function extractVarReferences(value) {
187
189
  for (const match of value.matchAll(VAR_REFERENCE_RE)) {
188
190
  references.add(match[1]);
189
191
  }
190
- return htmlEscape.sortStrings(references);
192
+ return safelistSource.sortStrings(references);
191
193
  }
192
194
  function isThirdPartyCssPath(filePath) {
193
195
  return filePath.split(/[\\/]/).includes("node_modules");
@@ -228,7 +230,7 @@ function planGlobalVarAliases(input) {
228
230
  entries.push({
229
231
  original,
230
232
  alias,
231
- scopes: htmlEscape.sortStrings(
233
+ scopes: safelistSource.sortStrings(
232
234
  new Set((definitions.get(original) ?? []).map((definition) => definition.scopeId))
233
235
  )
234
236
  });
@@ -263,7 +265,7 @@ function collectCandidates(input, definitions) {
263
265
  }
264
266
  }
265
267
  }
266
- return htmlEscape.sortStrings(candidates);
268
+ return safelistSource.sortStrings(candidates);
267
269
  }
268
270
  function validateCandidates(candidates, definitions, reserved, aliasPrefix) {
269
271
  const diagnostics = [];
@@ -541,8 +543,8 @@ function createRSCModuleRecord(code, id) {
541
543
  }
542
544
  function deleteRSCModuleRecord(records, id) {
543
545
  const normalized = normalizeModuleId(id);
544
- const clean = transformCache.normalizePathSeparators(id.split("?")[0] ?? id);
545
- const resolved = transformCache.normalizePathSeparators(path__namespace.resolve(clean));
546
+ const clean = safelistSource.normalizePathSeparators(id.split("?")[0] ?? id);
547
+ const resolved = safelistSource.normalizePathSeparators(path__namespace.resolve(clean));
546
548
  pruneRSCModulePathCaches(/* @__PURE__ */ new Set([normalized, resolved, clean]));
547
549
  let deleted = records.delete(normalized);
548
550
  if (resolved !== normalized) {
@@ -588,7 +590,7 @@ const APP_ROUTER_ENTRIES = /* @__PURE__ */ new Set([
588
590
  "route"
589
591
  ]);
590
592
  function isNextAppRouterEntry(id) {
591
- const clean = transformCache.normalizePathSeparators(id.split("?")[0] ?? id);
593
+ const clean = safelistSource.normalizePathSeparators(id.split("?")[0] ?? id);
592
594
  if (!clean.includes("/app/") && !clean.startsWith("app/")) return false;
593
595
  const basename = clean.split("/").pop() ?? "";
594
596
  const dotIdx = basename.indexOf(".");
@@ -943,9 +945,9 @@ function normalizeModuleId(id) {
943
945
  }
944
946
  let normalized;
945
947
  try {
946
- normalized = transformCache.normalizePathSeparators(fs__namespace.realpathSync.native(clean));
948
+ normalized = safelistSource.normalizePathSeparators(fs__namespace.realpathSync.native(clean));
947
949
  } catch {
948
- normalized = transformCache.normalizePathSeparators(path__namespace.resolve(clean));
950
+ normalized = safelistSource.normalizePathSeparators(path__namespace.resolve(clean));
949
951
  }
950
952
  normalizedModuleIdCache.set(clean, normalized);
951
953
  return normalized;
@@ -991,7 +993,7 @@ function resolveLocalModule(importer, source) {
991
993
  }
992
994
  function pruneRSCModulePathCaches(moduleIds) {
993
995
  for (const [key, value] of normalizedModuleIdCache) {
994
- const normalizedKey = transformCache.normalizePathSeparators(key);
996
+ const normalizedKey = safelistSource.normalizePathSeparators(key);
995
997
  if (moduleIds.has(value) || moduleIds.has(normalizedKey)) {
996
998
  normalizedModuleIdCache.delete(key);
997
999
  }
@@ -1619,10 +1621,10 @@ An unread option is silent, so whatever you configured it for is not happening.`
1619
1621
  const GLOB_MAGIC_RE = /[*?[\]{}]/;
1620
1622
  const DEFAULT_IGNORED_DIRS = /* @__PURE__ */ new Set(["node_modules", ".git", ".next", ".turbo", "dist", "build"]);
1621
1623
  function normalizeFileId(id) {
1622
- return transformCache.normalizePathSeparators(id.split(/[?#]/, 1)[0]);
1624
+ return safelistSource.normalizePathSeparators(id.split(/[?#]/, 1)[0]);
1623
1625
  }
1624
1626
  function normalizeRoot(rootDir) {
1625
- return transformCache.normalizePathSeparators(path__namespace.resolve(rootDir));
1627
+ return safelistSource.normalizePathSeparators(path__namespace.resolve(rootDir));
1626
1628
  }
1627
1629
  function hasGlobMagic(pattern) {
1628
1630
  return GLOB_MAGIC_RE.test(pattern);
@@ -1631,7 +1633,7 @@ function escapeRegExp(ch) {
1631
1633
  return /[|\\{}()[\]^$+?.]/.test(ch) ? `\\${ch}` : ch;
1632
1634
  }
1633
1635
  function globToRegExp(pattern) {
1634
- const normalized = transformCache.normalizePathSeparators(pattern);
1636
+ const normalized = safelistSource.normalizePathSeparators(pattern);
1635
1637
  let out = "^";
1636
1638
  for (let i = 0; i < normalized.length; i++) {
1637
1639
  const ch = normalized[i];
@@ -1654,7 +1656,7 @@ function globToRegExp(pattern) {
1654
1656
  function relativeToRoot(file, rootDir) {
1655
1657
  const root = normalizeRoot(rootDir);
1656
1658
  const normalizedFile = normalizeFileId(file);
1657
- return transformCache.normalizePathSeparators(path__namespace.posix.relative(root, normalizedFile));
1659
+ return safelistSource.normalizePathSeparators(path__namespace.posix.relative(root, normalizedFile));
1658
1660
  }
1659
1661
  function matchesPattern(id, pattern, rootDir) {
1660
1662
  const file = normalizeFileId(id);
@@ -1663,7 +1665,7 @@ function matchesPattern(id, pattern, rootDir) {
1663
1665
  pattern.lastIndex = 0;
1664
1666
  return pattern.test(file) || pattern.test(relative);
1665
1667
  }
1666
- const normalizedPattern = transformCache.normalizePathSeparators(pattern);
1668
+ const normalizedPattern = safelistSource.normalizePathSeparators(pattern);
1667
1669
  if (hasGlobMagic(normalizedPattern)) {
1668
1670
  const re = globToRegExp(normalizedPattern);
1669
1671
  return re.test(file) || re.test(relative);
@@ -1727,18 +1729,36 @@ function expandFilePatterns(rootDir, patterns) {
1727
1729
  }
1728
1730
  }
1729
1731
  }
1730
- return htmlEscape.sortStrings(files);
1732
+ return safelistSource.sortStrings(files);
1733
+ }
1734
+
1735
+ const BACKSLASH = String.fromCodePoint(92);
1736
+ function unicodeEscape(hexadecimal) {
1737
+ return `${BACKSLASH}u${hexadecimal}`;
1738
+ }
1739
+ function replaceEveryLiteral(value, search, replacement) {
1740
+ return value.replaceAll(search, () => replacement);
1741
+ }
1742
+ function escapeSingleQuotedString(value) {
1743
+ let escaped = replaceEveryLiteral(value, BACKSLASH, BACKSLASH.repeat(2));
1744
+ escaped = replaceEveryLiteral(escaped, "'", `${BACKSLASH}'`);
1745
+ escaped = replaceEveryLiteral(escaped, "\r", `${BACKSLASH}r`);
1746
+ return replaceEveryLiteral(escaped, "\n", `${BACKSLASH}n`);
1747
+ }
1748
+ function escapeDoubleQuotedString(value) {
1749
+ const escaped = replaceEveryLiteral(value, BACKSLASH, BACKSLASH.repeat(2));
1750
+ return replaceEveryLiteral(escaped, '"', `${BACKSLASH}"`);
1731
1751
  }
1732
1752
 
1733
1753
  const LINE_SEPARATOR$1 = String.fromCodePoint(8232);
1734
1754
  const PARAGRAPH_SEPARATOR$1 = String.fromCodePoint(8233);
1735
1755
  function safeJsonForScriptTag(value, prettyPrint = false) {
1736
1756
  const json = prettyPrint ? JSON.stringify(value, null, 2) : JSON.stringify(value);
1737
- let escaped = htmlEscape.replaceEveryLiteral(json, "<", htmlEscape.unicodeEscape("003C"));
1738
- escaped = htmlEscape.replaceEveryLiteral(escaped, ">", htmlEscape.unicodeEscape("003E"));
1739
- escaped = htmlEscape.replaceEveryLiteral(escaped, "&", htmlEscape.unicodeEscape("0026"));
1740
- escaped = htmlEscape.replaceEveryLiteral(escaped, LINE_SEPARATOR$1, htmlEscape.unicodeEscape("2028"));
1741
- return htmlEscape.replaceEveryLiteral(escaped, PARAGRAPH_SEPARATOR$1, htmlEscape.unicodeEscape("2029"));
1757
+ let escaped = replaceEveryLiteral(json, "<", unicodeEscape("003C"));
1758
+ escaped = replaceEveryLiteral(escaped, ">", unicodeEscape("003E"));
1759
+ escaped = replaceEveryLiteral(escaped, "&", unicodeEscape("0026"));
1760
+ escaped = replaceEveryLiteral(escaped, LINE_SEPARATOR$1, unicodeEscape("2028"));
1761
+ return replaceEveryLiteral(escaped, PARAGRAPH_SEPARATOR$1, unicodeEscape("2029"));
1742
1762
  }
1743
1763
  function injectHtmlOpeningAttr(html, attr) {
1744
1764
  const lower = html.toLowerCase();
@@ -1764,31 +1784,22 @@ function injectChecksum(html, checksum, minify = false) {
1764
1784
  const attrName = minify ? "data-sz-cs" : "data-sz-checksum";
1765
1785
  return injectHtmlOpeningAttr(html, ` ${attrName}="${checksum}"`);
1766
1786
  }
1767
- function injectMangleMapScript(html, mangleMap, options = {}) {
1768
- const {
1769
- prettyPrint = false,
1770
- varMangleMap = {},
1771
- globalVarAliasPrefix = types.CSSZYX_GLOBAL_ALIAS_PREFIX,
1772
- installRuntimeObject = true
1773
- } = options;
1774
- const checksumMap = createHydrationMangleMap(mangleMap, varMangleMap);
1775
- const jsonContent = safeJsonForScriptTag(checksumMap, prettyPrint);
1776
- const varMapContent = safeJsonForScriptTag(varMangleMap);
1777
- const reuseChecksumPayload = Object.keys(varMangleMap).length === 0;
1778
- const classMapExpr = reuseChecksumPayload ? '(function(){var e=document.getElementById("__CSSZYX_MANGLE_MAP__");return e?JSON.parse(e.textContent):{}})()' : safeJsonForScriptTag(mangleMap);
1779
- const scriptTag = `<script id="__CSSZYX_MANGLE_MAP__" type="application/json">${jsonContent}<\/script>`;
1780
- const prefixContent = safeJsonForScriptTag(globalVarAliasPrefix);
1781
- const debugScript = `<script>(function(){var m=${classMapExpr};var vm=${varMapContent};var gp=${prefixContent};var r={};var vr={};for(var k in m)r[m[k]]=k;for(var vk in vm){var vv=vm[vk];var vs=Array.isArray(vv)?vv:[vv];for(var vi=0;vi<vs.length;vi++)(vr[vs[vi]]||(vr[vs[vi]]=[])).push(vk)}var cs=document.documentElement.getAttribute("data-sz-checksum")||"";window.__csszyx={mangleMap:m,varMangleMap:vm,checksum:cs,decode:function(c){return r[c]},encode:function(c){return m[c]},decodeVar:function(v){return vr[v]||[]},encodeVar:function(v){return vm[v]},decodeGlobalVar:function(v){var a=vr[v]||[];return v.indexOf(gp)===0?a[0]:void 0},decodeAll:function(el){return(el.className||"").split(" ").map(function(c){return r[c]||c})}}})()<\/script>`;
1782
- const combined = installRuntimeObject ? `${scriptTag}
1783
- ${debugScript}` : scriptTag;
1787
+ function withScriptTag(html, scriptTag) {
1784
1788
  if (html.includes("</head>")) {
1785
- return html.replace("</head>", `${combined}
1789
+ return html.replace("</head>", `${scriptTag}
1786
1790
  </head>`);
1787
- } else if (html.includes("</html>")) {
1788
- return html.replace("</html>", `${combined}
1791
+ }
1792
+ if (html.includes("</html>")) {
1793
+ return html.replace("</html>", `${scriptTag}
1789
1794
  </html>`);
1790
1795
  }
1791
- return html + combined;
1796
+ return html + scriptTag;
1797
+ }
1798
+ function injectMangleMapScript(html, mangleMap, options = {}) {
1799
+ const { prettyPrint = false, varMangleMap = {} } = options;
1800
+ const checksumMap = createHydrationMangleMap(mangleMap, varMangleMap);
1801
+ const scriptTag = `<script id="__CSSZYX_MANGLE_MAP__" type="application/json">${safeJsonForScriptTag(checksumMap, prettyPrint)}<\/script>`;
1802
+ return withScriptTag(html, scriptTag);
1792
1803
  }
1793
1804
  function injectMangleMapAttribute(html, mangleMap, minify = false, varMangleMap = {}) {
1794
1805
  const attrName = minify ? "data-sz-m" : "data-sz-map";
@@ -1835,7 +1846,7 @@ function buildRecoveryManifest(tokens, options) {
1835
1846
  const stripped = options.production === true;
1836
1847
  const strippedDevOnlyPaths = [];
1837
1848
  const sorted = {};
1838
- const sortedKeys = htmlEscape.sortStrings(tokens.keys());
1849
+ const sortedKeys = safelistSource.sortStrings(tokens.keys());
1839
1850
  for (const key of sortedKeys) {
1840
1851
  const data = tokens.get(key);
1841
1852
  if (!data) {
@@ -1862,27 +1873,97 @@ function injectRecoveryManifest(html, manifest) {
1862
1873
  }
1863
1874
  const json = JSON.stringify(manifest);
1864
1875
  const scriptTag = `<script id="__SZ_RECOVERY_MANIFEST__" type="application/json">${json}<\/script>`;
1865
- if (html.includes("</head>")) {
1866
- return html.replace("</head>", `${scriptTag}
1867
- </head>`);
1868
- } else if (html.includes("</html>")) {
1869
- return html.replace("</html>", `${scriptTag}
1870
- </html>`);
1871
- }
1872
- return html + scriptTag;
1876
+ return withScriptTag(html, scriptTag);
1873
1877
  }
1874
1878
 
1875
1879
  const LINE_SEPARATOR = String.fromCodePoint(8232);
1876
1880
  const PARAGRAPH_SEPARATOR = String.fromCodePoint(8233);
1877
1881
  function escapeJsonForInlineScript(json) {
1878
- let escaped = htmlEscape.replaceEveryLiteral(json, "`", htmlEscape.unicodeEscape("0060"));
1879
- escaped = htmlEscape.replaceEveryLiteral(escaped, "$", htmlEscape.unicodeEscape("0024"));
1880
- escaped = htmlEscape.replaceEveryLiteral(escaped, "<", htmlEscape.unicodeEscape("003c"));
1881
- escaped = htmlEscape.replaceEveryLiteral(escaped, LINE_SEPARATOR, htmlEscape.unicodeEscape("2028"));
1882
- return htmlEscape.replaceEveryLiteral(escaped, PARAGRAPH_SEPARATOR, htmlEscape.unicodeEscape("2029"));
1882
+ let escaped = replaceEveryLiteral(json, "`", unicodeEscape("0060"));
1883
+ escaped = replaceEveryLiteral(escaped, "$", unicodeEscape("0024"));
1884
+ escaped = replaceEveryLiteral(escaped, "<", unicodeEscape("003c"));
1885
+ escaped = replaceEveryLiteral(escaped, LINE_SEPARATOR, unicodeEscape("2028"));
1886
+ return replaceEveryLiteral(escaped, PARAGRAPH_SEPARATOR, unicodeEscape("2029"));
1887
+ }
1888
+ function escapeJsonForStringLiteral(json) {
1889
+ let escaped = replaceEveryLiteral(json, "\\", unicodeEscape("005c"));
1890
+ for (const [character, code] of [
1891
+ ['"', "0022"],
1892
+ ["'", "0027"],
1893
+ ["`", "0060"],
1894
+ ["$", "0024"],
1895
+ ["<", "003c"],
1896
+ [">", "003e"],
1897
+ [LINE_SEPARATOR, "2028"],
1898
+ [PARAGRAPH_SEPARATOR, "2029"]
1899
+ ]) {
1900
+ escaped = replaceEveryLiteral(escaped, character, unicodeEscape(code));
1901
+ }
1902
+ return escaped;
1883
1903
  }
1884
1904
  function escapeForDoubleQuotedString(value) {
1885
- return htmlEscape.escapeDoubleQuotedString(value);
1905
+ return escapeDoubleQuotedString(value);
1906
+ }
1907
+
1908
+ function createLazyAggregate(build, initial) {
1909
+ const entries = /* @__PURE__ */ new Map();
1910
+ let current = initial;
1911
+ let dirty = false;
1912
+ return {
1913
+ entries,
1914
+ set(key, entry) {
1915
+ entries.set(key, entry);
1916
+ dirty = true;
1917
+ },
1918
+ delete(key) {
1919
+ if (entries.delete(key)) dirty = true;
1920
+ },
1921
+ get() {
1922
+ if (dirty) {
1923
+ current = build(entries);
1924
+ dirty = false;
1925
+ }
1926
+ return current;
1927
+ }
1928
+ };
1929
+ }
1930
+
1931
+ function needsRuntimeMangleRegistration(manglingEnabled, mangleMap) {
1932
+ if (!manglingEnabled) return false;
1933
+ return Object.keys(mangleMap).length > 0;
1934
+ }
1935
+ function removedMangleMapDeliveryMessage() {
1936
+ return "[csszyx] production.mangleMapDelivery has been removed and is ignored. The runtime mangle map is always registered from inside the JS bundle now, on every lane, so the built HTML never carries an executable inline <script> and a strict script-src 'self' policy needs no exception. Delete the option. (`window.__csszyx` is now opt-in through `production.mangleDebugGlobal`.)";
1937
+ }
1938
+
1939
+ const MANGLE_RUNTIME_FILE = "mangle-runtime.mjs";
1940
+ function ensureMangleRuntimeFile(outputDir, globalVarAliasPrefix, exposeDebugGlobal) {
1941
+ const target = path__default.join(outputDir, MANGLE_RUNTIME_FILE);
1942
+ const staging = `${target}.${process.pid}.tmp`;
1943
+ try {
1944
+ fs__default.mkdirSync(outputDir, { recursive: true });
1945
+ fs__default.writeFileSync(
1946
+ staging,
1947
+ themeGroupsFile.createMangleRuntimeModule(globalVarAliasPrefix, exposeDebugGlobal),
1948
+ "utf8"
1949
+ );
1950
+ fs__default.renameSync(staging, target);
1951
+ return target;
1952
+ } catch {
1953
+ try {
1954
+ fs__default.rmSync(staging, { force: true });
1955
+ } catch {
1956
+ }
1957
+ return null;
1958
+ }
1959
+ }
1960
+ function applyMangleRuntimeEntry(compiler, context, file, onRegistered) {
1961
+ const EntryPlugin = compiler.webpack?.EntryPlugin;
1962
+ if (EntryPlugin === void 0) {
1963
+ return;
1964
+ }
1965
+ new EntryPlugin(context, file, { name: void 0 }).apply(compiler);
1966
+ onRegistered();
1886
1967
  }
1887
1968
 
1888
1969
  function createMangleSizeAccount() {
@@ -1920,7 +2001,7 @@ function recordCodePair(account, before, after) {
1920
2001
  account.codeGzAfter += gzipBytes(after);
1921
2002
  }
1922
2003
  function computeMangleSizeVerdict(account, mapPayload) {
1923
- const channels = htmlEscape.sortStrings(account.channels);
2004
+ const channels = safelistSource.sortStrings(account.channels);
1924
2005
  const mapCost = gzipBytes(mapPayload) * channels.length;
1925
2006
  const cssSaving = account.cssGzBefore - account.cssGzAfter;
1926
2007
  const codeSaving = account.codeGzBefore - account.codeGzAfter;
@@ -1932,7 +2013,7 @@ function mangleSizeMessage(verdict) {
1932
2013
  const cssPart = verdict.cssSaving >= 0 ? `the mangled CSS saves ${verdict.cssSaving} B` : `the mangled CSS COSTS ${-verdict.cssSaving} B (short tokens compress worse than the names they replaced)`;
1933
2014
  const codePart = verdict.codeSaving >= 0 ? `the shortened classes in code save ${verdict.codeSaving} B` : `the shortened classes in code COST ${-verdict.codeSaving} B`;
1934
2015
  const channelPart = verdict.channels.length > 1 ? `${verdict.channels.join(" + ")} (${verdict.channels.length} copies)` : verdict.channels[0];
1935
- return `[csszyx] production.mangle is making this build BIGGER: +${verdict.net} B gzipped. The runtime mangle map costs ${verdict.mapCost} B via ${channelPart}, while ${cssPart} and ${codePart}. Mangling is a name-obfuscation feature; over a compressed response it does not reduce payload, because utility class names compress far better than the map they need. If you enabled it for size, set \`production.mangle: false\`. If you enabled it to hide class names, this is the expected price and you can ignore this. Narrowing \`production.mangleMapDelivery\` removes a map copy when only one channel is needed.`;
2016
+ return `[csszyx] production.mangle is making this build BIGGER: +${verdict.net} B gzipped. The runtime mangle map costs ${verdict.mapCost} B via ${channelPart}, while ${cssPart} and ${codePart}. Mangling is a name-obfuscation feature; over a compressed response it does not reduce payload, because utility class names compress far better than the map they need. If you enabled it for size, set \`production.mangle: false\`. If you enabled it to hide class names, this is the expected price and you can ignore this. Two copies is not a misconfiguration: the bundle carries the map the runtime reads, and the HTML carries the same census for the hydration checksum.`;
1936
2017
  }
1937
2018
 
1938
2019
  function isParserMode(value) {
@@ -1993,10 +2074,10 @@ function isSameFileVersion(before, after) {
1993
2074
  function generateThemeDts(opts) {
1994
2075
  const { theme, sourceFiles } = opts;
1995
2076
  const timestamp = (/* @__PURE__ */ new Date()).toISOString();
1996
- const withoutCarriageReturns = htmlEscape.replaceEveryLiteral(sourceFiles.join(", "), "\r", " ");
1997
- const sources = htmlEscape.replaceEveryLiteral(withoutCarriageReturns, "\n", " ");
1998
- const toUnion = (tokens) => tokens.map((t) => `'${htmlEscape.escapeSingleQuotedString(t)}'`).join(" | ");
1999
- const quoteKey = (key) => /^[a-z_$][\w$]*$/i.test(key) ? key : `'${htmlEscape.escapeSingleQuotedString(key)}'`;
2077
+ const withoutCarriageReturns = replaceEveryLiteral(sourceFiles.join(", "), "\r", " ");
2078
+ const sources = replaceEveryLiteral(withoutCarriageReturns, "\n", " ");
2079
+ const toUnion = (tokens) => tokens.map((t) => `'${escapeSingleQuotedString(t)}'`).join(" | ");
2080
+ const quoteKey = (key) => /^[a-z_$][\w$]*$/i.test(key) ? key : `'${escapeSingleQuotedString(key)}'`;
2000
2081
  const entries = [];
2001
2082
  if (theme.colors.length > 0) {
2002
2083
  entries.push(` colors: ${toUnion(theme.colors)};`);
@@ -2103,9 +2184,9 @@ let _hasWarnedTsConfig = false;
2103
2184
  let _hasWarnedTransformCacheVersion = false;
2104
2185
  let _hasWarnedNativeFallback = false;
2105
2186
  const _loggedActiveParsers = /* @__PURE__ */ new Set();
2106
- const requireFromHere = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('shared/unplugin.RGzhYt-D.cjs', document.baseURI).href)));
2187
+ const requireFromHere = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('shared/unplugin.BLbrShMZ.cjs', document.baseURI).href)));
2107
2188
  const PLUGIN_VERSION = findPackageVersionFromFile(
2108
- node_url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('shared/unplugin.RGzhYt-D.cjs', document.baseURI).href))),
2189
+ node_url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('shared/unplugin.BLbrShMZ.cjs', document.baseURI).href))),
2109
2190
  UNKNOWN_PACKAGE_VERSION
2110
2191
  );
2111
2192
  const COMPILER_VERSION = findPackageVersionFromModule("@csszyx/compiler", UNKNOWN_PACKAGE_VERSION);
@@ -2133,41 +2214,6 @@ function resolveNativeCacheIdentity() {
2133
2214
  }
2134
2215
  const BENCH_TRACE_ENABLED = process.env.CSSZYX_BENCH_TRACE === "1";
2135
2216
  const BENCH_TRACE_FILE = process.env.CSSZYX_BENCH_TRACE_FILE;
2136
- function appendTailwindSourceDirective(code, relPath) {
2137
- const directive = `@source "${relPath}";`;
2138
- if (code.includes(directive)) {
2139
- return null;
2140
- }
2141
- const separator = code.length === 0 || code.endsWith("\n") ? "" : "\n";
2142
- return `${code}${separator}${directive}
2143
- `;
2144
- }
2145
- function stripCssBlockComments(code) {
2146
- const SLASH = 47;
2147
- const STAR = 42;
2148
- let out = "";
2149
- let last = 0;
2150
- let i = 0;
2151
- const n = code.length;
2152
- while (i < n) {
2153
- if (code.codePointAt(i) === SLASH && code.codePointAt(i + 1) === STAR) {
2154
- out += code.slice(last, i);
2155
- i += 2;
2156
- while (i < n && !(code.codePointAt(i) === STAR && code.codePointAt(i + 1) === SLASH)) {
2157
- i++;
2158
- }
2159
- i += 2;
2160
- last = i;
2161
- } else {
2162
- i++;
2163
- }
2164
- }
2165
- return out + code.slice(last);
2166
- }
2167
- function cssImportsTailwind(code) {
2168
- const withoutBlockComments = stripCssBlockComments(code);
2169
- return /@import\s+["']tailwindcss(?:\/[^"']*)?["']/.test(withoutBlockComments);
2170
- }
2171
2217
  function hasInjectableTailwindCandidate(classes) {
2172
2218
  for (const c of classes) {
2173
2219
  if (c.length >= 2 && /^[a-z]/.test(c)) {
@@ -2231,7 +2277,7 @@ function tailwindImportScopesContent(css) {
2231
2277
  return false;
2232
2278
  }
2233
2279
  function cssHasContentScope(code) {
2234
- const s = stripCssBlockComments(code);
2280
+ const s = safelistSource.stripCssBlockComments(code);
2235
2281
  return tailwindImportScopesContent(s) || /@source\s+not\b/.test(s);
2236
2282
  }
2237
2283
  function isMonorepoPackage(root) {
@@ -2291,7 +2337,7 @@ function emitMissingCssFallback(quiet, message, id, emit) {
2291
2337
  ${message}`);
2292
2338
  }
2293
2339
  function normalizeForMatch(p) {
2294
- const n = transformCache.normalizePathSeparators(p);
2340
+ const n = safelistSource.normalizePathSeparators(p);
2295
2341
  return n.length > 1 && n.endsWith("/") ? n.slice(0, -1) : n;
2296
2342
  }
2297
2343
  function findJsxExpressionEnd(code, bodyStart) {
@@ -2418,15 +2464,6 @@ function watchModeMangleMessage() {
2418
2464
  function realContentHashDisabledMessage() {
2419
2465
  return "[csszyx] optimization.realContentHash is off while production.mangle is on. csszyx mangles assets after webpack computes their content hashes, and realContentHash is what recomputes those hashes from the final bytes. Without it, two builds that differ only by mangling emit the same filenames with different contents and caches keep serving the old file.";
2420
2466
  }
2421
- function computeSafelistRelPath(rootDir, safelistFilename, cssId) {
2422
- const safelistPath = transformCache.normalizePathSeparators(path__namespace.join(rootDir, safelistFilename));
2423
- const cssDir = transformCache.normalizePathSeparators(path__namespace.dirname(cssId));
2424
- let relPath = path__namespace.posix.relative(cssDir, safelistPath);
2425
- if (!relPath.startsWith(".")) {
2426
- relPath = `./${relPath}`;
2427
- }
2428
- return relPath;
2429
- }
2430
2467
  function cssVariableEntries(result) {
2431
2468
  const entries = [];
2432
2469
  for (const [original, value] of result.cssVariableMap ?? []) {
@@ -2447,7 +2484,6 @@ function recordFileVarMangleEntries(state, filename, entries) {
2447
2484
  } else {
2448
2485
  state.varMangleEntriesByFile.set(normalizedFilename, entries);
2449
2486
  }
2450
- state.varMangleMap = buildVarMangleMap(state.varMangleEntriesByFile);
2451
2487
  }
2452
2488
  function shouldTrackGlobalVarSources(config) {
2453
2489
  return config?.enabled === true;
@@ -2682,7 +2718,6 @@ function recordFileCSSVariableMetrics(state, filename, code) {
2682
2718
  state.cssVarMetricsByFile.delete(normalizedFilename);
2683
2719
  }
2684
2720
  }
2685
- state.cssVarMetrics = buildCSSVariableMetrics(state.cssVarMetricsByFile);
2686
2721
  }
2687
2722
  function collectCSSVariableMetrics(code) {
2688
2723
  const componentUses = /* @__PURE__ */ new Map();
@@ -2843,7 +2878,7 @@ function findPackageVersionFromFile(file, fallback) {
2843
2878
  }
2844
2879
  }
2845
2880
  function normalizeSourceFilename(filename) {
2846
- return transformCache.normalizePathSeparators(filename);
2881
+ return safelistSource.normalizePathSeparators(filename);
2847
2882
  }
2848
2883
  const SCRIPT_ID_EXTENSIONS = [".ts", ".tsx", ".js", ".jsx"];
2849
2884
  const SOURCE_MODULE_EXTENSIONS = [...SCRIPT_ID_EXTENSIONS, ".cts", ".mts", ".cjs", ".mjs"];
@@ -3115,20 +3150,18 @@ function createCsszyxPlugins(options = {}) {
3115
3150
  let specifierAliases = [];
3116
3151
  const mangleReserved = new Set(options.production?.mangleExclude ?? []);
3117
3152
  let mangleMapFrozen = false;
3153
+ let prescanSawServerModule = false;
3154
+ let skipRscRecords = false;
3155
+ let lastPrescanCacheMisses = 0;
3118
3156
  let frozenOwnedClasses = /* @__PURE__ */ new Set();
3119
3157
  let frozenAuthoredClasses = /* @__PURE__ */ new Set();
3120
3158
  let cssRewrittenInTransform = false;
3121
3159
  let projectCssFiles = [];
3122
3160
  const transformMangledSources = /* @__PURE__ */ new Set();
3123
3161
  const transformExternalClasses = /* @__PURE__ */ new Set();
3124
- const mangleMapDelivery = options.production?.mangleMapDelivery ?? "both";
3125
- if (!["both", "html", "bundle"].includes(mangleMapDelivery)) {
3126
- throw new Error(
3127
- `[csszyx] production.mangleMapDelivery must be 'both', 'html' or 'bundle'; got ${JSON.stringify(mangleMapDelivery)}.`
3128
- );
3162
+ if (options.production?.mangleMapDelivery !== void 0) {
3163
+ console.warn(removedMangleMapDeliveryMessage());
3129
3164
  }
3130
- const deliverMapInHtml = mangleMapDelivery !== "bundle";
3131
- const deliverMapInBundle = mangleMapDelivery !== "html";
3132
3165
  const sizeAccount = createMangleSizeAccount();
3133
3166
  const astBudgetOverride = options.build?.astBudgetLimit;
3134
3167
  const prescanAstBudget = astBudgetOverride ?? 5e5;
@@ -3139,7 +3172,6 @@ function createCsszyxPlugins(options = {}) {
3139
3172
  const globalVarMangleConfig = options.production?.mangleGlobalVars;
3140
3173
  const globalVarSourceTrackingEnabled = shouldTrackGlobalVarSources(globalVarMangleConfig);
3141
3174
  const globalVarAliasPrefix = globalVarMangleConfig?.aliasPrefix ?? types.CSSZYX_GLOBAL_ALIAS_PREFIX;
3142
- const encodedGlobalVarAliasPrefix = encodeURIComponent(globalVarAliasPrefix);
3143
3175
  const earlyGlobalVarAliasEntries = createEarlyGlobalVarAliasEntries(
3144
3176
  globalVarMangleConfig,
3145
3177
  globalVarAliasPrefix
@@ -3194,12 +3226,21 @@ function createCsszyxPlugins(options = {}) {
3194
3226
  const transformMemoryCache = /* @__PURE__ */ new Map();
3195
3227
  let transformMemoryCacheCodeChars = 0;
3196
3228
  const prescanResultHandoff = /* @__PURE__ */ new Map();
3229
+ const varMangleEntries = createLazyAggregate(
3230
+ buildVarMangleMap,
3231
+ Object.fromEntries(earlyGlobalVarAliasEntries)
3232
+ );
3233
+ const cssVarMetricTotals = createLazyAggregate(
3234
+ buildCSSVariableMetrics,
3235
+ emptyCSSVariableMetrics()
3236
+ );
3197
3237
  const state = {
3198
3238
  classes: /* @__PURE__ */ new Set(),
3199
3239
  parsedTheme: null,
3200
3240
  scanCssTheme: null,
3201
3241
  autoThemeCssFiles: [],
3202
3242
  sawTailwindEntry: false,
3243
+ tailwindEntryFiles: /* @__PURE__ */ new Set(),
3203
3244
  sawAnyCss: false,
3204
3245
  tailwindWarningEmitted: false,
3205
3246
  tailwindEntryScoped: false,
@@ -3213,10 +3254,14 @@ function createCsszyxPlugins(options = {}) {
3213
3254
  ownedClasses: /* @__PURE__ */ new Set(),
3214
3255
  authoredClasses: /* @__PURE__ */ new Set(),
3215
3256
  mangleMap: {},
3216
- varMangleEntriesByFile: /* @__PURE__ */ new Map(),
3217
- varMangleMap: Object.fromEntries(earlyGlobalVarAliasEntries),
3218
- cssVarMetricsByFile: /* @__PURE__ */ new Map(),
3219
- cssVarMetrics: emptyCSSVariableMetrics(),
3257
+ varMangleEntriesByFile: varMangleEntries,
3258
+ get varMangleMap() {
3259
+ return varMangleEntries.get();
3260
+ },
3261
+ cssVarMetricsByFile: cssVarMetricTotals,
3262
+ get cssVarMetrics() {
3263
+ return cssVarMetricTotals.get();
3264
+ },
3220
3265
  checksum: "",
3221
3266
  finalized: false,
3222
3267
  rootDir: process.cwd(),
@@ -3228,7 +3273,7 @@ function createCsszyxPlugins(options = {}) {
3228
3273
  if (earlyGlobalVarAliasEntries.length > 0) {
3229
3274
  state.varMangleEntriesByFile.set(GLOBAL_VAR_ALIAS_MAP_OWNER, earlyGlobalVarAliasEntries);
3230
3275
  }
3231
- const SAFELIST_FILENAME = "csszyx-classes.html";
3276
+ const SAFELIST_FILENAME = safelistSource.SAFELIST_FILE;
3232
3277
  const SOURCE_EXTENSIONS = /* @__PURE__ */ new Set([
3233
3278
  ".tsx",
3234
3279
  ".jsx",
@@ -3381,6 +3426,7 @@ function createCsszyxPlugins(options = {}) {
3381
3426
  );
3382
3427
  if (cached) return cached;
3383
3428
  }
3429
+ lastPrescanCacheMisses++;
3384
3430
  const execution = runConfiguredParser(source, effectiveFilename, compilerOptions);
3385
3431
  if (cacheEnabled && cacheKey && execution.cacheable) {
3386
3432
  transformCache.writeTransformCache(cacheRoot, cacheInput, execution.result, cacheKey);
@@ -3467,6 +3513,7 @@ function createCsszyxPlugins(options = {}) {
3467
3513
  if (cacheEnabled) evictTransformCacheOnce();
3468
3514
  compiler.ensureRustTransformAvailable();
3469
3515
  const misses = collectRustPrescanMisses(batchable, compilerOptions, cacheRoot, results);
3516
+ lastPrescanCacheMisses += misses.length;
3470
3517
  if (misses.length > 0) {
3471
3518
  try {
3472
3519
  runRustPrescanBatch(misses, compilerOptions, cacheRoot, results);
@@ -3610,12 +3657,7 @@ function createCsszyxPlugins(options = {}) {
3610
3657
  return;
3611
3658
  }
3612
3659
  const safelistPath = path__namespace.join(state.rootDir, SAFELIST_FILENAME);
3613
- const classNames = Array.from(classes);
3614
- const classList = htmlEscape.escapeHtmlAttribute(classNames.join(" "));
3615
- const content = `<!-- Auto-generated by csszyx \u2014 DO NOT EDIT -->
3616
- <!-- Tailwind CSS scans this file for class name detection -->
3617
- <div class="${classList}"><div class="${classList}">x</div><div class="${classList}">x</div></div>
3618
- ` + htmlEscape.renderTailwindScannerCandidates(classNames);
3660
+ const content = safelistSource.renderSafelistFile(Array.from(classes));
3619
3661
  try {
3620
3662
  let existing = "";
3621
3663
  try {
@@ -3626,7 +3668,9 @@ function createCsszyxPlugins(options = {}) {
3626
3668
  }
3627
3669
  }
3628
3670
  if (existing !== content) {
3671
+ fs__namespace.mkdirSync(path__namespace.dirname(safelistPath), { recursive: true });
3629
3672
  fs__namespace.writeFileSync(safelistPath, content);
3673
+ safelistSource.removeLegacySafelists(state.rootDir, console.warn);
3630
3674
  }
3631
3675
  } catch {
3632
3676
  }
@@ -3680,15 +3724,15 @@ function createCsszyxPlugins(options = {}) {
3680
3724
  function refreshSzvRegistryEntry(filePath, content) {
3681
3725
  if (!shouldProcessSource(filePath)) return;
3682
3726
  if (content === null) {
3683
- szvCrossModuleRegistry.delete(transformCache.normalizePathSeparators(filePath));
3684
- szvCrossModuleForwards.delete(transformCache.normalizePathSeparators(filePath));
3727
+ szvCrossModuleRegistry.delete(safelistSource.normalizePathSeparators(filePath));
3728
+ szvCrossModuleForwards.delete(safelistSource.normalizePathSeparators(filePath));
3685
3729
  return;
3686
3730
  }
3687
3731
  transformCache.recordSzvRegistryFile(szvCrossModuleRegistry, filePath, content);
3688
3732
  transformCache.recordCrossModuleForwards(szvCrossModuleForwards, filePath, content);
3689
3733
  if (importedStaticSzEnabled) {
3690
3734
  transformCache.recordSzObjectRegistryFile(szvCrossModuleRegistry, filePath, content);
3691
- szObjectProvidersExamined.add(transformCache.normalizePathSeparators(filePath));
3735
+ szObjectProvidersExamined.add(safelistSource.normalizePathSeparators(filePath));
3692
3736
  recordProvidersDemandedBy(filePath, content);
3693
3737
  }
3694
3738
  }
@@ -3711,7 +3755,7 @@ function createCsszyxPlugins(options = {}) {
3711
3755
  for (const specifier of queue) {
3712
3756
  const providerPath = transformCache.resolveProviderPathWith(specifier, transformCache.isReadableProviderFile);
3713
3757
  if (providerPath === void 0) continue;
3714
- const key = transformCache.normalizePathSeparators(providerPath);
3758
+ const key = safelistSource.normalizePathSeparators(providerPath);
3715
3759
  if (!szObjectProvidersExamined.has(key)) {
3716
3760
  szObjectProvidersExamined.add(key);
3717
3761
  readAndRecordSzObjectProvider(providerPath);
@@ -3735,14 +3779,14 @@ function createCsszyxPlugins(options = {}) {
3735
3779
  for (const specifier of queue) {
3736
3780
  const providerPath = transformCache.resolveProviderPath(seenSourcePaths, specifier);
3737
3781
  if (providerPath === void 0) continue;
3738
- szObjectProvidersExamined.add(transformCache.normalizePathSeparators(providerPath));
3782
+ szObjectProvidersExamined.add(safelistSource.normalizePathSeparators(providerPath));
3739
3783
  readAndRecordSzObjectProvider(providerPath);
3740
3784
  enqueueForwardedProviders(providerPath, queue, queued);
3741
3785
  }
3742
3786
  }
3743
3787
  function enqueueForwardedProviders(providerPath, queue, queued) {
3744
3788
  const directory = path__namespace.dirname(providerPath);
3745
- for (const forward of szvCrossModuleForwards.get(transformCache.normalizePathSeparators(providerPath)) ?? []) {
3789
+ for (const forward of szvCrossModuleForwards.get(safelistSource.normalizePathSeparators(providerPath)) ?? []) {
3746
3790
  for (const base of transformCache.specifierBases(forward.specifier, directory, specifierAliases)) {
3747
3791
  if (queued.has(base)) continue;
3748
3792
  queued.add(base);
@@ -3766,6 +3810,7 @@ function createCsszyxPlugins(options = {}) {
3766
3810
  szvCrossModuleRegistry.clear();
3767
3811
  szvCrossModuleForwards.clear();
3768
3812
  szObjectProvidersExamined.clear();
3813
+ prescanSawServerModule = false;
3769
3814
  const prescanStarted = node_perf_hooks.performance.now();
3770
3815
  const discoveredClasses = /* @__PURE__ */ new Set();
3771
3816
  const rawDiscoveredClasses = /* @__PURE__ */ new Set();
@@ -3784,9 +3829,12 @@ function createCsszyxPlugins(options = {}) {
3784
3829
  return;
3785
3830
  }
3786
3831
  recordAuthoredClasses(content);
3832
+ if (!prescanSawServerModule && isRSCServerModule(content, filePath)) {
3833
+ prescanSawServerModule = true;
3834
+ }
3787
3835
  recordSzvRegistryEntries(filePath, content);
3788
3836
  transformCache.recordCrossModuleForwards(szvCrossModuleForwards, filePath, content);
3789
- seenSourcePaths.add(transformCache.normalizePathSeparators(filePath));
3837
+ seenSourcePaths.add(safelistSource.normalizePathSeparators(filePath));
3790
3838
  if (fileMayContainSafelistableSz(content)) {
3791
3839
  prescanSources.push({ filePath, content });
3792
3840
  recordSzObjectDemand(filePath, content);
@@ -3823,6 +3871,7 @@ function createCsszyxPlugins(options = {}) {
3823
3871
  }
3824
3872
  }
3825
3873
  }
3874
+ const walkStarted = node_perf_hooks.performance.now();
3826
3875
  scanDir(state.rootDir);
3827
3876
  const normRoot = normalizeForMatch(state.rootDir);
3828
3877
  for (const sourceDir of compileSourceDirs) {
@@ -3831,7 +3880,20 @@ function createCsszyxPlugins(options = {}) {
3831
3880
  }
3832
3881
  scanDir(sourceDir);
3833
3882
  }
3883
+ traceBenchTiming(
3884
+ `prescan:walk files=${seenSourcePaths.size} sz=${prescanSources.length}`,
3885
+ state.rootDir,
3886
+ node_perf_hooks.performance.now() - walkStarted
3887
+ );
3888
+ const demandStarted = node_perf_hooks.performance.now();
3834
3889
  recordDemandedSzObjectProviders(seenSourcePaths, szObjectDemand);
3890
+ traceBenchTiming(
3891
+ `prescan:demand providers=${szObjectProvidersExamined.size}`,
3892
+ state.rootDir,
3893
+ node_perf_hooks.performance.now() - demandStarted
3894
+ );
3895
+ const batchStarted = node_perf_hooks.performance.now();
3896
+ lastPrescanCacheMisses = 0;
3835
3897
  const prescanContentByPath = new Map(
3836
3898
  prescanSources.map((file) => [file.filePath, file.content])
3837
3899
  );
@@ -3844,12 +3906,23 @@ function createCsszyxPlugins(options = {}) {
3844
3906
  rawDiscoveredClasses
3845
3907
  );
3846
3908
  }
3909
+ traceBenchTiming(
3910
+ `prescan:batch files=${prescanSources.length} misses=${lastPrescanCacheMisses}`,
3911
+ state.rootDir,
3912
+ node_perf_hooks.performance.now() - batchStarted
3913
+ );
3847
3914
  for (const cls of discoveredClasses) {
3848
3915
  addSafelistClass(cls);
3849
3916
  state.ownedClasses.add(cls);
3850
3917
  }
3851
3918
  const safelistClasses = /* @__PURE__ */ new Set([...discoveredClasses, ...rawDiscoveredClasses]);
3919
+ const safelistStarted = node_perf_hooks.performance.now();
3852
3920
  writeSafelistFile(safelistClasses);
3921
+ traceBenchTiming(
3922
+ `prescan:safelist classes=${safelistClasses.size}`,
3923
+ state.rootDir,
3924
+ node_perf_hooks.performance.now() - safelistStarted
3925
+ );
3853
3926
  traceBenchTiming("prescan", state.rootDir, node_perf_hooks.performance.now() - prescanStarted);
3854
3927
  }
3855
3928
  function collectPrescanResult(result, filePath, discoveredClasses, rawDiscoveredClasses) {
@@ -4028,6 +4101,12 @@ function createCsszyxPlugins(options = {}) {
4028
4101
  result = result.split(themeGroupsFile.CHECKSUM_PLACEHOLDER).join(state.checksum);
4029
4102
  }
4030
4103
  const isEvalWrapped = result.includes("eval(") && result.includes("sourceURL=webpack");
4104
+ if (result.includes(themeGroupsFile.CENSUS_PLACEHOLDER)) {
4105
+ const census = safeJsonForScriptTag(
4106
+ createHydrationMangleMap(state.mangleMap, state.varMangleMap)
4107
+ );
4108
+ result = result.split(themeGroupsFile.CENSUS_PLACEHOLDER).join(escapeJsonForStringLiteral(census));
4109
+ }
4031
4110
  if (result.includes(themeGroupsFile.MANGLE_MAP_PLACEHOLDER)) {
4032
4111
  const jsonMap = escapeJsonForInlineScript(JSON.stringify(state.mangleMap));
4033
4112
  const escapedMap = isEvalWrapped ? escapeForDoubleQuotedString(jsonMap) : jsonMap;
@@ -4057,14 +4136,82 @@ function createCsszyxPlugins(options = {}) {
4057
4136
  usesBoolClass: false
4058
4137
  };
4059
4138
  }
4139
+ function recordUntransformedHotFile(file, content) {
4140
+ trackGlobalVarSourceFile(file, content);
4141
+ recordFileVarMangleEntries(state, file, []);
4142
+ recordFileCSSVariableMetrics(state, file, null);
4143
+ }
4144
+ function discoverHotFileClasses(file, watcher) {
4145
+ if (!shouldProcessSource(file)) {
4146
+ return;
4147
+ }
4148
+ let fileContent, result;
4149
+ try {
4150
+ fileContent = fs__namespace.readFileSync(file, "utf-8");
4151
+ } catch {
4152
+ refreshSzvRegistryEntry(file, null);
4153
+ return;
4154
+ }
4155
+ refreshSzvRegistryEntry(file, fileContent);
4156
+ if (!fileContent.includes("sz=") && !fileContent.includes("szs=") && !/\bsz\s*:\s*["'{]/.test(fileContent)) {
4157
+ recordUntransformedHotFile(file, fileContent);
4158
+ return;
4159
+ }
4160
+ try {
4161
+ const hmrTransformStarted = node_perf_hooks.performance.now();
4162
+ result = transformConfiguredSource(fileContent, file);
4163
+ traceBenchTiming("handle-hot-update", file, node_perf_hooks.performance.now() - hmrTransformStarted);
4164
+ } catch {
4165
+ recordUntransformedHotFile(file, fileContent);
4166
+ return;
4167
+ }
4168
+ if (!result.transformed) {
4169
+ recordUntransformedHotFile(file, fileContent);
4170
+ return;
4171
+ }
4172
+ recordHotTransformResult(file, fileContent, result, watcher);
4173
+ }
4174
+ function recordHotTransformResult(file, fileContent, result, watcher) {
4175
+ const sizeBefore = state.classes.size;
4176
+ trackGlobalVarSourceFile(file, fileContent);
4177
+ for (const cls of result.classes) {
4178
+ addSafelistClass(cls);
4179
+ state.ownedClasses.add(cls);
4180
+ }
4181
+ recordFileVarMangleEntries(state, file, cssVariableEntries(result));
4182
+ recordFileCSSVariableMetrics(state, file, result.code);
4183
+ for (const [token, data] of result.recoveryTokens) {
4184
+ state.recoveryTokens.set(token, data);
4185
+ }
4186
+ if (state.classes.size > sizeBefore) {
4187
+ writeSafelistFile(state.classes);
4188
+ const safelistPath = path__namespace.join(state.rootDir, SAFELIST_FILENAME);
4189
+ watcher.emit("change", safelistPath);
4190
+ }
4191
+ }
4192
+ function tailwindEntryModules(moduleGraph) {
4193
+ const modules = [];
4194
+ for (const file of state.tailwindEntryFiles) {
4195
+ const found = moduleGraph.getModulesByFile(file);
4196
+ if (found) modules.push(...found);
4197
+ }
4198
+ return modules;
4199
+ }
4060
4200
  function transformTailwindCssEntry(code, id) {
4061
4201
  state.sawAnyCss = true;
4062
- if (!cssImportsTailwind(code)) return null;
4202
+ const [cssFile] = id.split("?");
4203
+ const legacy = safelistSource.findLegacySourceDirective(code, cssFile);
4204
+ if (legacy !== null) {
4205
+ throw new Error(safelistSource.legacySourceMessage(cssFile, legacy.target));
4206
+ }
4207
+ if (!safelistSource.cssImportsTailwind(code)) return null;
4063
4208
  state.sawTailwindEntry = true;
4209
+ const [entryFile] = id.split("?");
4210
+ state.tailwindEntryFiles.add(entryFile);
4064
4211
  if (cssHasContentScope(code)) state.tailwindEntryScoped = true;
4065
4212
  if (!hasInjectableTailwindCandidate(state.classes)) return null;
4066
- const relPath = computeSafelistRelPath(state.rootDir, SAFELIST_FILENAME, id);
4067
- const transformed = appendTailwindSourceDirective(code, relPath);
4213
+ const relPath = safelistSource.computeSafelistRelPath(state.rootDir, SAFELIST_FILENAME, id);
4214
+ const transformed = safelistSource.appendTailwindSourceDirective(code, relPath);
4068
4215
  return transformed === null ? null : { code: transformed, map: null };
4069
4216
  }
4070
4217
  function reportTransformDiagnostics(result, id, warn) {
@@ -4132,16 +4279,16 @@ function createCsszyxPlugins(options = {}) {
4132
4279
  if (!code.includes("<html") || !/(?:layout|Root|Document|app)\.tsx?$/i.test(id)) {
4133
4280
  return null;
4134
4281
  }
4135
- let transformedCode = code;
4136
4282
  const attrName = options.production?.minify ? "data-sz-cs" : "data-sz-checksum";
4137
- const htmlTag = findOpeningTag(transformedCode, "html");
4138
- if (htmlTag) {
4139
- transformedCode = `${transformedCode.slice(0, htmlTag.close)} ${attrName}="${themeGroupsFile.CHECKSUM_PLACEHOLDER}"${transformedCode.slice(htmlTag.close)}`;
4283
+ const htmlTag = findOpeningTag(code, "html");
4284
+ if (!htmlTag) {
4285
+ return code;
4140
4286
  }
4141
- const debugScript = `<script dangerouslySetInnerHTML={{__html: \`(function(){var m=${themeGroupsFile.MANGLE_MAP_PLACEHOLDER};var vm=${themeGroupsFile.VAR_MANGLE_MAP_PLACEHOLDER};var gp=decodeURIComponent(${escapeJsonForInlineScript(JSON.stringify(encodedGlobalVarAliasPrefix))});var r={};var vr={};for(var k in m)r[m[k]]=k;for(var vk in vm){var vv=vm[vk];var vs=Array.isArray(vv)?vv:[vv];for(var vi=0;vi<vs.length;vi++)(vr[vs[vi]]||(vr[vs[vi]]=[])).push(vk)}window.__csszyx={mangleMap:m,varMangleMap:vm,checksum:"${themeGroupsFile.CHECKSUM_PLACEHOLDER}",decode:function(c){return r[c]},encode:function(c){return m[c]},decodeVar:function(v){return vr[v]||[]},encodeVar:function(v){return vm[v]},decodeGlobalVar:function(v){var a=vr[v]||[];return v.indexOf(gp)===0?a[0]:void 0},decodeAll:function(el){return(el.className||"").split(" ").map(function(c){return r[c]||c})}}})()\`}} />`;
4287
+ let transformedCode = `${code.slice(0, htmlTag.close)} ${attrName}="${themeGroupsFile.CHECKSUM_PLACEHOLDER}"${code.slice(htmlTag.close)}`;
4288
+ const censusTag = `<script id="__CSSZYX_MANGLE_MAP__" type="application/json" dangerouslySetInnerHTML={{__html: \`${themeGroupsFile.CENSUS_PLACEHOLDER}\`}} />`;
4142
4289
  const bodyTag = findOpeningTag(transformedCode, "body");
4143
4290
  if (bodyTag) {
4144
- transformedCode = `${transformedCode.slice(0, bodyTag.close + 1)}${debugScript}${transformedCode.slice(bodyTag.close + 1)}`;
4291
+ transformedCode = `${transformedCode.slice(0, bodyTag.close + 1)}${censusTag}${transformedCode.slice(bodyTag.close + 1)}`;
4145
4292
  }
4146
4293
  return transformedCode;
4147
4294
  }
@@ -4207,12 +4354,22 @@ ${transformedCode}`;
4207
4354
  if (activeFramework !== "vite" && activeFramework !== "rollup") {
4208
4355
  return null;
4209
4356
  }
4210
- if (!manglingEnabled || !deliverMapInBundle || !shouldProcessSource(id) || !MANGLE_RUNTIME_CONSUMER_RE.test(transformedCode) || transformedCode.includes(themeGroupsFile.MANGLE_RUNTIME_VIRTUAL_ID)) {
4357
+ if (!manglingEnabled || !shouldProcessSource(id) || !MANGLE_RUNTIME_CONSUMER_RE.test(transformedCode) || transformedCode.includes(themeGroupsFile.MANGLE_RUNTIME_VIRTUAL_ID)) {
4211
4358
  return null;
4212
4359
  }
4213
4360
  return insertRuntimeImport(transformedCode, `import '${themeGroupsFile.MANGLE_RUNTIME_VIRTUAL_ID}';
4214
4361
  `);
4215
4362
  }
4363
+ function applyWebpackMangleRuntimeEntry(compiler) {
4364
+ const root = compiler.context;
4365
+ const file = ensureMangleRuntimeFile(
4366
+ path__namespace.join(root, ".csszyx"),
4367
+ globalVarAliasPrefix,
4368
+ options.production?.mangleDebugGlobal === true
4369
+ );
4370
+ if (file === null) return;
4371
+ applyMangleRuntimeEntry(compiler, root, file, () => sizeAccount.channels.add("bundle"));
4372
+ }
4216
4373
  function collectPreTransformClasses(output) {
4217
4374
  if (!output.transformed && !output.code.includes("class=") && !output.code.includes("className=")) {
4218
4375
  return null;
@@ -4278,7 +4435,10 @@ ${transformedCode}`;
4278
4435
  }
4279
4436
  if (id === themeGroupsFile.RESOLVED_MANGLE_RUNTIME_VIRTUAL_ID) {
4280
4437
  sizeAccount.channels.add("bundle");
4281
- return themeGroupsFile.createMangleRuntimeModule(globalVarAliasPrefix);
4438
+ return themeGroupsFile.createMangleRuntimeModule(
4439
+ globalVarAliasPrefix,
4440
+ options.production?.mangleDebugGlobal === true
4441
+ );
4282
4442
  }
4283
4443
  if (id === themeGroupsFile.RESOLVED_THEME_GROUPS_VIRTUAL_ID) {
4284
4444
  return themeGroupsFile.createThemeGroupsModule(themeGroupTokens());
@@ -4356,8 +4516,10 @@ ${transformedCode}`;
4356
4516
  }
4357
4517
  if (matchesScriptExtension(id, SCRIPT_ID_EXTENSIONS)) {
4358
4518
  assertNoRSCBoundaryViolation(output.code, id);
4359
- const record = createRSCModuleRecord(output.code, id);
4360
- state.rscModules.set(record.id, record);
4519
+ if (!skipRscRecords) {
4520
+ const record = createRSCModuleRecord(output.code, id);
4521
+ state.rscModules.set(record.id, record);
4522
+ }
4361
4523
  }
4362
4524
  return collectPreTransformClasses(output);
4363
4525
  },
@@ -4434,10 +4596,8 @@ ${transformedCode}`;
4434
4596
  if (compiler.options?.mode === "development") {
4435
4597
  manglingEnabled = false;
4436
4598
  }
4437
- if (manglingEnabled && mangleMapDelivery !== "both") {
4438
- console.warn(
4439
- `[csszyx] production.mangleMapDelivery: '${mangleMapDelivery}' has no effect on the webpack lane \u2014 map delivery only narrows on vite/rollup builds.`
4440
- );
4599
+ if (manglingEnabled) {
4600
+ applyWebpackMangleRuntimeEntry(compiler);
4441
4601
  }
4442
4602
  compiler.hooks.beforeCompile.tap("csszyx:prescan", () => {
4443
4603
  announceActiveParser();
@@ -4496,6 +4656,7 @@ ${transformedCode}`;
4496
4656
  }
4497
4657
  evictTransformCacheOnce();
4498
4658
  prescanAndWriteClasses();
4659
+ skipRscRecords = config.command === "build" && !config.build?.watch && !prescanSawServerModule;
4499
4660
  state.scanCssTheme = runThemeScan(root, options.build?.scanCss) ?? state.scanCssTheme;
4500
4661
  runAutoThemeScan(root);
4501
4662
  if (config.command === "build") {
@@ -4509,8 +4670,11 @@ ${transformedCode}`;
4509
4670
  },
4510
4671
  /**
4511
4672
  * Vite HMR hook: re-runs theme scan when a watched CSS file changes,
4512
- * and incrementally updates csszyx-classes.html when a source file gains new sz classes.
4673
+ * and incrementally updates the safelist when a source file gains new sz classes.
4513
4674
  * @param ctx - HMR context containing the changed file
4675
+ * @returns The modules a safelist write affects, so Vite hot-updates
4676
+ * the stylesheet instead of reloading the page; undefined otherwise,
4677
+ * which leaves Vite's own handling in place.
4514
4678
  */
4515
4679
  handleHotUpdate(ctx) {
4516
4680
  prescanResultHandoff.clear();
@@ -4535,59 +4699,11 @@ ${transformedCode}`;
4535
4699
  ctx.server.ws.send({ type: "full-reload" });
4536
4700
  }
4537
4701
  }
4538
- if (!shouldProcessSource(ctx.file)) {
4539
- return;
4540
- }
4541
- let fileContent, result;
4542
- try {
4543
- fileContent = fs__namespace.readFileSync(ctx.file, "utf-8");
4544
- } catch {
4545
- refreshSzvRegistryEntry(ctx.file, null);
4546
- return;
4547
- }
4548
- refreshSzvRegistryEntry(ctx.file, fileContent);
4549
- if (!fileContent.includes("sz=") && !fileContent.includes("szs=") && !/\bsz\s*:\s*["'{]/.test(fileContent)) {
4550
- trackGlobalVarSourceFile(ctx.file, fileContent);
4551
- recordFileVarMangleEntries(state, ctx.file, []);
4552
- recordFileCSSVariableMetrics(state, ctx.file, null);
4553
- return;
4554
- }
4555
- try {
4556
- const hmrTransformStarted = node_perf_hooks.performance.now();
4557
- result = transformConfiguredSource(fileContent, ctx.file);
4558
- traceBenchTiming(
4559
- "handle-hot-update",
4560
- ctx.file,
4561
- node_perf_hooks.performance.now() - hmrTransformStarted
4562
- );
4563
- } catch {
4564
- trackGlobalVarSourceFile(ctx.file, fileContent);
4565
- recordFileVarMangleEntries(state, ctx.file, []);
4566
- recordFileCSSVariableMetrics(state, ctx.file, null);
4567
- return;
4568
- }
4569
- if (!result.transformed) {
4570
- trackGlobalVarSourceFile(ctx.file, fileContent);
4571
- recordFileVarMangleEntries(state, ctx.file, []);
4572
- recordFileCSSVariableMetrics(state, ctx.file, null);
4573
- return;
4574
- }
4575
- const sizeBefore = state.classes.size;
4576
- trackGlobalVarSourceFile(ctx.file, fileContent);
4577
- for (const cls of result.classes) {
4578
- addSafelistClass(cls);
4579
- state.ownedClasses.add(cls);
4580
- }
4581
- recordFileVarMangleEntries(state, ctx.file, cssVariableEntries(result));
4582
- recordFileCSSVariableMetrics(state, ctx.file, result.code);
4583
- for (const [token, data] of result.recoveryTokens) {
4584
- state.recoveryTokens.set(token, data);
4585
- }
4586
- if (state.classes.size > sizeBefore) {
4587
- writeSafelistFile(state.classes);
4588
- const safelistPath = path__namespace.join(state.rootDir, SAFELIST_FILENAME);
4589
- ctx.server.watcher.emit("change", safelistPath);
4702
+ if (safelistSource.normalizePathSeparators(ctx.file) === safelistSource.normalizePathSeparators(path__namespace.join(state.rootDir, SAFELIST_FILENAME))) {
4703
+ return tailwindEntryModules(ctx.server.moduleGraph);
4590
4704
  }
4705
+ discoverHotFileClasses(ctx.file, ctx.server.watcher);
4706
+ return void 0;
4591
4707
  },
4592
4708
  transformIndexHtml: {
4593
4709
  order: "pre",
@@ -4601,13 +4717,11 @@ ${transformedCode}`;
4601
4717
  finalizeMangleMap();
4602
4718
  const injectedMangleMap = manglingEnabled ? state.mangleMap : {};
4603
4719
  let result = transformIndexHtml(html, injectedMangleMap, state.checksum, {
4604
- // Always 'script'; the checksum itself is injected by
4605
- // injectHydrationData regardless of this mode.
4720
+ // Always 'script' the inert JSON census; the
4721
+ // checksum attribute is injected regardless.
4606
4722
  mode: "script",
4607
4723
  minify: process.env.NODE_ENV === "production",
4608
- varMangleMap: state.varMangleMap,
4609
- globalVarAliasPrefix,
4610
- installRuntimeObject: deliverMapInHtml
4724
+ varMangleMap: state.varMangleMap
4611
4725
  });
4612
4726
  if (manglingEnabled) {
4613
4727
  sizeAccount.channels.add("html");
@@ -4628,6 +4742,18 @@ ${transformedCode}`;
4628
4742
  }
4629
4743
  result = injectRecoveryManifest(result, manifest);
4630
4744
  }
4745
+ if (needsRuntimeMangleRegistration(manglingEnabled, injectedMangleMap)) {
4746
+ return {
4747
+ html: result,
4748
+ tags: [
4749
+ {
4750
+ tag: "script",
4751
+ attrs: { type: "module", src: themeGroupsFile.MANGLE_RUNTIME_VIRTUAL_ID },
4752
+ injectTo: "head-prepend"
4753
+ }
4754
+ ]
4755
+ };
4756
+ }
4631
4757
  return result;
4632
4758
  }
4633
4759
  }
@@ -4980,17 +5106,14 @@ const esbuildPlugin = (options = {}) => {
4980
5106
  };
4981
5107
 
4982
5108
  exports.allocateMangleTokens = allocateMangleTokens;
4983
- exports.appendTailwindSourceDirective = appendTailwindSourceDirective;
4984
5109
  exports.assertNoRSCBoundaryViolation = assertNoRSCBoundaryViolation;
4985
5110
  exports.assertNoRSCGraphViolation = assertNoRSCGraphViolation;
4986
5111
  exports.collectMangleHybridHazards = collectMangleHybridHazards;
4987
- exports.computeSafelistRelPath = computeSafelistRelPath;
4988
5112
  exports.createGlobalVarAliasValidationOptions = createGlobalVarAliasValidationOptions;
4989
5113
  exports.createGlobalVarMapAssetSource = createGlobalVarMapAssetSource;
4990
5114
  exports.createGlobalVarScanCacheKey = createGlobalVarScanCacheKey;
4991
5115
  exports.createRSCModuleRecord = createRSCModuleRecord;
4992
5116
  exports.cssHasContentScope = cssHasContentScope;
4993
- exports.cssImportsTailwind = cssImportsTailwind;
4994
5117
  exports.deleteRSCModuleRecord = deleteRSCModuleRecord;
4995
5118
  exports.emitMissingCssFallback = emitMissingCssFallback;
4996
5119
  exports.esbuildPlugin = esbuildPlugin;