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.
- package/dist/index.mjs +18 -12
- 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
|
-
|
|
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
|
|
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.
|
|
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) =>
|
|
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.
|
|
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
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
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);
|