chaincss 1.13.3 → 2.0.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/CHANGELOG.md +81 -0
- package/LICENSE +2 -3
- package/README.md +238 -105
- package/dist/cli/commands/build.d.ts +3 -0
- package/dist/cli/commands/build.d.ts.map +1 -0
- package/dist/cli/commands/compile.d.ts +3 -0
- package/dist/cli/commands/compile.d.ts.map +1 -0
- package/dist/cli/commands/init.d.ts +5 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/timeline.d.ts +2 -0
- package/dist/cli/commands/timeline.d.ts.map +1 -0
- package/dist/cli/commands/watch.d.ts +6 -0
- package/dist/cli/commands/watch.d.ts.map +1 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +5960 -0
- package/dist/cli/types.d.ts +51 -0
- package/dist/cli/types.d.ts.map +1 -0
- package/dist/cli/utils/config-loader.d.ts +8 -0
- package/dist/cli/utils/config-loader.d.ts.map +1 -0
- package/dist/cli/utils/file-utils.d.ts +9 -0
- package/dist/cli/utils/file-utils.d.ts.map +1 -0
- package/dist/cli/utils/logger.d.ts +17 -0
- package/dist/cli/utils/logger.d.ts.map +1 -0
- package/dist/compiler/atomic-optimizer.d.ts +76 -0
- package/dist/compiler/atomic-optimizer.d.ts.map +1 -0
- package/dist/compiler/btt.d.ts +138 -0
- package/dist/compiler/btt.d.ts.map +1 -0
- package/dist/compiler/cache-manager.d.ts +20 -0
- package/dist/compiler/cache-manager.d.ts.map +1 -0
- package/dist/compiler/commonProps.d.ts +2 -0
- package/dist/compiler/commonProps.d.ts.map +1 -0
- package/dist/compiler/index.d.ts +12 -0
- package/dist/compiler/index.d.ts.map +1 -0
- package/dist/compiler/index.js +5177 -0
- package/dist/compiler/prefixer.d.ts +42 -0
- package/dist/compiler/prefixer.d.ts.map +1 -0
- package/dist/compiler/theme-contract.d.ts +61 -0
- package/dist/compiler/theme-contract.d.ts.map +1 -0
- package/dist/compiler/tokens.d.ts +52 -0
- package/dist/compiler/tokens.d.ts.map +1 -0
- package/dist/compiler/types.d.ts +57 -0
- package/dist/compiler/types.d.ts.map +1 -0
- package/dist/core/compiler.d.ts +32 -0
- package/dist/core/compiler.d.ts.map +1 -0
- package/dist/core/constants.d.ts +129 -0
- package/dist/core/constants.d.ts.map +1 -0
- package/dist/core/index.d.ts +4 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/types.d.ts +88 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/utils.d.ts +37 -0
- package/dist/core/utils.d.ts.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5667 -0
- package/dist/plugins/vite.d.ts +11 -0
- package/dist/plugins/vite.d.ts.map +1 -0
- package/dist/plugins/vite.js +25839 -0
- package/dist/plugins/webpack.d.ts +45 -0
- package/dist/plugins/webpack.d.ts.map +1 -0
- package/dist/plugins/webpack.js +107 -0
- package/dist/runtime/hmr.d.ts +3 -0
- package/dist/runtime/hmr.d.ts.map +1 -0
- package/dist/runtime/index.d.ts +15 -0
- package/dist/runtime/index.d.ts.map +1 -0
- package/dist/runtime/index.js +552 -0
- package/dist/runtime/injector.d.ts +85 -0
- package/dist/runtime/injector.d.ts.map +1 -0
- package/dist/runtime/react.d.ts +54 -0
- package/dist/runtime/react.d.ts.map +1 -0
- package/dist/runtime/react.js +270 -0
- package/dist/runtime/types.d.ts +45 -0
- package/dist/runtime/types.d.ts.map +1 -0
- package/dist/runtime/utils.d.ts +62 -0
- package/dist/runtime/utils.d.ts.map +1 -0
- package/dist/runtime/vue.d.ts +52 -0
- package/dist/runtime/vue.d.ts.map +1 -0
- package/dist/runtime/vue.js +232 -0
- package/package.json +90 -119
- package/browser/commonProps.js +0 -14
- package/browser/index.js +0 -3
- package/browser/react-hooks.js +0 -162
- package/browser/rtt.js +0 -400
- package/browser/vue-composables.js +0 -200
- package/node/atomic-optimizer.js +0 -526
- package/node/btt.js +0 -1009
- package/node/cache-manager.js +0 -56
- package/node/chaincss.js +0 -642
- package/node/index.js +0 -2
- package/node/loaders/chaincss-loader.js +0 -62
- package/node/plugins/next-plugin.js +0 -120
- package/node/plugins/vite-plugin.js +0 -383
- package/node/plugins/webpack-plugin.js +0 -41
- package/node/prefixer.js +0 -237
- package/node/strVal.js +0 -92
- package/node/theme-validator.js +0 -32
- package/shared/theme-contract.js +0 -98
- package/shared/tokens.cjs +0 -256
- package/shared/tokens.mjs +0 -320
- package/types.d.ts +0 -325
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
// node/loaders/chaincss-loader.js
|
|
2
|
-
const path = require('path');
|
|
3
|
-
const { execSync } = require('child_process');
|
|
4
|
-
const fs = require('fs');
|
|
5
|
-
|
|
6
|
-
module.exports = function(source) {
|
|
7
|
-
const callback = this.async();
|
|
8
|
-
const options = this.getOptions() || {};
|
|
9
|
-
|
|
10
|
-
const mode = options.mode || (process.env.NODE_ENV === 'production' ? 'build' : 'runtime');
|
|
11
|
-
|
|
12
|
-
if (mode === 'runtime') {
|
|
13
|
-
const code = `
|
|
14
|
-
import { $, compile } from '@melcanz85/chaincss';
|
|
15
|
-
const styles = (() => {
|
|
16
|
-
${source}
|
|
17
|
-
return { ${extractStyleNames(source)} };
|
|
18
|
-
})();
|
|
19
|
-
export default styles;
|
|
20
|
-
`;
|
|
21
|
-
callback(null, code);
|
|
22
|
-
return;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
try {
|
|
26
|
-
const tempFile = path.join(this.context, '.temp.jcss');
|
|
27
|
-
fs.writeFileSync(tempFile, source);
|
|
28
|
-
|
|
29
|
-
const outputDir = path.join(process.cwd(), '.chaincss-cache');
|
|
30
|
-
if (!fs.existsSync(outputDir)) {
|
|
31
|
-
fs.mkdirSync(outputDir, { recursive: true });
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const cmd = `node ${path.join(__dirname, '../chaincss.js')} ${tempFile} ${outputDir} ${options.atomic ? '--atomic' : ''}`;
|
|
35
|
-
execSync(cmd, { stdio: 'pipe' });
|
|
36
|
-
|
|
37
|
-
const cssPath = path.join(outputDir, 'global.css');
|
|
38
|
-
const css = fs.readFileSync(cssPath, 'utf8');
|
|
39
|
-
|
|
40
|
-
fs.unlinkSync(tempFile);
|
|
41
|
-
|
|
42
|
-
const code = `
|
|
43
|
-
const css = ${JSON.stringify(css)};
|
|
44
|
-
if (typeof document !== 'undefined') {
|
|
45
|
-
const style = document.createElement('style');
|
|
46
|
-
style.setAttribute('data-chaincss', ${JSON.stringify(this.resourcePath)});
|
|
47
|
-
style.textContent = css;
|
|
48
|
-
document.head.appendChild(style);
|
|
49
|
-
}
|
|
50
|
-
export default {};
|
|
51
|
-
`;
|
|
52
|
-
callback(null, code);
|
|
53
|
-
} catch (err) {
|
|
54
|
-
callback(err);
|
|
55
|
-
}
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
function extractStyleNames(source) {
|
|
59
|
-
const matches = source.match(/const\s+(\w+)\s*=\s*\$\(\)/g);
|
|
60
|
-
if (!matches) return '';
|
|
61
|
-
return matches.map(m => m.match(/const\s+(\w+)/)[1]).join(', ');
|
|
62
|
-
}
|
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
const path = require('path');
|
|
2
|
-
|
|
3
|
-
module.exports = function withChainCSS(nextConfig = {}) {
|
|
4
|
-
return {
|
|
5
|
-
...nextConfig,
|
|
6
|
-
webpack(config, options) {
|
|
7
|
-
// Add loader for .jcss files (works in RSC)
|
|
8
|
-
config.module.rules.push({
|
|
9
|
-
test: /\.jcss$/,
|
|
10
|
-
use: [
|
|
11
|
-
options.defaultLoaders.babel,
|
|
12
|
-
{
|
|
13
|
-
loader: path.resolve(__dirname, '../loaders/chaincss-loader.js'),
|
|
14
|
-
options: {
|
|
15
|
-
mode: 'build', // Build mode for RSC - extracts CSS
|
|
16
|
-
atomic: true
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
]
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
// Enable CSS extraction for RSC
|
|
23
|
-
if (options.isServer) {
|
|
24
|
-
config.optimization = {
|
|
25
|
-
...config.optimization,
|
|
26
|
-
splitChunks: {
|
|
27
|
-
cacheGroups: {
|
|
28
|
-
styles: {
|
|
29
|
-
name: 'styles',
|
|
30
|
-
type: 'css/mini-extract',
|
|
31
|
-
chunks: 'all',
|
|
32
|
-
enforce: true
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
};
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
if (typeof nextConfig.webpack === 'function') {
|
|
40
|
-
return nextConfig.webpack(config, options);
|
|
41
|
-
}
|
|
42
|
-
return config;
|
|
43
|
-
},
|
|
44
|
-
|
|
45
|
-
// Enable CSS support in App Router
|
|
46
|
-
experimental: {
|
|
47
|
-
...nextConfig.experimental,
|
|
48
|
-
turbo: {
|
|
49
|
-
...nextConfig.experimental?.turbo,
|
|
50
|
-
rules: {
|
|
51
|
-
...nextConfig.experimental?.turbo?.rules,
|
|
52
|
-
'*.jcss': {
|
|
53
|
-
loaders: ['chaincss/loader'],
|
|
54
|
-
as: '*.css'
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
};
|
|
60
|
-
};
|
|
61
|
-
const path = require('path');
|
|
62
|
-
|
|
63
|
-
module.exports = function withChainCSS(nextConfig = {}) {
|
|
64
|
-
return {
|
|
65
|
-
...nextConfig,
|
|
66
|
-
webpack(config, options) {
|
|
67
|
-
// Add loader for .jcss files (works in RSC)
|
|
68
|
-
config.module.rules.push({
|
|
69
|
-
test: /\.jcss$/,
|
|
70
|
-
use: [
|
|
71
|
-
options.defaultLoaders.babel,
|
|
72
|
-
{
|
|
73
|
-
loader: path.resolve(__dirname, '../loaders/chaincss-loader.js'),
|
|
74
|
-
options: {
|
|
75
|
-
mode: 'build', // Build mode for RSC - extracts CSS
|
|
76
|
-
atomic: true
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
]
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
// Enable CSS extraction for RSC
|
|
83
|
-
if (options.isServer) {
|
|
84
|
-
config.optimization = {
|
|
85
|
-
...config.optimization,
|
|
86
|
-
splitChunks: {
|
|
87
|
-
cacheGroups: {
|
|
88
|
-
styles: {
|
|
89
|
-
name: 'styles',
|
|
90
|
-
type: 'css/mini-extract',
|
|
91
|
-
chunks: 'all',
|
|
92
|
-
enforce: true
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
if (typeof nextConfig.webpack === 'function') {
|
|
100
|
-
return nextConfig.webpack(config, options);
|
|
101
|
-
}
|
|
102
|
-
return config;
|
|
103
|
-
},
|
|
104
|
-
|
|
105
|
-
// Enable CSS support in App Router
|
|
106
|
-
experimental: {
|
|
107
|
-
...nextConfig.experimental,
|
|
108
|
-
turbo: {
|
|
109
|
-
...nextConfig.experimental?.turbo,
|
|
110
|
-
rules: {
|
|
111
|
-
...nextConfig.experimental?.turbo?.rules,
|
|
112
|
-
'*.jcss': {
|
|
113
|
-
loaders: ['chaincss/loader'],
|
|
114
|
-
as: '*.css'
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
};
|
|
120
|
-
};
|
|
@@ -1,383 +0,0 @@
|
|
|
1
|
-
import path from 'node:path';
|
|
2
|
-
import fs from 'node:fs';
|
|
3
|
-
import { createRequire } from 'node:module';
|
|
4
|
-
import CleanCSS from 'clean-css';
|
|
5
|
-
import { $, run, compile as originalCompile, chain } from '../btt.js';
|
|
6
|
-
|
|
7
|
-
const require = createRequire(import.meta.url);
|
|
8
|
-
|
|
9
|
-
// Optional: Try to load prefixer
|
|
10
|
-
let prefixer;
|
|
11
|
-
try {
|
|
12
|
-
const ChainCSSPrefixer = (await import('../prefixer.js')).default;
|
|
13
|
-
prefixer = new ChainCSSPrefixer({ enabled: true });
|
|
14
|
-
} catch (err) {
|
|
15
|
-
console.warn('ChainCSS: Prefixer not available, autoprefixing disabled');
|
|
16
|
-
prefixer = { process: async (css) => ({ css }) };
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
// Cache for processed files
|
|
20
|
-
const fileCache = new Map();
|
|
21
|
-
const compiledCache = new Map();
|
|
22
|
-
|
|
23
|
-
// Helper to compile script without temp files
|
|
24
|
-
const compileScript = (scriptBlock, filename, get) => {
|
|
25
|
-
const dirname = path.dirname(filename);
|
|
26
|
-
|
|
27
|
-
chain.cssOutput = '';
|
|
28
|
-
|
|
29
|
-
const fn = new Function(
|
|
30
|
-
'$',
|
|
31
|
-
'run',
|
|
32
|
-
'compile',
|
|
33
|
-
'chain',
|
|
34
|
-
'get',
|
|
35
|
-
'__filename',
|
|
36
|
-
'__dirname',
|
|
37
|
-
scriptBlock
|
|
38
|
-
);
|
|
39
|
-
|
|
40
|
-
fn($, run, originalCompile, chain, get, filename, dirname);
|
|
41
|
-
|
|
42
|
-
return chain.cssOutput || '';
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
const processJavascriptBlocks = (content, filename, get) => {
|
|
46
|
-
const blocks = content.split(/<@([\s\S]*?)@>/gm);
|
|
47
|
-
let output = '';
|
|
48
|
-
|
|
49
|
-
for (let i = 0; i < blocks.length; i++) {
|
|
50
|
-
if (i % 2 === 0) {
|
|
51
|
-
output += blocks[i];
|
|
52
|
-
} else {
|
|
53
|
-
const css = compileScript(blocks[i], filename, get);
|
|
54
|
-
if (css && typeof css === 'string') {
|
|
55
|
-
output += css;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
return output.trim();
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
const processJCSSFile = (filePath) => {
|
|
64
|
-
const abs = path.resolve(filePath);
|
|
65
|
-
|
|
66
|
-
if (fileCache.has(abs)) return fileCache.get(abs);
|
|
67
|
-
|
|
68
|
-
if (!fs.existsSync(abs)) {
|
|
69
|
-
throw new Error(`ChainCSS: File not found: ${abs}`);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
const content = fs.readFileSync(abs, 'utf8');
|
|
73
|
-
const dirname = path.dirname(abs);
|
|
74
|
-
|
|
75
|
-
const get = (relativePath) => {
|
|
76
|
-
const targetPath = path.resolve(dirname, relativePath);
|
|
77
|
-
return processJCSSFile(targetPath);
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
const result = processJavascriptBlocks(content, abs, get);
|
|
81
|
-
|
|
82
|
-
fileCache.set(abs, result);
|
|
83
|
-
return result;
|
|
84
|
-
};
|
|
85
|
-
|
|
86
|
-
const processCSS = async (css, filepath, options = {}) => {
|
|
87
|
-
const { minify = true, prefix = true } = options;
|
|
88
|
-
let processed = css;
|
|
89
|
-
|
|
90
|
-
if (prefix && prefixer) {
|
|
91
|
-
try {
|
|
92
|
-
const result = await prefixer.process(css, { from: filepath });
|
|
93
|
-
processed = result.css;
|
|
94
|
-
} catch (err) {
|
|
95
|
-
console.warn(`ChainCSS prefixer error in ${filepath}:`, err.message);
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
if (minify) {
|
|
100
|
-
const minified = new CleanCSS({ level: 2 }).minify(processed);
|
|
101
|
-
if (minified.errors.length) {
|
|
102
|
-
console.warn(`ChainCSS minification errors in ${filepath}:`, minified.errors);
|
|
103
|
-
}
|
|
104
|
-
return minified.styles;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
return processed;
|
|
108
|
-
};
|
|
109
|
-
|
|
110
|
-
// Helper to track used selectors for tree shaking
|
|
111
|
-
const trackUsedSelectors = (bundle) => {
|
|
112
|
-
const usedSelectors = new Set();
|
|
113
|
-
if (!bundle) return usedSelectors;
|
|
114
|
-
|
|
115
|
-
const classRegex = /class(?:Name)?=["']([^"']+)["']/g;
|
|
116
|
-
let match;
|
|
117
|
-
while ((match = classRegex.exec(bundle)) !== null) {
|
|
118
|
-
match[1].split(' ').forEach(cls => {
|
|
119
|
-
if (cls && cls !== '') {
|
|
120
|
-
usedSelectors.add(`.${cls}`);
|
|
121
|
-
}
|
|
122
|
-
});
|
|
123
|
-
}
|
|
124
|
-
return usedSelectors;
|
|
125
|
-
};
|
|
126
|
-
|
|
127
|
-
// Helper to filter unused CSS
|
|
128
|
-
function filterUsedCSS(css, usedSelectors) {
|
|
129
|
-
const lines = css.split('\n');
|
|
130
|
-
const filteredLines = [];
|
|
131
|
-
let inRule = false;
|
|
132
|
-
|
|
133
|
-
for (const line of lines) {
|
|
134
|
-
const selectorMatch = line.match(/^([^{]+){/);
|
|
135
|
-
if (selectorMatch) {
|
|
136
|
-
const selectors = selectorMatch[1].split(',').map(s => s.trim());
|
|
137
|
-
const isUsed = selectors.some(selector => {
|
|
138
|
-
const baseSelector = selector.split(':')[0];
|
|
139
|
-
return usedSelectors.has(baseSelector);
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
if (isUsed) {
|
|
143
|
-
filteredLines.push(line);
|
|
144
|
-
inRule = true;
|
|
145
|
-
} else {
|
|
146
|
-
inRule = false;
|
|
147
|
-
}
|
|
148
|
-
} else if (inRule) {
|
|
149
|
-
filteredLines.push(line);
|
|
150
|
-
if (line.includes('}')) {
|
|
151
|
-
inRule = false;
|
|
152
|
-
}
|
|
153
|
-
} else if (!line.includes('}')) {
|
|
154
|
-
filteredLines.push(line);
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
return filteredLines.join('\n');
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
export default function chaincssVite(opts = {}) {
|
|
162
|
-
const {
|
|
163
|
-
extension = '.jcss',
|
|
164
|
-
minify = process.env.NODE_ENV === 'production',
|
|
165
|
-
prefix = true,
|
|
166
|
-
hmr = true,
|
|
167
|
-
debug = process.env.NODE_ENV === 'development',
|
|
168
|
-
treeShake = process.env.NODE_ENV === 'production'
|
|
169
|
-
} = opts;
|
|
170
|
-
|
|
171
|
-
let generatedCSS = '';
|
|
172
|
-
let generatedClassMap = {};
|
|
173
|
-
|
|
174
|
-
return {
|
|
175
|
-
name: 'vite-plugin-chaincss',
|
|
176
|
-
enforce: 'pre',
|
|
177
|
-
|
|
178
|
-
async transform(code, id) {
|
|
179
|
-
if (!id.endsWith(extension)) return null;
|
|
180
|
-
|
|
181
|
-
try {
|
|
182
|
-
const dirname = path.dirname(id);
|
|
183
|
-
const get = (relativePath) => {
|
|
184
|
-
const targetPath = path.resolve(dirname, relativePath);
|
|
185
|
-
return processJCSSFile(targetPath);
|
|
186
|
-
};
|
|
187
|
-
|
|
188
|
-
let css = processJavascriptBlocks(code, id, get);
|
|
189
|
-
|
|
190
|
-
generatedCSS = css;
|
|
191
|
-
if (chain.classMap) {
|
|
192
|
-
generatedClassMap = chain.classMap;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
css = await processCSS(css, id, { minify, prefix });
|
|
196
|
-
|
|
197
|
-
// Development with Debug Mode
|
|
198
|
-
if (process.env.NODE_ENV !== 'production' && debug) {
|
|
199
|
-
const classMapStr = JSON.stringify(generatedClassMap);
|
|
200
|
-
return {
|
|
201
|
-
code: `
|
|
202
|
-
// ChainCSS with Debug Mode
|
|
203
|
-
const id = ${JSON.stringify(id)};
|
|
204
|
-
const css = ${JSON.stringify(css)};
|
|
205
|
-
const classMap = ${classMapStr};
|
|
206
|
-
|
|
207
|
-
let style = document.querySelector(\`style[data-chaincss="\${id}"]\`);
|
|
208
|
-
if (!style) {
|
|
209
|
-
style = document.createElement('style');
|
|
210
|
-
style.setAttribute('data-chaincss', id);
|
|
211
|
-
document.head.appendChild(style);
|
|
212
|
-
}
|
|
213
|
-
style.textContent = css;
|
|
214
|
-
|
|
215
|
-
// Debug Mode: Add inspector attributes
|
|
216
|
-
if (typeof window !== 'undefined' && window.__CHAINCSS_DEBUG__ !== false) {
|
|
217
|
-
// Mark elements with their chaincss classes
|
|
218
|
-
const observer = new MutationObserver(() => {
|
|
219
|
-
document.querySelectorAll('[class*="chain-"]').forEach(el => {
|
|
220
|
-
const classes = Array.from(el.classList).filter(c => c.includes('chain-')).join(' ');
|
|
221
|
-
if (classes && !el.hasAttribute('data-chaincss-class')) {
|
|
222
|
-
el.setAttribute('data-chaincss-class', classes);
|
|
223
|
-
}
|
|
224
|
-
});
|
|
225
|
-
});
|
|
226
|
-
observer.observe(document.body, { childList: true, subtree: true });
|
|
227
|
-
|
|
228
|
-
console.log('🔍 ChainCSS Debug Mode Active');
|
|
229
|
-
console.log('📊 Class Map:', classMap);
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
if (import.meta.hot) {
|
|
233
|
-
import.meta.hot.accept((newModule) => {
|
|
234
|
-
if (newModule?.default) {
|
|
235
|
-
style.textContent = newModule.default;
|
|
236
|
-
}
|
|
237
|
-
});
|
|
238
|
-
import.meta.hot.dispose(() => {
|
|
239
|
-
style.remove();
|
|
240
|
-
});
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
export default css;
|
|
244
|
-
`,
|
|
245
|
-
map: null
|
|
246
|
-
};
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
// Development without Debug
|
|
250
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
251
|
-
return {
|
|
252
|
-
code: `
|
|
253
|
-
const id = ${JSON.stringify(id)};
|
|
254
|
-
const css = ${JSON.stringify(css)};
|
|
255
|
-
|
|
256
|
-
let style = document.querySelector(\`style[data-chaincss="\${id}"]\`);
|
|
257
|
-
if (!style) {
|
|
258
|
-
style = document.createElement('style');
|
|
259
|
-
style.setAttribute('data-chaincss', id);
|
|
260
|
-
document.head.appendChild(style);
|
|
261
|
-
}
|
|
262
|
-
style.textContent = css;
|
|
263
|
-
|
|
264
|
-
if (import.meta.hot) {
|
|
265
|
-
import.meta.hot.accept((newModule) => {
|
|
266
|
-
if (newModule?.default) {
|
|
267
|
-
style.textContent = newModule.default;
|
|
268
|
-
}
|
|
269
|
-
});
|
|
270
|
-
import.meta.hot.dispose(() => {
|
|
271
|
-
style.remove();
|
|
272
|
-
});
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
export default css;
|
|
276
|
-
`,
|
|
277
|
-
map: null
|
|
278
|
-
};
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
// Production with Tree Shaking tracking
|
|
282
|
-
return {
|
|
283
|
-
code: `export default ${JSON.stringify(css)};`,
|
|
284
|
-
map: null
|
|
285
|
-
};
|
|
286
|
-
|
|
287
|
-
} catch (err) {
|
|
288
|
-
this.error(`ChainCSS error in ${id}: ${err.message}`);
|
|
289
|
-
return null;
|
|
290
|
-
}
|
|
291
|
-
},
|
|
292
|
-
|
|
293
|
-
// Add debug styles to HTML
|
|
294
|
-
transformIndexHtml(html) {
|
|
295
|
-
if (debug && process.env.NODE_ENV !== 'production') {
|
|
296
|
-
return {
|
|
297
|
-
html,
|
|
298
|
-
tags: [
|
|
299
|
-
{
|
|
300
|
-
tag: 'script',
|
|
301
|
-
injectTo: 'head',
|
|
302
|
-
children: `
|
|
303
|
-
window.__CHAINCSS_DEBUG__ = true;
|
|
304
|
-
console.log('🔍 ChainCSS Debug Mode: Hover over elements to see their atomic classes');
|
|
305
|
-
`
|
|
306
|
-
},
|
|
307
|
-
{
|
|
308
|
-
tag: 'style',
|
|
309
|
-
injectTo: 'head',
|
|
310
|
-
children: `
|
|
311
|
-
[data-chaincss-class]:hover::after {
|
|
312
|
-
content: attr(data-chaincss-class);
|
|
313
|
-
position: absolute;
|
|
314
|
-
background: #667eea;
|
|
315
|
-
color: white;
|
|
316
|
-
padding: 2px 8px;
|
|
317
|
-
font-size: 11px;
|
|
318
|
-
border-radius: 4px;
|
|
319
|
-
font-family: monospace;
|
|
320
|
-
z-index: 9999;
|
|
321
|
-
pointer-events: none;
|
|
322
|
-
white-space: nowrap;
|
|
323
|
-
box-shadow: 0 2px 4px rgba(0,0,0,0.2);
|
|
324
|
-
}
|
|
325
|
-
`
|
|
326
|
-
}
|
|
327
|
-
]
|
|
328
|
-
};
|
|
329
|
-
}
|
|
330
|
-
return html;
|
|
331
|
-
},
|
|
332
|
-
|
|
333
|
-
// Tree Shaking: Remove unused CSS
|
|
334
|
-
generateBundle(options, bundle) {
|
|
335
|
-
if (!treeShake) return;
|
|
336
|
-
|
|
337
|
-
const jsBundle = Object.values(bundle).find(
|
|
338
|
-
file => file.type === 'chunk' && file.isEntry
|
|
339
|
-
);
|
|
340
|
-
|
|
341
|
-
if (!jsBundle) return;
|
|
342
|
-
|
|
343
|
-
const usedSelectors = trackUsedSelectors(jsBundle.code);
|
|
344
|
-
|
|
345
|
-
const totalSelectors = Object.keys(generatedClassMap).length;
|
|
346
|
-
const usedCount = usedSelectors.size;
|
|
347
|
-
const deadCount = totalSelectors - usedCount;
|
|
348
|
-
const savings = totalSelectors > 0 ? (deadCount / totalSelectors * 100).toFixed(1) : 0;
|
|
349
|
-
|
|
350
|
-
if (deadCount > 0) {
|
|
351
|
-
console.log(`\n ChainCSS Tree Shaking Results:`);
|
|
352
|
-
console.log(`Total styles: ${totalSelectors}`);
|
|
353
|
-
console.log(`Used styles: ${usedCount}`);
|
|
354
|
-
console.log(`Dead code eliminated: ${deadCount} (${savings}% savings)`);
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
const cssFile = Object.values(bundle).find(
|
|
358
|
-
file => file.type === 'asset' && file.fileName.endsWith('.css')
|
|
359
|
-
);
|
|
360
|
-
|
|
361
|
-
if (cssFile && typeof cssFile.source === 'string') {
|
|
362
|
-
const originalCSS = cssFile.source;
|
|
363
|
-
const filteredCSS = filterUsedCSS(originalCSS, usedSelectors);
|
|
364
|
-
|
|
365
|
-
if (filteredCSS.length < originalCSS.length) {
|
|
366
|
-
cssFile.source = filteredCSS;
|
|
367
|
-
const cssSavings = ((originalCSS.length - filteredCSS.length) / originalCSS.length * 100).toFixed(1);
|
|
368
|
-
console.log(` 🎨 CSS size reduced by ${cssSavings}%`);
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
},
|
|
372
|
-
|
|
373
|
-
handleHotUpdate({ file, server }) {
|
|
374
|
-
if (file.endsWith(extension)) {
|
|
375
|
-
fileCache.delete(file);
|
|
376
|
-
server.ws.send({
|
|
377
|
-
type: 'full-reload',
|
|
378
|
-
path: '*'
|
|
379
|
-
});
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
|
-
};
|
|
383
|
-
}
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
// node/plugins/webpack-plugin.js
|
|
2
|
-
const path = require('path');
|
|
3
|
-
const { execSync } = require('child_process');
|
|
4
|
-
const fs = require('fs');
|
|
5
|
-
|
|
6
|
-
class ChainCSSWebpackPlugin {
|
|
7
|
-
constructor(options = {}) {
|
|
8
|
-
this.options = {
|
|
9
|
-
atomic: process.env.NODE_ENV === 'production',
|
|
10
|
-
input: './src/styles/main.jcss',
|
|
11
|
-
output: './dist',
|
|
12
|
-
...options
|
|
13
|
-
};
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
apply(compiler) {
|
|
17
|
-
compiler.hooks.beforeCompile.tapAsync('ChainCSSPlugin', async (params, callback) => {
|
|
18
|
-
try {
|
|
19
|
-
const inputPath = path.resolve(process.cwd(), this.options.input);
|
|
20
|
-
const outputPath = path.resolve(process.cwd(), this.options.output);
|
|
21
|
-
|
|
22
|
-
if (!fs.existsSync(inputPath)) {
|
|
23
|
-
console.warn('ChainCSS: No main.jcss file found, skipping...');
|
|
24
|
-
callback();
|
|
25
|
-
return;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const cmd = `node ${path.join(__dirname, '../chaincss.js')} ${inputPath} ${outputPath} ${this.options.atomic ? '--atomic' : ''}`;
|
|
29
|
-
execSync(cmd, { stdio: 'inherit' });
|
|
30
|
-
|
|
31
|
-
console.log('ChainCSS compiled successfully');
|
|
32
|
-
callback();
|
|
33
|
-
} catch (err) {
|
|
34
|
-
console.error('ChainCSS compilation failed:', err.message);
|
|
35
|
-
callback(err);
|
|
36
|
-
}
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
module.exports = ChainCSSWebpackPlugin;
|