@melcanz85/chaincss 1.11.5 → 1.12.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/LICENSE +22 -0
- package/node/atomic-optimizer.js +275 -88
- package/node/benchmarks/compare.js +17 -0
- package/node/benchmarks/run.js +299 -0
- package/node/btt.js +587 -150
- package/node/chaincss.js +189 -65
- package/node/loaders/chaincss-loader.js +62 -0
- package/node/plugins/next-plugin.js +29 -0
- package/node/plugins/vite-plugin.js +215 -0
- package/node/plugins/webpack-plugin.js +41 -0
- package/node/strVal.js +2 -2
- package/package.json +69 -35
- package/types.d.ts +175 -61
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
// node/plugins/vite-plugin.js
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import fs from 'node:fs';
|
|
4
|
+
import { createRequire } from 'node:module';
|
|
5
|
+
import CleanCSS from 'clean-css';
|
|
6
|
+
import { $, run, compile as originalCompile, chain } from '../btt.js';
|
|
7
|
+
|
|
8
|
+
const require = createRequire(import.meta.url);
|
|
9
|
+
|
|
10
|
+
// Optional: Try to load prefixer
|
|
11
|
+
let prefixer;
|
|
12
|
+
try {
|
|
13
|
+
const ChainCSSPrefixer = (await import('../prefixer.js')).default;
|
|
14
|
+
prefixer = new ChainCSSPrefixer({ enabled: true });
|
|
15
|
+
} catch (err) {
|
|
16
|
+
console.warn('ChainCSS: Prefixer not available, autoprefixing disabled');
|
|
17
|
+
prefixer = { process: async (css) => ({ css }) };
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Cache for processed files
|
|
21
|
+
const fileCache = new Map();
|
|
22
|
+
const compiledCache = new Map();
|
|
23
|
+
|
|
24
|
+
// Helper to compile script without temp files
|
|
25
|
+
const compileScript = (scriptBlock, filename, get) => {
|
|
26
|
+
const dirname = path.dirname(filename);
|
|
27
|
+
|
|
28
|
+
// Reset CSS output
|
|
29
|
+
chain.cssOutput = '';
|
|
30
|
+
|
|
31
|
+
// Create a function from the script - no temp files!
|
|
32
|
+
const fn = new Function(
|
|
33
|
+
'$',
|
|
34
|
+
'run',
|
|
35
|
+
'compile',
|
|
36
|
+
'chain',
|
|
37
|
+
'get',
|
|
38
|
+
'__filename',
|
|
39
|
+
'__dirname',
|
|
40
|
+
scriptBlock
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
// Execute with helpers
|
|
44
|
+
fn($, run, originalCompile, chain, get, filename, dirname);
|
|
45
|
+
|
|
46
|
+
return chain.cssOutput || '';
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const processJavascriptBlocks = (content, filename, get) => {
|
|
50
|
+
const blocks = content.split(/<@([\s\S]*?)@>/gm);
|
|
51
|
+
let output = '';
|
|
52
|
+
|
|
53
|
+
for (let i = 0; i < blocks.length; i++) {
|
|
54
|
+
if (i % 2 === 0) {
|
|
55
|
+
// Static content
|
|
56
|
+
output += blocks[i];
|
|
57
|
+
} else {
|
|
58
|
+
// JavaScript block
|
|
59
|
+
const css = compileScript(blocks[i], filename, get);
|
|
60
|
+
if (css && typeof css === 'string') {
|
|
61
|
+
output += css;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return output.trim();
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const processJCSSFile = (filePath) => {
|
|
70
|
+
const abs = path.resolve(filePath);
|
|
71
|
+
|
|
72
|
+
// Return cached result if available
|
|
73
|
+
if (fileCache.has(abs)) return fileCache.get(abs);
|
|
74
|
+
|
|
75
|
+
// Check if file exists
|
|
76
|
+
if (!fs.existsSync(abs)) {
|
|
77
|
+
throw new Error(`ChainCSS: File not found: ${abs}`);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const content = fs.readFileSync(abs, 'utf8');
|
|
81
|
+
const dirname = path.dirname(abs);
|
|
82
|
+
|
|
83
|
+
// Create get function for this file
|
|
84
|
+
const get = (relativePath) => {
|
|
85
|
+
const targetPath = path.resolve(dirname, relativePath);
|
|
86
|
+
return processJCSSFile(targetPath);
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
// Process the file
|
|
90
|
+
const result = processJavascriptBlocks(content, abs, get);
|
|
91
|
+
|
|
92
|
+
// Cache the result
|
|
93
|
+
fileCache.set(abs, result);
|
|
94
|
+
return result;
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
// Minify and prefix CSS
|
|
98
|
+
const processCSS = async (css, filepath, options = {}) => {
|
|
99
|
+
const { minify = true, prefix = true } = options;
|
|
100
|
+
let processed = css;
|
|
101
|
+
|
|
102
|
+
// Add prefixing
|
|
103
|
+
if (prefix && prefixer) {
|
|
104
|
+
try {
|
|
105
|
+
const result = await prefixer.process(css, { from: filepath });
|
|
106
|
+
processed = result.css;
|
|
107
|
+
} catch (err) {
|
|
108
|
+
console.warn(`ChainCSS prefixer error in ${filepath}:`, err.message);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Minify
|
|
113
|
+
if (minify) {
|
|
114
|
+
const minified = new CleanCSS({ level: 2 }).minify(processed);
|
|
115
|
+
if (minified.errors.length) {
|
|
116
|
+
console.warn(`ChainCSS minification errors in ${filepath}:`, minified.errors);
|
|
117
|
+
}
|
|
118
|
+
return minified.styles;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return processed;
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
export default function chaincssVite(opts = {}) {
|
|
125
|
+
const {
|
|
126
|
+
extension = '.jcss',
|
|
127
|
+
minify = process.env.NODE_ENV === 'production',
|
|
128
|
+
prefix = true,
|
|
129
|
+
hmr = true
|
|
130
|
+
} = opts;
|
|
131
|
+
|
|
132
|
+
return {
|
|
133
|
+
name: 'vite-plugin-chaincss',
|
|
134
|
+
enforce: 'pre',
|
|
135
|
+
|
|
136
|
+
// Transform .jcss files
|
|
137
|
+
async transform(code, id) {
|
|
138
|
+
if (!id.endsWith(extension)) return null;
|
|
139
|
+
|
|
140
|
+
try {
|
|
141
|
+
// Create get function for root file
|
|
142
|
+
const dirname = path.dirname(id);
|
|
143
|
+
const get = (relativePath) => {
|
|
144
|
+
const targetPath = path.resolve(dirname, relativePath);
|
|
145
|
+
return processJCSSFile(targetPath);
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
// Process the file
|
|
149
|
+
let css = processJavascriptBlocks(code, id, get);
|
|
150
|
+
|
|
151
|
+
// Process CSS (prefix + minify)
|
|
152
|
+
css = await processCSS(css, id, { minify, prefix });
|
|
153
|
+
|
|
154
|
+
// In development, inject CSS for HMR
|
|
155
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
156
|
+
return {
|
|
157
|
+
code: `
|
|
158
|
+
// ChainCSS HMR
|
|
159
|
+
const id = ${JSON.stringify(id)};
|
|
160
|
+
const css = ${JSON.stringify(css)};
|
|
161
|
+
|
|
162
|
+
// Add style to head
|
|
163
|
+
let style = document.querySelector(\`style[data-chaincss="\${id}"]\`);
|
|
164
|
+
if (!style) {
|
|
165
|
+
style = document.createElement('style');
|
|
166
|
+
style.setAttribute('data-chaincss', id);
|
|
167
|
+
document.head.appendChild(style);
|
|
168
|
+
}
|
|
169
|
+
style.textContent = css;
|
|
170
|
+
|
|
171
|
+
// HMR handling
|
|
172
|
+
if (import.meta.hot) {
|
|
173
|
+
import.meta.hot.accept((newModule) => {
|
|
174
|
+
if (newModule?.default) {
|
|
175
|
+
style.textContent = newModule.default;
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
import.meta.hot.dispose(() => {
|
|
180
|
+
style.remove();
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export default css;
|
|
185
|
+
`,
|
|
186
|
+
map: null
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Production: just export CSS
|
|
191
|
+
return {
|
|
192
|
+
code: `export default ${JSON.stringify(css)};`,
|
|
193
|
+
map: null
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
} catch (err) {
|
|
197
|
+
this.error(`ChainCSS error in ${id}: ${err.message}`);
|
|
198
|
+
return null;
|
|
199
|
+
}
|
|
200
|
+
},
|
|
201
|
+
|
|
202
|
+
// Handle HMR updates
|
|
203
|
+
handleHotUpdate({ file, server }) {
|
|
204
|
+
if (file.endsWith(extension)) {
|
|
205
|
+
// Invalidate cache for changed file
|
|
206
|
+
fileCache.delete(file);
|
|
207
|
+
// Trigger reload
|
|
208
|
+
server.ws.send({
|
|
209
|
+
type: 'full-reload',
|
|
210
|
+
path: '*'
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
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;
|
package/node/strVal.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const strVal = {
|
|
2
|
-
|
|
2
|
+
userConf: `// Project Configuration
|
|
3
3
|
module.exports = {
|
|
4
4
|
atomic: {
|
|
5
5
|
enabled: true,
|
|
@@ -18,7 +18,7 @@ module.exports = {
|
|
|
18
18
|
}
|
|
19
19
|
};
|
|
20
20
|
`,
|
|
21
|
-
|
|
21
|
+
cli_opt_guide: `
|
|
22
22
|
ChainCSS - JavaScript-powered CSS preprocessor
|
|
23
23
|
|
|
24
24
|
Usage:
|
package/package.json
CHANGED
|
@@ -1,38 +1,79 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@melcanz85/chaincss",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "1.12.1",
|
|
4
|
+
"description": "Chainable CSS-in-JS with build-time compilation, atomic CSS, and zero-runtime options",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"css",
|
|
7
|
+
"css-in-js",
|
|
8
|
+
"chaincss",
|
|
9
|
+
"atomic-css",
|
|
10
|
+
"zero-runtime",
|
|
11
|
+
"design-tokens",
|
|
12
|
+
"react",
|
|
13
|
+
"nextjs",
|
|
14
|
+
"vite",
|
|
15
|
+
"webpack"
|
|
16
|
+
],
|
|
17
|
+
"author": "Rommel Caneos",
|
|
18
|
+
"license": "MIT",
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "git+https://github.com/melcanz08/chaincss.git"
|
|
22
|
+
},
|
|
23
|
+
"homepage": "https://chaincss.dev",
|
|
24
|
+
"bugs": {
|
|
25
|
+
"url": "https://github.com/melcanz08/chaincss/issues"
|
|
26
|
+
},
|
|
5
27
|
"exports": {
|
|
6
28
|
".": {
|
|
7
29
|
"types": "./types.d.ts",
|
|
8
30
|
"node": {
|
|
9
|
-
"require": "./node/
|
|
31
|
+
"require": "./node/btt.js",
|
|
32
|
+
"import": "./node/btt.js"
|
|
10
33
|
},
|
|
11
34
|
"browser": {
|
|
12
|
-
"import": "./browser/
|
|
35
|
+
"import": "./browser/rtt.js",
|
|
36
|
+
"require": "./browser/rtt.js"
|
|
13
37
|
},
|
|
14
|
-
"default": "./browser/
|
|
38
|
+
"default": "./browser/rtt.js"
|
|
15
39
|
},
|
|
16
|
-
"./
|
|
40
|
+
"./react": {
|
|
17
41
|
"types": "./types.d.ts",
|
|
18
|
-
"
|
|
42
|
+
"browser": {
|
|
43
|
+
"import": "./browser/react-hooks.js",
|
|
44
|
+
"require": "./browser/react-hooks.js"
|
|
45
|
+
},
|
|
46
|
+
"default": "./browser/react-hooks.js"
|
|
19
47
|
},
|
|
20
|
-
"./
|
|
48
|
+
"./vite-plugin": {
|
|
21
49
|
"types": "./types.d.ts",
|
|
22
|
-
"import": "./
|
|
50
|
+
"import": "./node/plugins/vite-plugin.js",
|
|
51
|
+
"require": "./node/plugins/vite-plugin.js",
|
|
52
|
+
"default": "./node/plugins/vite-plugin.js"
|
|
23
53
|
},
|
|
24
|
-
"./
|
|
54
|
+
"./webpack-plugin": {
|
|
25
55
|
"types": "./types.d.ts",
|
|
26
|
-
"
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
56
|
+
"import": "./node/plugins/webpack-plugin.js",
|
|
57
|
+
"require": "./node/plugins/webpack-plugin.js",
|
|
58
|
+
"default": "./node/plugins/webpack-plugin.js"
|
|
59
|
+
},
|
|
60
|
+
"./next-plugin": {
|
|
61
|
+
"types": "./types.d.ts",
|
|
62
|
+
"import": "./node/plugins/next-plugin.js",
|
|
63
|
+
"require": "./node/plugins/next-plugin.js",
|
|
64
|
+
"default": "./node/plugins/next-plugin.js"
|
|
65
|
+
},
|
|
66
|
+
"./loader": {
|
|
67
|
+
"types": "./types.d.ts",
|
|
68
|
+
"import": "./node/loaders/chaincss-loader.js",
|
|
69
|
+
"require": "./node/loaders/chaincss-loader.js",
|
|
70
|
+
"default": "./node/loaders/chaincss-loader.js"
|
|
30
71
|
}
|
|
31
72
|
},
|
|
32
73
|
"types": "types.d.ts",
|
|
33
74
|
"files": [
|
|
34
|
-
"node/",
|
|
35
75
|
"browser/",
|
|
76
|
+
"node/",
|
|
36
77
|
"shared/",
|
|
37
78
|
"types.d.ts",
|
|
38
79
|
"README.md",
|
|
@@ -40,28 +81,27 @@
|
|
|
40
81
|
],
|
|
41
82
|
"publishConfig": {
|
|
42
83
|
"access": "public",
|
|
43
|
-
"registry": "https://registry.npmjs.org/"
|
|
44
|
-
|
|
45
|
-
"repository": {
|
|
46
|
-
"type": "git",
|
|
47
|
-
"url": "git+https://github.com/melcanz08/chaincss.git"
|
|
84
|
+
"registry": "https://registry.npmjs.org/",
|
|
85
|
+
"provenance": true
|
|
48
86
|
},
|
|
49
|
-
"homepage": "https://melcanz08.github.io/chaincss-website",
|
|
50
87
|
"bin": {
|
|
51
88
|
"chaincss": "./node/chaincss.js"
|
|
52
89
|
},
|
|
53
90
|
"dependencies": {
|
|
54
91
|
"chokidar": "^3.5.3",
|
|
55
|
-
"clean-css": "^5.3.3"
|
|
56
|
-
"vm2": "^3.9.19"
|
|
92
|
+
"clean-css": "^5.3.3"
|
|
57
93
|
},
|
|
58
94
|
"peerDependencies": {
|
|
95
|
+
"react": ">=16.8.0",
|
|
59
96
|
"autoprefixer": "^10.0.0",
|
|
97
|
+
"postcss": "^8.5.6",
|
|
60
98
|
"browserslist": "^4.28.1",
|
|
61
|
-
"caniuse-db": "^1.0.30001770"
|
|
62
|
-
"postcss": "^8.5.6"
|
|
99
|
+
"caniuse-db": "^1.0.30001770"
|
|
63
100
|
},
|
|
64
101
|
"peerDependenciesMeta": {
|
|
102
|
+
"react": {
|
|
103
|
+
"optional": true
|
|
104
|
+
},
|
|
65
105
|
"autoprefixer": {
|
|
66
106
|
"optional": true
|
|
67
107
|
},
|
|
@@ -75,14 +115,8 @@
|
|
|
75
115
|
"optional": true
|
|
76
116
|
}
|
|
77
117
|
},
|
|
78
|
-
"
|
|
79
|
-
"
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
"compiler",
|
|
83
|
-
"css-in-js",
|
|
84
|
-
"react"
|
|
85
|
-
],
|
|
86
|
-
"author": "Rommel Caneos",
|
|
87
|
-
"license": "MIT"
|
|
118
|
+
"engines": {
|
|
119
|
+
"node": ">=14.0.0"
|
|
120
|
+
},
|
|
121
|
+
"sideEffects": false
|
|
88
122
|
}
|