chaincss 2.0.7 → 2.1.1
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/CHANGELOG.md +30 -0
- package/CODE_OF_CONDUCT.md +21 -0
- package/CONTRIBUTING.md +28 -0
- package/README.md +455 -226
- package/demo/demo/node_modules/caniuse-db/fulldata-json/data-2.0.json +1 -0
- package/demo/index.html +16 -0
- package/demo/package.json +20 -0
- package/demo/src/App.tsx +117 -0
- package/demo/src/chaincss-barrel.ts +9 -0
- package/demo/src/main.tsx +8 -0
- package/demo/src/styles.chain.ts +300 -0
- package/demo/vite.config.ts +46 -0
- package/dist/cli/commands/build.d.ts +0 -1
- package/dist/cli/commands/cache.d.ts +1 -0
- package/dist/cli/commands/init.d.ts +6 -3
- package/dist/cli/commands/timeline.d.ts +0 -1
- package/dist/cli/commands/watch.d.ts +0 -1
- package/dist/cli/index.d.ts +0 -1
- package/dist/cli/index.js +3213 -5296
- package/dist/cli/types.d.ts +51 -20
- package/dist/cli/utils/config-loader.d.ts +0 -1
- package/dist/cli/utils/file-utils.d.ts +27 -3
- package/dist/cli/utils/logger.d.ts +0 -1
- package/dist/compiler/Chain.d.ts +215 -0
- package/dist/compiler/animations.d.ts +76 -0
- package/dist/compiler/atomic-optimizer.d.ts +47 -12
- package/dist/compiler/breakpoints.d.ts +46 -0
- package/dist/compiler/btt.d.ts +36 -60
- package/dist/compiler/cache-manager.d.ts +58 -4
- package/dist/compiler/commonProps.d.ts +0 -1
- package/dist/compiler/content-addressable-cache.d.ts +78 -0
- package/dist/compiler/helpers.d.ts +54 -0
- package/dist/compiler/index.d.ts +16 -9
- package/dist/compiler/index.js +4450 -4316
- package/dist/compiler/prefixer.d.ts +17 -1
- package/dist/compiler/shorthands.d.ts +28 -0
- package/dist/compiler/suggestions.d.ts +43 -0
- package/dist/compiler/theme-contract.d.ts +16 -27
- package/dist/compiler/token-resolver.d.ts +69 -0
- package/dist/compiler/tokens.d.ts +33 -8
- package/dist/core/auto-detector.d.ts +34 -0
- package/dist/core/common-utils.d.ts +97 -0
- package/dist/core/compiler.d.ts +63 -23
- package/dist/core/constants.d.ts +137 -36
- package/dist/core/smart-chain.d.ts +3 -0
- package/dist/core/types.d.ts +122 -15
- package/dist/core/utils.d.ts +134 -17
- package/dist/index.d.ts +52 -8
- package/dist/index.js +7090 -5578
- package/dist/plugins/vite.d.ts +7 -5
- package/dist/plugins/vite.js +2964 -25641
- package/dist/plugins/webpack.d.ts +24 -1
- package/dist/plugins/webpack.js +209 -72
- package/dist/runtime/Chain.d.ts +32 -0
- package/dist/runtime/auto-hooks.d.ts +11 -0
- package/dist/runtime/hmr.d.ts +22 -2
- package/dist/runtime/index.d.ts +3 -2
- package/dist/runtime/index.js +3648 -301
- package/dist/runtime/injector.d.ts +39 -72
- package/dist/runtime/react.d.ts +17 -12
- package/dist/runtime/svelte.d.ts +15 -0
- package/dist/runtime/types.d.ts +126 -4
- package/dist/runtime/utils.d.ts +0 -1
- package/dist/runtime/vue.d.ts +34 -14
- package/package.json +59 -66
- package/src/cli/commands/build.ts +133 -0
- package/src/cli/commands/cache.ts +371 -0
- package/src/cli/commands/init.ts +230 -0
- package/src/cli/commands/timeline.ts +435 -0
- package/src/cli/commands/watch.ts +211 -0
- package/src/cli/index.ts +226 -0
- package/src/cli/types.ts +100 -0
- package/src/cli/utils/config-loader.ts +174 -0
- package/src/cli/utils/file-utils.ts +139 -0
- package/src/cli/utils/logger.ts +74 -0
- package/src/compiler/Chain.ts +831 -0
- package/src/compiler/animations.ts +517 -0
- package/src/compiler/atomic-optimizer.ts +786 -0
- package/src/compiler/breakpoints.ts +347 -0
- package/src/compiler/btt.ts +1147 -0
- package/src/compiler/cache-manager.ts +446 -0
- package/src/compiler/commonProps.ts +18 -0
- package/src/compiler/content-addressable-cache.ts +478 -0
- package/src/compiler/helpers.ts +407 -0
- package/src/compiler/index.ts +72 -0
- package/src/compiler/prefixer.ts +720 -0
- package/src/compiler/shorthands.ts +558 -0
- package/src/compiler/suggestions.ts +436 -0
- package/src/compiler/theme-contract.ts +197 -0
- package/src/compiler/token-resolver.ts +241 -0
- package/src/compiler/tokens.ts +612 -0
- package/src/core/auto-detector.ts +187 -0
- package/src/core/common-utils.ts +423 -0
- package/src/core/compiler.ts +835 -0
- package/src/core/constants.ts +424 -0
- package/src/core/index.ts +107 -0
- package/src/core/smart-chain.ts +163 -0
- package/src/core/types.ts +257 -0
- package/src/core/utils.ts +598 -0
- package/src/index.ts +208 -0
- package/src/plugins/vite.d.ts +316 -0
- package/src/plugins/vite.ts +424 -0
- package/src/plugins/webpack.d.ts +289 -0
- package/src/plugins/webpack.ts +416 -0
- package/src/runtime/Chain.ts +242 -0
- package/src/runtime/auto-hooks.tsx +127 -0
- package/src/runtime/auto-vue.ts +72 -0
- package/src/runtime/hmr.ts +212 -0
- package/src/runtime/index.ts +82 -0
- package/src/runtime/injector.ts +273 -0
- package/src/runtime/react.tsx +269 -0
- package/src/runtime/svelte.ts +15 -0
- package/src/runtime/types.ts +256 -0
- package/src/runtime/utils.ts +128 -0
- package/src/runtime/vite-env.d.ts +120 -0
- package/src/runtime/vue.ts +231 -0
- package/tsconfig.build.json +41 -0
- package/tsconfig.json +25 -0
- package/tsconfig.runtimes.json +18 -0
- package/dist/cli/cli.cjs +0 -7
- package/dist/cli/commands/build.d.ts.map +0 -1
- package/dist/cli/commands/compile.d.ts +0 -3
- package/dist/cli/commands/compile.d.ts.map +0 -1
- package/dist/cli/commands/init.d.ts.map +0 -1
- package/dist/cli/commands/timeline.d.ts.map +0 -1
- package/dist/cli/commands/watch.d.ts.map +0 -1
- package/dist/cli/index.d.ts.map +0 -1
- package/dist/cli/types.d.ts.map +0 -1
- package/dist/cli/utils/config-loader.d.ts.map +0 -1
- package/dist/cli/utils/file-utils.d.ts.map +0 -1
- package/dist/cli/utils/logger.d.ts.map +0 -1
- package/dist/compiler/atomic-optimizer.d.ts.map +0 -1
- package/dist/compiler/btt.d.ts.map +0 -1
- package/dist/compiler/cache-manager.d.ts.map +0 -1
- package/dist/compiler/commonProps.d.ts.map +0 -1
- package/dist/compiler/index.d.ts.map +0 -1
- package/dist/compiler/prefixer.d.ts.map +0 -1
- package/dist/compiler/theme-contract.d.ts.map +0 -1
- package/dist/compiler/tokens.d.ts.map +0 -1
- package/dist/compiler/types.d.ts +0 -57
- package/dist/compiler/types.d.ts.map +0 -1
- package/dist/core/compiler.d.ts.map +0 -1
- package/dist/core/constants.d.ts.map +0 -1
- package/dist/core/index.d.ts +0 -4
- package/dist/core/index.d.ts.map +0 -1
- package/dist/core/types.d.ts.map +0 -1
- package/dist/core/utils.d.ts.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/plugins/vite.d.ts.map +0 -1
- package/dist/plugins/webpack.d.ts.map +0 -1
- package/dist/runtime/hmr.d.ts.map +0 -1
- package/dist/runtime/index.d.ts.map +0 -1
- package/dist/runtime/injector.d.ts.map +0 -1
- package/dist/runtime/react.d.ts.map +0 -1
- package/dist/runtime/react.js +0 -324
- package/dist/runtime/types.d.ts.map +0 -1
- package/dist/runtime/utils.d.ts.map +0 -1
- package/dist/runtime/vue.d.ts.map +0 -1
- package/dist/runtime/vue.js +0 -286
|
@@ -0,0 +1,424 @@
|
|
|
1
|
+
// chaincss/src/plugins/vite.ts
|
|
2
|
+
|
|
3
|
+
import { Plugin, HmrContext, ViteDevServer } from 'vite';
|
|
4
|
+
import { ChainCSSCompiler } from '../core/compiler.js';
|
|
5
|
+
import path from 'path';
|
|
6
|
+
import fs from 'fs';
|
|
7
|
+
|
|
8
|
+
export interface ChainCSSPluginOptions {
|
|
9
|
+
atomic?: boolean;
|
|
10
|
+
minify?: boolean;
|
|
11
|
+
verbose?: boolean;
|
|
12
|
+
hmr?: boolean;
|
|
13
|
+
injectGlobal?: boolean;
|
|
14
|
+
cssOutput?: string;
|
|
15
|
+
manifestOutput?: string;
|
|
16
|
+
include?: string[];
|
|
17
|
+
exclude?: string[];
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export default function chaincssPlugin(options: ChainCSSPluginOptions = {}): Plugin {
|
|
21
|
+
const compiler = new ChainCSSCompiler({
|
|
22
|
+
atomic: { enabled: options.atomic !== false },
|
|
23
|
+
output: { minify: options.minify || false },
|
|
24
|
+
verbose: options.verbose || false
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
const virtualCssId = 'virtual:chaincss.css';
|
|
28
|
+
const resolvedCssId = '\0' + virtualCssId;
|
|
29
|
+
|
|
30
|
+
const virtualManifestId = 'virtual:chaincss-manifest';
|
|
31
|
+
const resolvedManifestId = '\0' + virtualManifestId;
|
|
32
|
+
|
|
33
|
+
// Store generated data
|
|
34
|
+
let generatedCSS = '';
|
|
35
|
+
let generatedManifest: Record<string, any> = {};
|
|
36
|
+
let processedFiles = new Set<string>();
|
|
37
|
+
let lastHmrUpdate = 0;
|
|
38
|
+
let hmrTimeout: NodeJS.Timeout | null = null;
|
|
39
|
+
let server: ViteDevServer | null = null;
|
|
40
|
+
|
|
41
|
+
// Helper for verbose logging
|
|
42
|
+
function log(message: string, level: 'info' | 'warn' | 'error' = 'info') {
|
|
43
|
+
if (!options.verbose && level === 'info') return;
|
|
44
|
+
const prefix = '[ChainCSS]';
|
|
45
|
+
switch (level) {
|
|
46
|
+
case 'warn':
|
|
47
|
+
console.warn(`${prefix} ⚠️ ${message}`);
|
|
48
|
+
break;
|
|
49
|
+
case 'error':
|
|
50
|
+
console.error(`${prefix} ❌ ${message}`);
|
|
51
|
+
break;
|
|
52
|
+
default:
|
|
53
|
+
console.log(`${prefix} ${message}`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Helper to check if file should be processed
|
|
58
|
+
function shouldProcess(id: string): boolean {
|
|
59
|
+
if (id.startsWith('\0') || id.includes('virtual:')) return false;
|
|
60
|
+
if (id.includes('node_modules')) return false;
|
|
61
|
+
|
|
62
|
+
// Check exclude patterns
|
|
63
|
+
if (options.exclude) {
|
|
64
|
+
for (const pattern of options.exclude) {
|
|
65
|
+
if (id.includes(pattern)) return false;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Check include patterns
|
|
70
|
+
if (options.include) {
|
|
71
|
+
for (const pattern of options.include) {
|
|
72
|
+
if (id.includes(pattern)) return true;
|
|
73
|
+
}
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Default: process source files
|
|
78
|
+
const isUserFile = id.includes('/src/') || id.includes('/components/');
|
|
79
|
+
const isComponent = /\.(t|j)sx?$/.test(id);
|
|
80
|
+
|
|
81
|
+
return isUserFile && isComponent;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Get CSS from compiler safely
|
|
85
|
+
function updateCSS(): string {
|
|
86
|
+
try {
|
|
87
|
+
const freshCSS = compiler.getCombinedCSS();
|
|
88
|
+
if (freshCSS && freshCSS !== generatedCSS) {
|
|
89
|
+
generatedCSS = freshCSS;
|
|
90
|
+
if (options.verbose) {
|
|
91
|
+
log(`CSS updated: ${generatedCSS.length} bytes`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return generatedCSS;
|
|
95
|
+
} catch (error) {
|
|
96
|
+
log(`Failed to get CSS: ${(error as Error).message}`, 'error');
|
|
97
|
+
return generatedCSS;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Get manifest from compiler
|
|
102
|
+
function updateManifest(): Record<string, any> {
|
|
103
|
+
try {
|
|
104
|
+
const freshManifest = compiler.getAtomicMap();
|
|
105
|
+
if (JSON.stringify(freshManifest) !== JSON.stringify(generatedManifest)) {
|
|
106
|
+
generatedManifest = freshManifest;
|
|
107
|
+
if (options.verbose) {
|
|
108
|
+
log(`Manifest updated: ${Object.keys(generatedManifest).length} entries`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return generatedManifest;
|
|
112
|
+
} catch (error) {
|
|
113
|
+
log(`Failed to get manifest: ${(error as Error).message}`, 'error');
|
|
114
|
+
return generatedManifest;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Send HMR update
|
|
119
|
+
function sendHMRUpdate() {
|
|
120
|
+
if (!server || !options.hmr !== false) return;
|
|
121
|
+
|
|
122
|
+
// Debounce HMR updates
|
|
123
|
+
if (hmrTimeout) clearTimeout(hmrTimeout);
|
|
124
|
+
hmrTimeout = setTimeout(() => {
|
|
125
|
+
const now = Date.now();
|
|
126
|
+
if (now - lastHmrUpdate < 100) return;
|
|
127
|
+
lastHmrUpdate = now;
|
|
128
|
+
|
|
129
|
+
const css = updateCSS();
|
|
130
|
+
const manifest = updateManifest();
|
|
131
|
+
|
|
132
|
+
server!.ws.send({
|
|
133
|
+
type: 'custom',
|
|
134
|
+
event: 'chaincss:update',
|
|
135
|
+
data: {
|
|
136
|
+
css,
|
|
137
|
+
map: manifest,
|
|
138
|
+
timestamp: now
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
if (options.verbose) {
|
|
143
|
+
log(`HMR update sent: ${css.length} bytes`);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
hmrTimeout = null;
|
|
147
|
+
}, 50);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Generate bootstrap code with proper CSS injection
|
|
151
|
+
function generateBootstrapCode(css: string): string {
|
|
152
|
+
const shouldInjectGlobal = options.injectGlobal !== false;
|
|
153
|
+
|
|
154
|
+
if (!shouldInjectGlobal) {
|
|
155
|
+
return `
|
|
156
|
+
// ChainCSS Runtime Bootstrap (No CSS Injection)
|
|
157
|
+
import manifest from "virtual:chaincss-manifest";
|
|
158
|
+
import { setManifest } from "chaincss/runtime";
|
|
159
|
+
|
|
160
|
+
try {
|
|
161
|
+
setManifest(manifest);
|
|
162
|
+
console.log("[ChainCSS] ✅ Runtime initialized");
|
|
163
|
+
} catch (err) {
|
|
164
|
+
console.error("[ChainCSS] Failed to initialize:", err);
|
|
165
|
+
}
|
|
166
|
+
`;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Escape CSS for injection
|
|
170
|
+
const escapedCSS = css
|
|
171
|
+
.replace(/\\/g, '\\\\')
|
|
172
|
+
.replace(/`/g, '\\`')
|
|
173
|
+
.replace(/\$/g, '\\$');
|
|
174
|
+
|
|
175
|
+
return `
|
|
176
|
+
// ChainCSS Runtime Bootstrap
|
|
177
|
+
import manifest from "virtual:chaincss-manifest";
|
|
178
|
+
import { setManifest } from "chaincss/runtime";
|
|
179
|
+
|
|
180
|
+
// Initialize ChainCSS
|
|
181
|
+
try {
|
|
182
|
+
setManifest(manifest);
|
|
183
|
+
console.log("[ChainCSS] ✅ Runtime initialized");
|
|
184
|
+
} catch (err) {
|
|
185
|
+
console.error("[ChainCSS] Failed to initialize:", err);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Inject CSS
|
|
189
|
+
(function() {
|
|
190
|
+
const css = \`${escapedCSS}\`;
|
|
191
|
+
const styleId = 'chaincss-injected-styles';
|
|
192
|
+
|
|
193
|
+
if (css && css.trim()) {
|
|
194
|
+
let styleTag = document.getElementById(styleId);
|
|
195
|
+
if (!styleTag) {
|
|
196
|
+
styleTag = document.createElement('style');
|
|
197
|
+
styleTag.id = styleId;
|
|
198
|
+
styleTag.setAttribute('data-chaincss', 'true');
|
|
199
|
+
document.head.appendChild(styleTag);
|
|
200
|
+
}
|
|
201
|
+
styleTag.textContent = css;
|
|
202
|
+
console.log("[ChainCSS] ✅ Injected", css.length, "bytes of CSS");
|
|
203
|
+
} else if (document.getElementById(styleId)) {
|
|
204
|
+
// Remove empty style tag
|
|
205
|
+
const existing = document.getElementById(styleId);
|
|
206
|
+
if (existing) existing.remove();
|
|
207
|
+
}
|
|
208
|
+
})();
|
|
209
|
+
|
|
210
|
+
// HMR Support
|
|
211
|
+
if (import.meta.hot) {
|
|
212
|
+
import.meta.hot.on('chaincss:update', (data) => {
|
|
213
|
+
if (data.map) setManifest({ atomicMap: data.map });
|
|
214
|
+
if (data.css) {
|
|
215
|
+
const styleTag = document.getElementById('chaincss-injected-styles');
|
|
216
|
+
if (styleTag) {
|
|
217
|
+
styleTag.textContent = data.css;
|
|
218
|
+
console.log("[ChainCSS] 🔄 HMR update:", data.css.length, "bytes");
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
// Accept self for HMR
|
|
224
|
+
import.meta.hot.accept();
|
|
225
|
+
}
|
|
226
|
+
`;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
return {
|
|
230
|
+
name: 'chaincss',
|
|
231
|
+
enforce: 'pre' as const,
|
|
232
|
+
|
|
233
|
+
configureServer(_server: ViteDevServer) {
|
|
234
|
+
server = _server;
|
|
235
|
+
log('Vite plugin initialized');
|
|
236
|
+
|
|
237
|
+
// Watch for config changes
|
|
238
|
+
_server.watcher.on('change', (filePath) => {
|
|
239
|
+
if (filePath.includes('chaincss.config')) {
|
|
240
|
+
log('Config changed, clearing cache...');
|
|
241
|
+
compiler.clearCSS();
|
|
242
|
+
processedFiles.clear();
|
|
243
|
+
updateCSS();
|
|
244
|
+
updateManifest();
|
|
245
|
+
sendHMRUpdate();
|
|
246
|
+
}
|
|
247
|
+
});
|
|
248
|
+
},
|
|
249
|
+
|
|
250
|
+
resolveId(id: string) {
|
|
251
|
+
if (id === virtualCssId) return resolvedCssId;
|
|
252
|
+
if (id === virtualManifestId) return resolvedManifestId;
|
|
253
|
+
return null;
|
|
254
|
+
},
|
|
255
|
+
|
|
256
|
+
load(id: string) {
|
|
257
|
+
if (id === resolvedManifestId) {
|
|
258
|
+
const manifest = updateManifest();
|
|
259
|
+
const manifestData = {
|
|
260
|
+
atomicMap: manifest,
|
|
261
|
+
version: '2.0.0',
|
|
262
|
+
timestamp: Date.now()
|
|
263
|
+
};
|
|
264
|
+
return `export default ${JSON.stringify(manifestData)};`;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
if (id === resolvedCssId) {
|
|
268
|
+
const css = updateCSS();
|
|
269
|
+
return css || '/* ChainCSS: No styles */';
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
return null;
|
|
273
|
+
},
|
|
274
|
+
|
|
275
|
+
async transform(source: string, id: string) {
|
|
276
|
+
if (!shouldProcess(id)) return null;
|
|
277
|
+
|
|
278
|
+
const fileName = path.basename(id);
|
|
279
|
+
|
|
280
|
+
try {
|
|
281
|
+
// Skip if already processed (with cache)
|
|
282
|
+
if (processedFiles.has(id) && !source.includes('chain(')) {
|
|
283
|
+
return null;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
log(`Processing: ${fileName}`);
|
|
287
|
+
processedFiles.add(id);
|
|
288
|
+
|
|
289
|
+
// Compile the source
|
|
290
|
+
await compiler.compileSource(source, id);
|
|
291
|
+
|
|
292
|
+
// Update stored data
|
|
293
|
+
updateCSS();
|
|
294
|
+
updateManifest();
|
|
295
|
+
|
|
296
|
+
// Send HMR update if needed
|
|
297
|
+
if (server && options.hmr !== false) {
|
|
298
|
+
sendHMRUpdate();
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// Check if this is an entry file
|
|
302
|
+
const isEntryFile = /(main|index|App|entry)\.(t|j)sx?$/.test(id);
|
|
303
|
+
|
|
304
|
+
if (isEntryFile && !source.includes('virtual:chaincss.css')) {
|
|
305
|
+
const bootstrapCode = generateBootstrapCode(generatedCSS);
|
|
306
|
+
log(`Bootstrapping entry file: ${fileName} (${generatedCSS.length} bytes)`);
|
|
307
|
+
|
|
308
|
+
return {
|
|
309
|
+
code: `${bootstrapCode}\n${source}`,
|
|
310
|
+
map: null
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
return null;
|
|
315
|
+
} catch (error) {
|
|
316
|
+
log(`Failed to process ${fileName}: ${(error as Error).message}`, 'error');
|
|
317
|
+
return null;
|
|
318
|
+
}
|
|
319
|
+
},
|
|
320
|
+
|
|
321
|
+
handleHotUpdate({ file, server: hotServer, modules }: HmrContext) {
|
|
322
|
+
if (!shouldProcess(file)) return modules;
|
|
323
|
+
|
|
324
|
+
log(`HMR update: ${path.basename(file)}`);
|
|
325
|
+
|
|
326
|
+
// Clear processed flag to force reprocessing
|
|
327
|
+
processedFiles.delete(file);
|
|
328
|
+
|
|
329
|
+
// Clear compiler cache for this file
|
|
330
|
+
compiler.clearCSS();
|
|
331
|
+
|
|
332
|
+
// Update data
|
|
333
|
+
const css = updateCSS();
|
|
334
|
+
const manifest = updateManifest();
|
|
335
|
+
|
|
336
|
+
// Send HMR update
|
|
337
|
+
if (options.hmr !== false) {
|
|
338
|
+
hotServer.ws.send({
|
|
339
|
+
type: 'custom',
|
|
340
|
+
event: 'chaincss:update',
|
|
341
|
+
data: {
|
|
342
|
+
css,
|
|
343
|
+
map: manifest,
|
|
344
|
+
file: path.basename(file),
|
|
345
|
+
timestamp: Date.now()
|
|
346
|
+
}
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
// Return modules to invalidate
|
|
351
|
+
const cssModule = [...modules].find(m => m.id === resolvedCssId);
|
|
352
|
+
if (cssModule) {
|
|
353
|
+
return [...modules, cssModule];
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
return modules;
|
|
357
|
+
},
|
|
358
|
+
|
|
359
|
+
buildStart() {
|
|
360
|
+
log('Build started');
|
|
361
|
+
processedFiles.clear();
|
|
362
|
+
generatedCSS = '';
|
|
363
|
+
generatedManifest = {};
|
|
364
|
+
compiler.clearCSS();
|
|
365
|
+
},
|
|
366
|
+
|
|
367
|
+
buildEnd() {
|
|
368
|
+
const finalCSS = updateCSS();
|
|
369
|
+
log(`Build complete - Final CSS: ${finalCSS.length} bytes`);
|
|
370
|
+
|
|
371
|
+
// Write CSS to file if output specified
|
|
372
|
+
if (options.cssOutput) {
|
|
373
|
+
try {
|
|
374
|
+
const outputPath = path.resolve(process.cwd(), options.cssOutput);
|
|
375
|
+
const outputDir = path.dirname(outputPath);
|
|
376
|
+
if (!fs.existsSync(outputDir)) {
|
|
377
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
378
|
+
}
|
|
379
|
+
fs.writeFileSync(outputPath, finalCSS, 'utf8');
|
|
380
|
+
log(`CSS written to: ${outputPath}`);
|
|
381
|
+
} catch (error) {
|
|
382
|
+
log(`Failed to write CSS: ${(error as Error).message}`, 'error');
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
// Write manifest if output specified
|
|
387
|
+
if (options.manifestOutput) {
|
|
388
|
+
try {
|
|
389
|
+
const manifestPath = path.resolve(process.cwd(), options.manifestOutput);
|
|
390
|
+
const manifestDir = path.dirname(manifestPath);
|
|
391
|
+
if (!fs.existsSync(manifestDir)) {
|
|
392
|
+
fs.mkdirSync(manifestDir, { recursive: true });
|
|
393
|
+
}
|
|
394
|
+
fs.writeFileSync(manifestPath, JSON.stringify(generatedManifest, null, 2), 'utf8');
|
|
395
|
+
log(`Manifest written to: ${manifestPath}`);
|
|
396
|
+
} catch (error) {
|
|
397
|
+
log(`Failed to write manifest: ${(error as Error).message}`, 'error');
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
},
|
|
401
|
+
|
|
402
|
+
generateBundle(_options, bundle) {
|
|
403
|
+
// Ensure CSS is included in the bundle
|
|
404
|
+
for (const [fileName, chunk] of Object.entries(bundle)) {
|
|
405
|
+
if (fileName.endsWith('.css') && generatedCSS) {
|
|
406
|
+
// @ts-ignore
|
|
407
|
+
if (!chunk.source || (chunk.source && chunk.source.length === 0)) {
|
|
408
|
+
// @ts-ignore
|
|
409
|
+
chunk.source = generatedCSS;
|
|
410
|
+
log(`Wrote ${generatedCSS.length} bytes to ${fileName}`);
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
},
|
|
415
|
+
|
|
416
|
+
// Clean up on close
|
|
417
|
+
closeBundle() {
|
|
418
|
+
if (hmrTimeout) {
|
|
419
|
+
clearTimeout(hmrTimeout);
|
|
420
|
+
}
|
|
421
|
+
log('Plugin closed');
|
|
422
|
+
}
|
|
423
|
+
};
|
|
424
|
+
}
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
// chaincss/src/plugins/webpack.d.ts
|
|
2
|
+
|
|
3
|
+
import { LoaderDefinition } from 'webpack';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* ChainCSS Webpack Loader Options
|
|
7
|
+
*/
|
|
8
|
+
export interface ChainCSSLoaderOptions {
|
|
9
|
+
/**
|
|
10
|
+
* Mode: 'build' for production (zero-runtime), 'runtime' for development
|
|
11
|
+
* @default process.env.NODE_ENV === 'production' ? 'build' : 'runtime'
|
|
12
|
+
*/
|
|
13
|
+
mode?: 'build' | 'runtime';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Enable atomic CSS optimization
|
|
17
|
+
* @default false
|
|
18
|
+
*/
|
|
19
|
+
atomic?: boolean;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Enable CSS minification
|
|
23
|
+
* @default process.env.NODE_ENV === 'production'
|
|
24
|
+
*/
|
|
25
|
+
minify?: boolean;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Enable source maps
|
|
29
|
+
* @default false
|
|
30
|
+
*/
|
|
31
|
+
sourceMap?: boolean;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Output directory for compiled CSS
|
|
35
|
+
* @default '.chaincss-cache'
|
|
36
|
+
*/
|
|
37
|
+
outputDir?: string;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Verbose logging
|
|
41
|
+
* @default false
|
|
42
|
+
*/
|
|
43
|
+
verbose?: boolean;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Enable CSS extraction to separate file
|
|
47
|
+
* @default false
|
|
48
|
+
*/
|
|
49
|
+
extractCSS?: boolean;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Enable Hot Module Replacement
|
|
53
|
+
* @default true in development
|
|
54
|
+
*/
|
|
55
|
+
hmr?: boolean;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Custom cache key for compilation
|
|
59
|
+
*/
|
|
60
|
+
cacheKey?: string;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Framework to generate components for
|
|
64
|
+
* @default 'auto'
|
|
65
|
+
*/
|
|
66
|
+
framework?: 'react' | 'vue' | 'svelte' | 'solid' | 'auto';
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Generate TypeScript type definitions
|
|
70
|
+
* @default false
|
|
71
|
+
*/
|
|
72
|
+
generateTypes?: boolean;
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Enable design tokens
|
|
76
|
+
* @default true
|
|
77
|
+
*/
|
|
78
|
+
tokens?: boolean;
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Custom breakpoint definitions
|
|
82
|
+
*/
|
|
83
|
+
breakpoints?: Record<string, string>;
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* CSS class name prefix
|
|
87
|
+
* @default 'chain'
|
|
88
|
+
*/
|
|
89
|
+
classPrefix?: string;
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Enable style timeline tracking
|
|
93
|
+
* @default false
|
|
94
|
+
*/
|
|
95
|
+
timeline?: boolean;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* ChainCSS Webpack Loader
|
|
100
|
+
*
|
|
101
|
+
* A webpack loader that processes ChainCSS files (.chain.js/.chain.ts)
|
|
102
|
+
* and converts them to static CSS at build time.
|
|
103
|
+
*
|
|
104
|
+
* @example
|
|
105
|
+
* ```js
|
|
106
|
+
* // webpack.config.js
|
|
107
|
+
* module.exports = {
|
|
108
|
+
* module: {
|
|
109
|
+
* rules: [
|
|
110
|
+
* {
|
|
111
|
+
* test: /\.chain\.(js|ts)$/,
|
|
112
|
+
* use: [
|
|
113
|
+
* 'babel-loader',
|
|
114
|
+
* {
|
|
115
|
+
* loader: 'chaincss/plugin/webpack',
|
|
116
|
+
* options: {
|
|
117
|
+
* mode: process.env.NODE_ENV === 'production' ? 'build' : 'runtime',
|
|
118
|
+
* atomic: true,
|
|
119
|
+
* minify: process.env.NODE_ENV === 'production',
|
|
120
|
+
* verbose: process.env.NODE_ENV === 'development'
|
|
121
|
+
* }
|
|
122
|
+
* }
|
|
123
|
+
* ]
|
|
124
|
+
* }
|
|
125
|
+
* ]
|
|
126
|
+
* }
|
|
127
|
+
* };
|
|
128
|
+
* ```
|
|
129
|
+
*
|
|
130
|
+
* @example
|
|
131
|
+
* ```js
|
|
132
|
+
* // With custom output directory
|
|
133
|
+
* {
|
|
134
|
+
* loader: 'chaincss/plugin/webpack',
|
|
135
|
+
* options: {
|
|
136
|
+
* outputDir: 'dist/styles',
|
|
137
|
+
* extractCSS: true,
|
|
138
|
+
* framework: 'react'
|
|
139
|
+
* }
|
|
140
|
+
* }
|
|
141
|
+
* ```
|
|
142
|
+
*/
|
|
143
|
+
declare const loader: LoaderDefinition<ChainCSSLoaderOptions>;
|
|
144
|
+
|
|
145
|
+
// Default export
|
|
146
|
+
export default loader;
|
|
147
|
+
|
|
148
|
+
// Named export for direct import
|
|
149
|
+
export { loader as chaincssLoader };
|
|
150
|
+
|
|
151
|
+
// Re-export LoaderDefinition for convenience
|
|
152
|
+
export type { LoaderDefinition } from 'webpack';
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* ChainCSS Runtime API for webpack
|
|
156
|
+
*/
|
|
157
|
+
export namespace ChainCSSWebpack {
|
|
158
|
+
/**
|
|
159
|
+
* Generated styles interface
|
|
160
|
+
*/
|
|
161
|
+
interface Styles {
|
|
162
|
+
[key: string]: string;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* CSS extraction plugin options
|
|
167
|
+
*/
|
|
168
|
+
interface ExtractCSSPluginOptions {
|
|
169
|
+
/**
|
|
170
|
+
* Output filename for extracted CSS
|
|
171
|
+
* @default '[name].css'
|
|
172
|
+
*/
|
|
173
|
+
filename?: string;
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Enable chunk CSS extraction
|
|
177
|
+
* @default true
|
|
178
|
+
*/
|
|
179
|
+
chunkFilename?: string;
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Enable source maps
|
|
183
|
+
* @default false
|
|
184
|
+
*/
|
|
185
|
+
sourceMap?: boolean;
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Ignore order warnings
|
|
189
|
+
* @default false
|
|
190
|
+
*/
|
|
191
|
+
ignoreOrder?: boolean;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* ChainCSS Webpack Plugin (for full builds)
|
|
196
|
+
*/
|
|
197
|
+
interface ChainCSSWebpackPlugin {
|
|
198
|
+
/**
|
|
199
|
+
* Apply the plugin to webpack compiler
|
|
200
|
+
*/
|
|
201
|
+
apply(compiler: any): void;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Create a ChainCSS webpack plugin
|
|
206
|
+
*/
|
|
207
|
+
function createPlugin(options?: {
|
|
208
|
+
/**
|
|
209
|
+
* Enable atomic CSS
|
|
210
|
+
* @default true
|
|
211
|
+
*/
|
|
212
|
+
atomic?: boolean;
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Output directory for CSS files
|
|
216
|
+
* @default 'dist/css'
|
|
217
|
+
*/
|
|
218
|
+
outputDir?: string;
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Enable CSS minification
|
|
222
|
+
* @default process.env.NODE_ENV === 'production'
|
|
223
|
+
*/
|
|
224
|
+
minify?: boolean;
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Generate TypeScript types
|
|
228
|
+
* @default false
|
|
229
|
+
*/
|
|
230
|
+
generateTypes?: boolean;
|
|
231
|
+
}): ChainCSSWebpackPlugin;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// Augment webpack module types
|
|
235
|
+
declare module 'webpack' {
|
|
236
|
+
interface Configuration {
|
|
237
|
+
/**
|
|
238
|
+
* ChainCSS specific configuration
|
|
239
|
+
*/
|
|
240
|
+
chaincss?: {
|
|
241
|
+
/**
|
|
242
|
+
* Enable ChainCSS processing
|
|
243
|
+
*/
|
|
244
|
+
enabled?: boolean;
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* ChainCSS loader options
|
|
248
|
+
*/
|
|
249
|
+
loaderOptions?: ChainCSSLoaderOptions;
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Files to include
|
|
253
|
+
*/
|
|
254
|
+
include?: RegExp | RegExp[];
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Files to exclude
|
|
258
|
+
*/
|
|
259
|
+
exclude?: RegExp | RegExp[];
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
interface LoaderContext {
|
|
264
|
+
/**
|
|
265
|
+
* ChainCSS specific properties
|
|
266
|
+
*/
|
|
267
|
+
chaincss?: {
|
|
268
|
+
/**
|
|
269
|
+
* Whether the file has been processed
|
|
270
|
+
*/
|
|
271
|
+
processed: boolean;
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Compiled CSS content
|
|
275
|
+
*/
|
|
276
|
+
css?: string;
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Compiled class map
|
|
280
|
+
*/
|
|
281
|
+
classMap?: Record<string, string>;
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// Export all types
|
|
287
|
+
export type {
|
|
288
|
+
LoaderDefinition as WebpackLoaderDefinition
|
|
289
|
+
};
|