@csszyx/unplugin 0.1.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.
- package/README.md +52 -0
- package/dist/chunk-4M7CPGP7.js +202 -0
- package/dist/chunk-JKM7IRGZ.js +663 -0
- package/dist/css-mangler.cjs +240 -0
- package/dist/css-mangler.d.cts +123 -0
- package/dist/css-mangler.d.ts +123 -0
- package/dist/css-mangler.js +14 -0
- package/dist/index.cjs +905 -0
- package/dist/index.d.cts +8 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +27 -0
- package/dist/unplugin-B9noIooS.d.cts +33 -0
- package/dist/unplugin-B9noIooS.d.ts +33 -0
- package/dist/vite.cjs +755 -0
- package/dist/vite.d.cts +30 -0
- package/dist/vite.d.ts +30 -0
- package/dist/vite.js +10 -0
- package/dist/webpack.cjs +764 -0
- package/dist/webpack.d.cts +10 -0
- package/dist/webpack.d.ts +10 -0
- package/dist/webpack.js +10 -0
- package/package.json +81 -0
package/README.md
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# @csszyx/unplugin
|
|
2
|
+
|
|
3
|
+
> Vite, Webpack, and Rollup integration for csszyx.
|
|
4
|
+
|
|
5
|
+
This package provides the build-time transformations needed to make csszyx work. It handles:
|
|
6
|
+
|
|
7
|
+
- 🔍 Extracting styles from your code.
|
|
8
|
+
- 🎨 Generating static CSS.
|
|
9
|
+
- 🧩 Mangling class names for production.
|
|
10
|
+
- ⚡ Injecting hydration scripts.
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm install -D @csszyx/unplugin
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Usage
|
|
19
|
+
|
|
20
|
+
### Vite
|
|
21
|
+
|
|
22
|
+
```ts
|
|
23
|
+
// vite.config.ts
|
|
24
|
+
import { defineConfig } from "vite";
|
|
25
|
+
import csszyx from "@csszyx/unplugin/vite";
|
|
26
|
+
|
|
27
|
+
export default defineConfig({
|
|
28
|
+
plugins: [csszyx()],
|
|
29
|
+
});
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Webpack
|
|
33
|
+
|
|
34
|
+
```js
|
|
35
|
+
// webpack.config.js
|
|
36
|
+
import csszyx from "@csszyx/unplugin/webpack";
|
|
37
|
+
|
|
38
|
+
export default {
|
|
39
|
+
plugins: [csszyx()],
|
|
40
|
+
};
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Features
|
|
44
|
+
|
|
45
|
+
- **Universal Support**: Works with standard unplugin hooks.
|
|
46
|
+
- **HTML Injection**: Automatically injects mangle maps and checksums.
|
|
47
|
+
- **Hot Module Replacement**: Updates styles instantly in dev.
|
|
48
|
+
- **CSS Mangling**: Compresses class names (e.g., `text-center` -> `a`) in production.
|
|
49
|
+
|
|
50
|
+
## License
|
|
51
|
+
|
|
52
|
+
MIT © [csszyx contributors](https://github.com/nguyennhutien/csszyx)
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
// src/css-mangler.ts
|
|
2
|
+
import postcss from "postcss";
|
|
3
|
+
import selectorParser from "postcss-selector-parser";
|
|
4
|
+
function unescapeTailwindClass(escapedName) {
|
|
5
|
+
let result = "";
|
|
6
|
+
let i = 0;
|
|
7
|
+
while (i < escapedName.length) {
|
|
8
|
+
if (escapedName[i] === "\\") {
|
|
9
|
+
i++;
|
|
10
|
+
if (i >= escapedName.length) {
|
|
11
|
+
break;
|
|
12
|
+
}
|
|
13
|
+
const char = escapedName[i];
|
|
14
|
+
if (/[0-9a-fA-F]/.test(char)) {
|
|
15
|
+
let hexStr = "";
|
|
16
|
+
while (i < escapedName.length && /[0-9a-fA-F]/.test(escapedName[i]) && hexStr.length < 6) {
|
|
17
|
+
hexStr += escapedName[i];
|
|
18
|
+
i++;
|
|
19
|
+
}
|
|
20
|
+
if (i < escapedName.length && escapedName[i] === " ") {
|
|
21
|
+
i++;
|
|
22
|
+
}
|
|
23
|
+
const codePoint = parseInt(hexStr, 16);
|
|
24
|
+
if (codePoint > 0) {
|
|
25
|
+
result += String.fromCodePoint(codePoint);
|
|
26
|
+
}
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
result += char;
|
|
30
|
+
i++;
|
|
31
|
+
} else {
|
|
32
|
+
result += escapedName[i];
|
|
33
|
+
i++;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return result;
|
|
37
|
+
}
|
|
38
|
+
function escapeCSSClassName(className) {
|
|
39
|
+
let result = "";
|
|
40
|
+
for (let i = 0; i < className.length; i++) {
|
|
41
|
+
const char = className[i];
|
|
42
|
+
const code = char.charCodeAt(0);
|
|
43
|
+
if (i === 0) {
|
|
44
|
+
if (/[0-9]/.test(char)) {
|
|
45
|
+
result += "\\3" + char + " ";
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
if (char === "-" && i + 1 < className.length) {
|
|
49
|
+
const next = className[i + 1];
|
|
50
|
+
if (/[0-9]/.test(next) || next === "-") {
|
|
51
|
+
result += "\\-";
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
if (/[!"#$%&'()*+,./:;<=>?@[\\\]^`{|}~]/.test(char)) {
|
|
57
|
+
result += "\\" + char;
|
|
58
|
+
} else if (code >= 128) {
|
|
59
|
+
result += char;
|
|
60
|
+
} else {
|
|
61
|
+
result += char;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return result;
|
|
65
|
+
}
|
|
66
|
+
function createSelectorProcessor(mangleMap, mangledClasses, unmangledClasses) {
|
|
67
|
+
return selectorParser((selectors) => {
|
|
68
|
+
selectors.walkClasses((classNode) => {
|
|
69
|
+
const originalValue = classNode.value;
|
|
70
|
+
const unescapedValue = unescapeTailwindClass(originalValue);
|
|
71
|
+
let mangledValue, matchedKey;
|
|
72
|
+
if (mangleMap[unescapedValue]) {
|
|
73
|
+
mangledValue = mangleMap[unescapedValue];
|
|
74
|
+
matchedKey = unescapedValue;
|
|
75
|
+
} else if (mangleMap[originalValue]) {
|
|
76
|
+
mangledValue = mangleMap[originalValue];
|
|
77
|
+
matchedKey = originalValue;
|
|
78
|
+
}
|
|
79
|
+
if (mangledValue && matchedKey) {
|
|
80
|
+
classNode.value = mangledValue;
|
|
81
|
+
mangledClasses.add(matchedKey);
|
|
82
|
+
} else {
|
|
83
|
+
unmangledClasses.add(originalValue);
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
async function mangleCSS(css, mangleMap, options = {}) {
|
|
89
|
+
const mangledClasses = /* @__PURE__ */ new Set();
|
|
90
|
+
const unmangledClasses = /* @__PURE__ */ new Set();
|
|
91
|
+
let transformedCount = 0;
|
|
92
|
+
const selectorProcessor = createSelectorProcessor(
|
|
93
|
+
mangleMap,
|
|
94
|
+
mangledClasses,
|
|
95
|
+
unmangledClasses
|
|
96
|
+
);
|
|
97
|
+
const csszyxManglerPlugin = {
|
|
98
|
+
postcssPlugin: "csszyx-css-mangler",
|
|
99
|
+
Rule(rule) {
|
|
100
|
+
try {
|
|
101
|
+
const originalSelector = rule.selector;
|
|
102
|
+
const newSelector = selectorProcessor.processSync(originalSelector);
|
|
103
|
+
if (newSelector !== originalSelector) {
|
|
104
|
+
rule.selector = newSelector;
|
|
105
|
+
transformedCount++;
|
|
106
|
+
}
|
|
107
|
+
} catch (error) {
|
|
108
|
+
if (options.debug) {
|
|
109
|
+
console.warn(`[csszyx] Failed to process selector: ${rule.selector}`, error);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
const result = await postcss([csszyxManglerPlugin]).process(css, {
|
|
115
|
+
from: options.from
|
|
116
|
+
});
|
|
117
|
+
if (options.debug) {
|
|
118
|
+
console.log(`[csszyx] CSS Mangler: ${transformedCount} selectors transformed`);
|
|
119
|
+
console.log(`[csszyx] Mangled classes: ${mangledClasses.size}`);
|
|
120
|
+
console.log(`[csszyx] Unmangled classes: ${unmangledClasses.size}`);
|
|
121
|
+
}
|
|
122
|
+
return {
|
|
123
|
+
css: result.css,
|
|
124
|
+
transformedCount,
|
|
125
|
+
mangledClasses: Array.from(mangledClasses),
|
|
126
|
+
unmangledClasses: Array.from(unmangledClasses)
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
function mangleCSSSync(css, mangleMap, options = {}) {
|
|
130
|
+
const mangledClasses = /* @__PURE__ */ new Set();
|
|
131
|
+
const unmangledClasses = /* @__PURE__ */ new Set();
|
|
132
|
+
let transformedCount = 0;
|
|
133
|
+
const selectorProcessor = createSelectorProcessor(
|
|
134
|
+
mangleMap,
|
|
135
|
+
mangledClasses,
|
|
136
|
+
unmangledClasses
|
|
137
|
+
);
|
|
138
|
+
const root = postcss.parse(css, { from: options.from });
|
|
139
|
+
root.walkRules((rule) => {
|
|
140
|
+
try {
|
|
141
|
+
const originalSelector = rule.selector;
|
|
142
|
+
const newSelector = selectorProcessor.processSync(originalSelector);
|
|
143
|
+
if (newSelector !== originalSelector) {
|
|
144
|
+
rule.selector = newSelector;
|
|
145
|
+
transformedCount++;
|
|
146
|
+
}
|
|
147
|
+
} catch (error) {
|
|
148
|
+
if (options.debug) {
|
|
149
|
+
console.warn(`[csszyx] Failed to process selector: ${rule.selector}`, error);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
if (options.debug) {
|
|
154
|
+
console.log(`[csszyx] CSS Mangler: ${transformedCount} selectors transformed`);
|
|
155
|
+
console.log(`[csszyx] Mangled classes: ${mangledClasses.size}`);
|
|
156
|
+
console.log(`[csszyx] Unmangled classes: ${unmangledClasses.size}`);
|
|
157
|
+
}
|
|
158
|
+
return {
|
|
159
|
+
css: root.toString(),
|
|
160
|
+
transformedCount,
|
|
161
|
+
mangledClasses: Array.from(mangledClasses),
|
|
162
|
+
unmangledClasses: Array.from(unmangledClasses)
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
function createPostCSSPlugin(mangleMap, options = {}) {
|
|
166
|
+
const mangledClasses = /* @__PURE__ */ new Set();
|
|
167
|
+
const unmangledClasses = /* @__PURE__ */ new Set();
|
|
168
|
+
const selectorProcessor = createSelectorProcessor(
|
|
169
|
+
mangleMap,
|
|
170
|
+
mangledClasses,
|
|
171
|
+
unmangledClasses
|
|
172
|
+
);
|
|
173
|
+
return {
|
|
174
|
+
postcssPlugin: "csszyx-css-mangler",
|
|
175
|
+
Rule(rule) {
|
|
176
|
+
try {
|
|
177
|
+
const originalSelector = rule.selector;
|
|
178
|
+
const newSelector = selectorProcessor.processSync(originalSelector);
|
|
179
|
+
if (newSelector !== originalSelector) {
|
|
180
|
+
rule.selector = newSelector;
|
|
181
|
+
}
|
|
182
|
+
} catch (error) {
|
|
183
|
+
if (options.debug) {
|
|
184
|
+
console.warn(`[csszyx] Failed to process selector: ${rule.selector}`, error);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
},
|
|
188
|
+
OnceExit() {
|
|
189
|
+
if (options.debug) {
|
|
190
|
+
console.log(`[csszyx] Mangled ${mangledClasses.size} unique classes`);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
export {
|
|
197
|
+
unescapeTailwindClass,
|
|
198
|
+
escapeCSSClassName,
|
|
199
|
+
mangleCSS,
|
|
200
|
+
mangleCSSSync,
|
|
201
|
+
createPostCSSPlugin
|
|
202
|
+
};
|