@kbach/react 0.5.22 → 0.5.24
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/vite-plugin.d.mts +7 -0
- package/dist/vite-plugin.d.ts +7 -0
- package/dist/vite-plugin.js +42 -79
- package/dist/vite-plugin.mjs +42 -79
- package/package.json +1 -1
package/dist/vite-plugin.d.mts
CHANGED
|
@@ -7,6 +7,13 @@ import { F as FrameworkConfig } from './types-CV5vXnSH.mjs';
|
|
|
7
7
|
* Vite plugin — scans source files for Kbach className/kb props and generates CSS.
|
|
8
8
|
* Zero setup: just add kbach() to your plugins array.
|
|
9
9
|
* Only generates CSS for classes you actually use (like Tailwind).
|
|
10
|
+
*
|
|
11
|
+
* How it works (same as Tailwind):
|
|
12
|
+
* 1. Scans your source files at startup for className/kb props
|
|
13
|
+
* 2. Generates CSS rules for only those classes
|
|
14
|
+
* 3. Appends them to your imported CSS file (e.g. app.css) via Vite's transform
|
|
15
|
+
* 4. Vite serves the CSS through its normal pipeline → <link rel="stylesheet">
|
|
16
|
+
* 5. When you add a new class in dev, the CSS file is hot-reloaded
|
|
10
17
|
*/
|
|
11
18
|
|
|
12
19
|
declare const VIRTUAL_ID = "virtual:kbach/styles.css";
|
package/dist/vite-plugin.d.ts
CHANGED
|
@@ -7,6 +7,13 @@ import { F as FrameworkConfig } from './types-CV5vXnSH.js';
|
|
|
7
7
|
* Vite plugin — scans source files for Kbach className/kb props and generates CSS.
|
|
8
8
|
* Zero setup: just add kbach() to your plugins array.
|
|
9
9
|
* Only generates CSS for classes you actually use (like Tailwind).
|
|
10
|
+
*
|
|
11
|
+
* How it works (same as Tailwind):
|
|
12
|
+
* 1. Scans your source files at startup for className/kb props
|
|
13
|
+
* 2. Generates CSS rules for only those classes
|
|
14
|
+
* 3. Appends them to your imported CSS file (e.g. app.css) via Vite's transform
|
|
15
|
+
* 4. Vite serves the CSS through its normal pipeline → <link rel="stylesheet">
|
|
16
|
+
* 5. When you add a new class in dev, the CSS file is hot-reloaded
|
|
10
17
|
*/
|
|
11
18
|
|
|
12
19
|
declare const VIRTUAL_ID = "virtual:kbach/styles.css";
|
package/dist/vite-plugin.js
CHANGED
|
@@ -3395,21 +3395,20 @@ function kbach(userConfig) {
|
|
|
3395
3395
|
const cfg = buildConfig(userConfig ?? {});
|
|
3396
3396
|
const screens = toNumericScreens(cfg.theme.screens ?? {});
|
|
3397
3397
|
const tokenCSS = /* @__PURE__ */ new Map();
|
|
3398
|
+
const processedCSSFiles = /* @__PURE__ */ new Set();
|
|
3398
3399
|
let root = process.cwd();
|
|
3399
3400
|
let server = null;
|
|
3400
|
-
function
|
|
3401
|
-
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
tokenCSS.set(token, generateClassCSS(token, cfg.theme, cfg.darkMode, screens));
|
|
3405
|
-
added = true;
|
|
3406
|
-
}
|
|
3407
|
-
return added;
|
|
3401
|
+
function processToken(token) {
|
|
3402
|
+
if (tokenCSS.has(token)) return false;
|
|
3403
|
+
tokenCSS.set(token, generateClassCSS(token, cfg.theme, cfg.darkMode, screens));
|
|
3404
|
+
return true;
|
|
3408
3405
|
}
|
|
3409
3406
|
function extractFromCode(code) {
|
|
3410
3407
|
let added = false;
|
|
3411
3408
|
for (const cls of extractClassStrings(code)) {
|
|
3412
|
-
|
|
3409
|
+
for (const token of cls.split(/\s+/).filter(Boolean)) {
|
|
3410
|
+
if (processToken(token)) added = true;
|
|
3411
|
+
}
|
|
3413
3412
|
}
|
|
3414
3413
|
return added;
|
|
3415
3414
|
}
|
|
@@ -3422,10 +3421,18 @@ function kbach(userConfig) {
|
|
|
3422
3421
|
}
|
|
3423
3422
|
return parts.join("\n");
|
|
3424
3423
|
}
|
|
3425
|
-
function
|
|
3426
|
-
|
|
3427
|
-
|
|
3428
|
-
|
|
3424
|
+
function invalidateCSSModules() {
|
|
3425
|
+
if (!server) return;
|
|
3426
|
+
for (const id of processedCSSFiles) {
|
|
3427
|
+
const mod = server.moduleGraph?.getModuleById(id);
|
|
3428
|
+
if (mod) server.moduleGraph.invalidateModule(mod);
|
|
3429
|
+
}
|
|
3430
|
+
server.hot?.send({ type: "update", updates: [...processedCSSFiles].map((id) => ({
|
|
3431
|
+
type: "js-update",
|
|
3432
|
+
path: id,
|
|
3433
|
+
acceptedPath: id,
|
|
3434
|
+
timestamp: Date.now()
|
|
3435
|
+
})) });
|
|
3429
3436
|
}
|
|
3430
3437
|
return {
|
|
3431
3438
|
name: "kbach",
|
|
@@ -3433,80 +3440,35 @@ function kbach(userConfig) {
|
|
|
3433
3440
|
configResolved(resolved) {
|
|
3434
3441
|
root = resolved.root;
|
|
3435
3442
|
},
|
|
3443
|
+
configureServer(s) {
|
|
3444
|
+
server = s;
|
|
3445
|
+
},
|
|
3436
3446
|
buildStart() {
|
|
3437
3447
|
for (const dir of ["src", "app", "pages", "components", "views", "layouts"]) {
|
|
3438
3448
|
scanDir((0, import_path.join)(root, dir), (code) => extractFromCode(code));
|
|
3439
3449
|
}
|
|
3440
3450
|
},
|
|
3441
|
-
// ──
|
|
3442
|
-
//
|
|
3443
|
-
//
|
|
3444
|
-
//
|
|
3445
|
-
|
|
3446
|
-
|
|
3447
|
-
s.middlewares.use((req, res, next) => {
|
|
3448
|
-
const url = req.url ?? "";
|
|
3449
|
-
if (/\.(js|ts|jsx|tsx|css|png|jpg|svg|ico|woff2?|ttf|json|map)(\?|$)/.test(url) || url.startsWith("/@") || url.startsWith("/__")) {
|
|
3450
|
-
return next();
|
|
3451
|
-
}
|
|
3452
|
-
const origWrite = res.write.bind(res);
|
|
3453
|
-
const origEnd = res.end.bind(res);
|
|
3454
|
-
const chunks = [];
|
|
3455
|
-
let done = false;
|
|
3456
|
-
res.write = function(chunk, enc, cb) {
|
|
3457
|
-
if (done) return origWrite(chunk, enc, cb);
|
|
3458
|
-
if (chunk != null) {
|
|
3459
|
-
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk ?? "")));
|
|
3460
|
-
}
|
|
3461
|
-
if (typeof enc === "function") enc();
|
|
3462
|
-
else if (typeof cb === "function") cb();
|
|
3463
|
-
return true;
|
|
3464
|
-
};
|
|
3465
|
-
res.end = function(chunk, enc, cb) {
|
|
3466
|
-
done = true;
|
|
3467
|
-
if (typeof chunk === "function") {
|
|
3468
|
-
cb = chunk;
|
|
3469
|
-
chunk = null;
|
|
3470
|
-
enc = null;
|
|
3471
|
-
} else if (typeof enc === "function") {
|
|
3472
|
-
cb = enc;
|
|
3473
|
-
enc = null;
|
|
3474
|
-
}
|
|
3475
|
-
if (chunk != null) {
|
|
3476
|
-
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk ?? "")));
|
|
3477
|
-
}
|
|
3478
|
-
if (chunks.length > 0) {
|
|
3479
|
-
const html = Buffer.concat(chunks).toString("utf-8");
|
|
3480
|
-
if (html.includes("</head>")) {
|
|
3481
|
-
const injected = injectIntoHtml(html);
|
|
3482
|
-
const buf = Buffer.from(injected, "utf-8");
|
|
3483
|
-
try {
|
|
3484
|
-
res.removeHeader("transfer-encoding");
|
|
3485
|
-
} catch {
|
|
3486
|
-
}
|
|
3487
|
-
try {
|
|
3488
|
-
res.setHeader("content-length", buf.length);
|
|
3489
|
-
} catch {
|
|
3490
|
-
}
|
|
3491
|
-
return origEnd(buf, cb);
|
|
3492
|
-
}
|
|
3493
|
-
return origEnd(Buffer.concat(chunks), enc, cb);
|
|
3494
|
-
}
|
|
3495
|
-
return origEnd(void 0, enc, cb);
|
|
3496
|
-
};
|
|
3497
|
-
next();
|
|
3498
|
-
});
|
|
3499
|
-
},
|
|
3500
|
-
// ── PROD: append to CSS files so they land in the extracted CSS bundle ────
|
|
3451
|
+
// ── CSS transform: append generated rules to the user's CSS file ──────────
|
|
3452
|
+
// Works exactly like Tailwind's PostCSS plugin:
|
|
3453
|
+
// - Your app.css content stays untouched (empty or your own rules)
|
|
3454
|
+
// - Kbach appends its generated rules to the transform output
|
|
3455
|
+
// - Vite serves the result via its normal CSS pipeline (<link rel="stylesheet">)
|
|
3456
|
+
// - In production, it lands in the extracted CSS bundle file
|
|
3501
3457
|
transform(code, id) {
|
|
3502
3458
|
const cleanId = id.split("?")[0];
|
|
3503
3459
|
if (cleanId.endsWith(".css") && !id.includes("node_modules") && !id.includes("\0")) {
|
|
3460
|
+
processedCSSFiles.add(cleanId);
|
|
3504
3461
|
const kbachCSS = getAllCSS();
|
|
3505
3462
|
if (!kbachCSS) return null;
|
|
3506
|
-
return { code: code
|
|
3463
|
+
return { code: `${code}
|
|
3464
|
+
/* kbach */
|
|
3465
|
+
${kbachCSS}`, map: null };
|
|
3507
3466
|
}
|
|
3508
3467
|
if (/\.(tsx?|jsx?)$/.test(cleanId) && !id.includes("node_modules")) {
|
|
3509
|
-
extractFromCode(code);
|
|
3468
|
+
const added = extractFromCode(code);
|
|
3469
|
+
if (added && server && processedCSSFiles.size > 0) {
|
|
3470
|
+
setTimeout(() => invalidateCSSModules(), 0);
|
|
3471
|
+
}
|
|
3510
3472
|
}
|
|
3511
3473
|
},
|
|
3512
3474
|
// ── Virtual module (opt-in explicit import) ───────────────────────────────
|
|
@@ -3516,13 +3478,14 @@ function kbach(userConfig) {
|
|
|
3516
3478
|
load(id) {
|
|
3517
3479
|
if (id === RESOLVED_ID) return getAllCSS();
|
|
3518
3480
|
},
|
|
3519
|
-
// ── HMR:
|
|
3520
|
-
handleHotUpdate({ file }) {
|
|
3481
|
+
// ── HMR: invalidate CSS when new classes are found in changed files ───────
|
|
3482
|
+
handleHotUpdate({ file, server: s }) {
|
|
3521
3483
|
if (file.includes("node_modules") || !/\.(tsx?|jsx?)$/.test(file)) return;
|
|
3522
3484
|
try {
|
|
3523
3485
|
const added = extractFromCode((0, import_fs.readFileSync)(file, "utf-8"));
|
|
3524
|
-
if (added
|
|
3525
|
-
|
|
3486
|
+
if (added) {
|
|
3487
|
+
server = s;
|
|
3488
|
+
invalidateCSSModules();
|
|
3526
3489
|
}
|
|
3527
3490
|
} catch {
|
|
3528
3491
|
}
|
package/dist/vite-plugin.mjs
CHANGED
|
@@ -53,21 +53,20 @@ function kbach(userConfig) {
|
|
|
53
53
|
const cfg = buildConfig(userConfig ?? {});
|
|
54
54
|
const screens = toNumericScreens(cfg.theme.screens ?? {});
|
|
55
55
|
const tokenCSS = /* @__PURE__ */ new Map();
|
|
56
|
+
const processedCSSFiles = /* @__PURE__ */ new Set();
|
|
56
57
|
let root = process.cwd();
|
|
57
58
|
let server = null;
|
|
58
|
-
function
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
tokenCSS.set(token, generateClassCSS(token, cfg.theme, cfg.darkMode, screens));
|
|
63
|
-
added = true;
|
|
64
|
-
}
|
|
65
|
-
return added;
|
|
59
|
+
function processToken(token) {
|
|
60
|
+
if (tokenCSS.has(token)) return false;
|
|
61
|
+
tokenCSS.set(token, generateClassCSS(token, cfg.theme, cfg.darkMode, screens));
|
|
62
|
+
return true;
|
|
66
63
|
}
|
|
67
64
|
function extractFromCode(code) {
|
|
68
65
|
let added = false;
|
|
69
66
|
for (const cls of extractClassStrings(code)) {
|
|
70
|
-
|
|
67
|
+
for (const token of cls.split(/\s+/).filter(Boolean)) {
|
|
68
|
+
if (processToken(token)) added = true;
|
|
69
|
+
}
|
|
71
70
|
}
|
|
72
71
|
return added;
|
|
73
72
|
}
|
|
@@ -80,10 +79,18 @@ function kbach(userConfig) {
|
|
|
80
79
|
}
|
|
81
80
|
return parts.join("\n");
|
|
82
81
|
}
|
|
83
|
-
function
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
82
|
+
function invalidateCSSModules() {
|
|
83
|
+
if (!server) return;
|
|
84
|
+
for (const id of processedCSSFiles) {
|
|
85
|
+
const mod = server.moduleGraph?.getModuleById(id);
|
|
86
|
+
if (mod) server.moduleGraph.invalidateModule(mod);
|
|
87
|
+
}
|
|
88
|
+
server.hot?.send({ type: "update", updates: [...processedCSSFiles].map((id) => ({
|
|
89
|
+
type: "js-update",
|
|
90
|
+
path: id,
|
|
91
|
+
acceptedPath: id,
|
|
92
|
+
timestamp: Date.now()
|
|
93
|
+
})) });
|
|
87
94
|
}
|
|
88
95
|
return {
|
|
89
96
|
name: "kbach",
|
|
@@ -91,80 +98,35 @@ function kbach(userConfig) {
|
|
|
91
98
|
configResolved(resolved) {
|
|
92
99
|
root = resolved.root;
|
|
93
100
|
},
|
|
101
|
+
configureServer(s) {
|
|
102
|
+
server = s;
|
|
103
|
+
},
|
|
94
104
|
buildStart() {
|
|
95
105
|
for (const dir of ["src", "app", "pages", "components", "views", "layouts"]) {
|
|
96
106
|
scanDir(join(root, dir), (code) => extractFromCode(code));
|
|
97
107
|
}
|
|
98
108
|
},
|
|
99
|
-
// ──
|
|
100
|
-
//
|
|
101
|
-
//
|
|
102
|
-
//
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
s.middlewares.use((req, res, next) => {
|
|
106
|
-
const url = req.url ?? "";
|
|
107
|
-
if (/\.(js|ts|jsx|tsx|css|png|jpg|svg|ico|woff2?|ttf|json|map)(\?|$)/.test(url) || url.startsWith("/@") || url.startsWith("/__")) {
|
|
108
|
-
return next();
|
|
109
|
-
}
|
|
110
|
-
const origWrite = res.write.bind(res);
|
|
111
|
-
const origEnd = res.end.bind(res);
|
|
112
|
-
const chunks = [];
|
|
113
|
-
let done = false;
|
|
114
|
-
res.write = function(chunk, enc, cb) {
|
|
115
|
-
if (done) return origWrite(chunk, enc, cb);
|
|
116
|
-
if (chunk != null) {
|
|
117
|
-
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk ?? "")));
|
|
118
|
-
}
|
|
119
|
-
if (typeof enc === "function") enc();
|
|
120
|
-
else if (typeof cb === "function") cb();
|
|
121
|
-
return true;
|
|
122
|
-
};
|
|
123
|
-
res.end = function(chunk, enc, cb) {
|
|
124
|
-
done = true;
|
|
125
|
-
if (typeof chunk === "function") {
|
|
126
|
-
cb = chunk;
|
|
127
|
-
chunk = null;
|
|
128
|
-
enc = null;
|
|
129
|
-
} else if (typeof enc === "function") {
|
|
130
|
-
cb = enc;
|
|
131
|
-
enc = null;
|
|
132
|
-
}
|
|
133
|
-
if (chunk != null) {
|
|
134
|
-
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk ?? "")));
|
|
135
|
-
}
|
|
136
|
-
if (chunks.length > 0) {
|
|
137
|
-
const html = Buffer.concat(chunks).toString("utf-8");
|
|
138
|
-
if (html.includes("</head>")) {
|
|
139
|
-
const injected = injectIntoHtml(html);
|
|
140
|
-
const buf = Buffer.from(injected, "utf-8");
|
|
141
|
-
try {
|
|
142
|
-
res.removeHeader("transfer-encoding");
|
|
143
|
-
} catch {
|
|
144
|
-
}
|
|
145
|
-
try {
|
|
146
|
-
res.setHeader("content-length", buf.length);
|
|
147
|
-
} catch {
|
|
148
|
-
}
|
|
149
|
-
return origEnd(buf, cb);
|
|
150
|
-
}
|
|
151
|
-
return origEnd(Buffer.concat(chunks), enc, cb);
|
|
152
|
-
}
|
|
153
|
-
return origEnd(void 0, enc, cb);
|
|
154
|
-
};
|
|
155
|
-
next();
|
|
156
|
-
});
|
|
157
|
-
},
|
|
158
|
-
// ── PROD: append to CSS files so they land in the extracted CSS bundle ────
|
|
109
|
+
// ── CSS transform: append generated rules to the user's CSS file ──────────
|
|
110
|
+
// Works exactly like Tailwind's PostCSS plugin:
|
|
111
|
+
// - Your app.css content stays untouched (empty or your own rules)
|
|
112
|
+
// - Kbach appends its generated rules to the transform output
|
|
113
|
+
// - Vite serves the result via its normal CSS pipeline (<link rel="stylesheet">)
|
|
114
|
+
// - In production, it lands in the extracted CSS bundle file
|
|
159
115
|
transform(code, id) {
|
|
160
116
|
const cleanId = id.split("?")[0];
|
|
161
117
|
if (cleanId.endsWith(".css") && !id.includes("node_modules") && !id.includes("\0")) {
|
|
118
|
+
processedCSSFiles.add(cleanId);
|
|
162
119
|
const kbachCSS = getAllCSS();
|
|
163
120
|
if (!kbachCSS) return null;
|
|
164
|
-
return { code: code
|
|
121
|
+
return { code: `${code}
|
|
122
|
+
/* kbach */
|
|
123
|
+
${kbachCSS}`, map: null };
|
|
165
124
|
}
|
|
166
125
|
if (/\.(tsx?|jsx?)$/.test(cleanId) && !id.includes("node_modules")) {
|
|
167
|
-
extractFromCode(code);
|
|
126
|
+
const added = extractFromCode(code);
|
|
127
|
+
if (added && server && processedCSSFiles.size > 0) {
|
|
128
|
+
setTimeout(() => invalidateCSSModules(), 0);
|
|
129
|
+
}
|
|
168
130
|
}
|
|
169
131
|
},
|
|
170
132
|
// ── Virtual module (opt-in explicit import) ───────────────────────────────
|
|
@@ -174,13 +136,14 @@ function kbach(userConfig) {
|
|
|
174
136
|
load(id) {
|
|
175
137
|
if (id === RESOLVED_ID) return getAllCSS();
|
|
176
138
|
},
|
|
177
|
-
// ── HMR:
|
|
178
|
-
handleHotUpdate({ file }) {
|
|
139
|
+
// ── HMR: invalidate CSS when new classes are found in changed files ───────
|
|
140
|
+
handleHotUpdate({ file, server: s }) {
|
|
179
141
|
if (file.includes("node_modules") || !/\.(tsx?|jsx?)$/.test(file)) return;
|
|
180
142
|
try {
|
|
181
143
|
const added = extractFromCode(readFileSync(file, "utf-8"));
|
|
182
|
-
if (added
|
|
183
|
-
|
|
144
|
+
if (added) {
|
|
145
|
+
server = s;
|
|
146
|
+
invalidateCSSModules();
|
|
184
147
|
}
|
|
185
148
|
} catch {
|
|
186
149
|
}
|