vite-plugin-token-shaker 0.0.2 → 0.0.4

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 (2) hide show
  1. package/dist/index.mjs +18 -12
  2. package/package.json +1 -1
package/dist/index.mjs CHANGED
@@ -37,7 +37,7 @@ function extractTokensVariables(code, registry) {
37
37
  if (!registry.has(varName)) registry.set(varName, {
38
38
  value: varValue,
39
39
  usageCount: 0,
40
- setElsewhere: false,
40
+ deoptimized: false,
41
41
  isAlias,
42
42
  emitDeclaration: false
43
43
  });
@@ -47,10 +47,10 @@ function extractTokensVariables(code, registry) {
47
47
  }
48
48
  }
49
49
  }
50
- function markVariablesSetElsewhere(code, registry) {
50
+ function markDeoptimizedFromCSS(code, registry) {
51
51
  let codeWithoutTokens = code;
52
52
  for (const layer of findTokensLayers(code)) codeWithoutTokens = codeWithoutTokens.slice(0, layer.start) + " ".repeat(layer.end - layer.start) + codeWithoutTokens.slice(layer.end);
53
- for (const [varName, variable] of registry) if (new RegExp(`${escapeRegex(varName)}\\s*:`, "g").test(codeWithoutTokens)) variable.setElsewhere = true;
53
+ for (const [varName, variable] of registry) if (new RegExp(`${escapeRegex(varName)}\\s*:`, "g").test(codeWithoutTokens)) variable.deoptimized = true;
54
54
  }
55
55
  function countVariableUsage(code, registry, visited = /* @__PURE__ */ new Set()) {
56
56
  for (const match of code.matchAll(VAR_REF_REGEX)) {
@@ -76,7 +76,10 @@ function resolveVariableValue(varName, registry, depth = 0) {
76
76
  if (depth > 10) return `var(${varName})`;
77
77
  const variable = registry.get(varName);
78
78
  if (!variable) return `var(${varName})`;
79
- return variable.value.replace(VAR_REF_REGEX, (_, nestedVarName) => resolveVariableValue(nestedVarName, registry, depth + 1));
79
+ return variable.value.replace(VAR_REF_REGEX, (_, nestedVarName) => {
80
+ if (registry.get(nestedVarName)?.deoptimized) return `var(${nestedVarName})`;
81
+ return resolveVariableValue(nestedVarName, registry, depth + 1);
82
+ });
80
83
  }
81
84
  function generateMangledNames(registry, manglePrefix) {
82
85
  const valueToVars = /* @__PURE__ */ new Map();
@@ -122,13 +125,13 @@ function transformCode(code, registry) {
122
125
  const variable = registry.get(varName);
123
126
  if (!variable) continue;
124
127
  if (variable.usageCount == 0) continue;
125
- if (variable.setElsewhere) {
128
+ if (variable.deoptimized) {
126
129
  declarations.push(`${varName}: ${varValue}`);
127
130
  continue;
128
131
  }
129
132
  if (variable.mangledName) {
130
133
  const resolvedValue = resolveVariableValue(varName, registry);
131
- if (variable.emitDeclaration && !variable.isAlias) {
134
+ if (variable.emitDeclaration) {
132
135
  if (!emittedValues.has(resolvedValue)) {
133
136
  declarations.push(`${variable.mangledName}: ${resolvedValue}`);
134
137
  emittedValues.add(resolvedValue);
@@ -142,40 +145,43 @@ function transformCode(code, registry) {
142
145
  result = result.replace(VAR_REF_REGEX, (original, varName, fallback) => {
143
146
  const variable = registry.get(varName);
144
147
  if (!variable) return original;
148
+ if (variable.deoptimized) return original;
145
149
  if (variable.mangledName) return `var(${variable.mangledName}${fallback ? `, ${fallback}` : ""})`;
146
- if (!variable.setElsewhere) return resolveVariableValue(varName, registry);
147
- return original;
150
+ return resolveVariableValue(varName, registry);
148
151
  });
149
152
  return result;
150
153
  }
151
154
  function getStats(registry, mangledCount) {
152
155
  let drop = 0, inline = 0, mangle = 0, keep = 0;
153
156
  for (const variable of registry.values()) if (variable.usageCount == 0) drop++;
154
- else if (variable.setElsewhere) keep++;
157
+ else if (variable.deoptimized) keep++;
155
158
  else if (variable.mangledName) mangle++;
156
159
  else inline++;
157
160
  return `Analysis: ${drop} drop, ${inline} inline, ${mangle} mangle (${mangledCount} unique values), ${keep} keep`;
158
161
  }
159
162
  function tokenShaker(options = {}) {
160
163
  const { manglePrefix = "--_", verbose = false } = options;
161
- const registry = /* @__PURE__ */ new Map();
162
164
  const log = verbose ? (...args) => console.log("[token-shaker]", ...args) : () => {};
163
165
  return {
164
166
  name: "vite-plugin-token-shaker",
165
167
  enforce: "pre",
166
168
  generateBundle(_outputOptions, bundle) {
167
- registry.clear();
168
169
  const cssAssets = Object.entries(bundle).filter(([name, asset]) => asset.type == "asset" && name.endsWith(".css"));
169
170
  if (cssAssets.length == 0) return;
171
+ const registry = /* @__PURE__ */ new Map();
170
172
  for (const [, asset] of cssAssets) extractTokensVariables(asset.source, registry);
171
173
  if (registry.size == 0) return;
172
174
  const bundledFiles = cssAssets.map(([name, asset]) => [name, asset.source]);
173
175
  log(`Analyzing ${registry.size} variables across ${cssAssets.length} CSS files`);
174
176
  resetUsageCounts(registry);
175
177
  for (const [, code] of bundledFiles) {
176
- markVariablesSetElsewhere(code, registry);
178
+ markDeoptimizedFromCSS(code, registry);
177
179
  countVariableUsage(code, registry);
178
180
  }
181
+ for (const chunk of Object.values(bundle)) {
182
+ if (chunk.type != "chunk") continue;
183
+ for (const [varName, variable] of registry) if (chunk.code.includes(varName)) variable.deoptimized = true;
184
+ }
179
185
  log(getStats(registry, generateMangledNames(registry, manglePrefix)));
180
186
  for (const [fileName, asset] of cssAssets) {
181
187
  const transformed = transformCode(asset.source, registry);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vite-plugin-token-shaker",
3
- "version": "0.0.2",
3
+ "version": "0.0.4",
4
4
  "description": "Clean up anything in @layer tokens",
5
5
  "type": "module",
6
6
  "license": "MIT",