@plumeria/webpack-plugin 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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) zss-in-js contributer
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,73 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createTheme = exports.createVars = void 0;
4
+ exports.createCSS = createCSS;
5
+ const zss_engine_1 = require("zss-engine");
6
+ function compileToSingleCSS(object) {
7
+ const baseSheets = [];
8
+ const querySheets = [];
9
+ const atomicHashes = new Set();
10
+ Object.entries(object).forEach(([key, styleObj]) => {
11
+ const flat = {};
12
+ const nonFlat = {};
13
+ (0, zss_engine_1.splitAtomicAndNested)(styleObj, flat, nonFlat);
14
+ if (Object.keys(flat).length > 0) {
15
+ const sheets = new Set();
16
+ (0, zss_engine_1.processAtomicProps)(flat, atomicHashes, sheets);
17
+ for (const sheet of sheets) {
18
+ if (sheet.includes('@media') || sheet.includes('@container')) {
19
+ querySheets.push(sheet);
20
+ }
21
+ else {
22
+ baseSheets.push(sheet);
23
+ }
24
+ }
25
+ }
26
+ if (Object.keys(nonFlat).length > 0) {
27
+ const nonFlatHash = (0, zss_engine_1.genBase36Hash)({ [key]: nonFlat }, 1, 7);
28
+ const { styleSheet } = (0, zss_engine_1.transpile)({ [key]: nonFlat }, nonFlatHash);
29
+ baseSheets.push(styleSheet);
30
+ }
31
+ });
32
+ return [...baseSheets, ...querySheets].join('\n');
33
+ }
34
+ function createCSS(object) {
35
+ const result = {};
36
+ Object.entries(object).forEach(([key, styleObj]) => {
37
+ Object.defineProperty(result, key, {
38
+ get: () => Object.freeze(styleObj),
39
+ });
40
+ });
41
+ const compiledCSS = compileToSingleCSS(object);
42
+ return compiledCSS;
43
+ }
44
+ const createVars = (object) => {
45
+ const styles = {
46
+ ':root': {},
47
+ };
48
+ Object.entries(object).forEach(([key, value]) => {
49
+ styles[':root'][`--${key}`] = value;
50
+ });
51
+ styles;
52
+ return styles;
53
+ };
54
+ exports.createVars = createVars;
55
+ const createTheme = (object) => {
56
+ const styles = {};
57
+ Object.entries(object).forEach(([key, value]) => {
58
+ Object.entries(value).forEach(([subKey, subValue]) => {
59
+ if (subKey.startsWith('@media')) {
60
+ styles[':root'] ||= {};
61
+ styles[':root'][subKey] ||= {};
62
+ styles[':root'][subKey][`--${key}`] = subValue;
63
+ }
64
+ else {
65
+ const themeSelector = subKey === 'default' ? ':root' : `:root[data-theme="${subKey}"]`;
66
+ styles[themeSelector] ||= {};
67
+ styles[themeSelector][`--${key}`] = subValue;
68
+ }
69
+ });
70
+ });
71
+ return styles;
72
+ };
73
+ exports.createTheme = createTheme;
package/dist/index.js ADDED
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const webpack_1 = require("webpack");
7
+ const webpack_virtual_modules_1 = __importDefault(require("webpack-virtual-modules"));
8
+ const PLUGIN_NAME = 'PlumeriaPlugin';
9
+ class PlumeriaPlugin {
10
+ styles = new Map();
11
+ virtualModules;
12
+ apply(compiler) {
13
+ this.virtualModules = new webpack_virtual_modules_1.default();
14
+ this.virtualModules.apply(compiler);
15
+ compiler.hooks.compile.tap(PLUGIN_NAME, () => {
16
+ this.styles.clear();
17
+ });
18
+ compiler.hooks.thisCompilation.tap(PLUGIN_NAME, (compilation) => {
19
+ compilation.hooks.processAssets.tapPromise({
20
+ name: PLUGIN_NAME,
21
+ stage: webpack_1.Compilation.PROCESS_ASSETS_STAGE_ADDITIONS,
22
+ }, async () => {
23
+ const fullCss = Array.from(this.styles.values()).join('\n');
24
+ compilation.emitAsset('plumeria.css', new webpack_1.sources.RawSource(fullCss));
25
+ });
26
+ });
27
+ }
28
+ registerStyle(virtualFileName, css) {
29
+ this.styles.set(virtualFileName, css);
30
+ this.virtualModules?.writeModule(virtualFileName, css);
31
+ }
32
+ }
33
+ exports.default = PlumeriaPlugin;
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,637 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.default = loader;
40
+ const core_1 = require("@babel/core");
41
+ const t = __importStar(require("@babel/types"));
42
+ const loader_utils_1 = __importDefault(require("loader-utils"));
43
+ const path_1 = __importDefault(require("path"));
44
+ const fs_1 = __importDefault(require("fs"));
45
+ const create_css_1 = require("./create-css");
46
+ const glob_1 = require("@rust-gear/glob");
47
+ const zss_engine_1 = require("zss-engine");
48
+ const PROJECT_ROOT = process.cwd().split('node_modules')[0];
49
+ const PATTERN_PATH = path_1.default.join(PROJECT_ROOT, '**/*.{js,jsx,ts,tsx}');
50
+ const GLOB_OPTIONS = {
51
+ exclude: ['**/node_modules/**', '**/dist/**', '**/build/**', '**/.next/**'],
52
+ cwd: PROJECT_ROOT,
53
+ };
54
+ let constTable = {};
55
+ let variableTable = {};
56
+ let keyframesHashTable = {};
57
+ let keyframesObjectTable = {};
58
+ let defineVarsObjectTable = {};
59
+ let defineThemeObjectTable = {};
60
+ function objectExpressionToObject(node, constTable, keyframesHashTable, variableTable) {
61
+ const obj = {};
62
+ node.properties.forEach((prop) => {
63
+ if (!t.isObjectProperty(prop))
64
+ return;
65
+ const key = getPropertyKey(prop.key, constTable, variableTable);
66
+ if (!key)
67
+ return;
68
+ const val = prop.value;
69
+ if (t.isIdentifier(val) || t.isMemberExpression(val)) {
70
+ const resolvedKeyframe = resolveKeyframesTableMemberExpression(val, keyframesHashTable);
71
+ if (resolvedKeyframe !== undefined) {
72
+ obj[key] = resolvedKeyframe;
73
+ return;
74
+ }
75
+ const resolvedVariable = resolveVariableTableMemberExpressionByNode(val, variableTable);
76
+ if (resolvedVariable !== undefined) {
77
+ obj[key] = resolvedVariable;
78
+ return;
79
+ }
80
+ }
81
+ if (t.isStringLiteral(val) ||
82
+ t.isNumericLiteral(val) ||
83
+ t.isBooleanLiteral(val)) {
84
+ obj[key] = val.value;
85
+ }
86
+ else if (t.isUnaryExpression(val)) {
87
+ obj[key] = evaluateUnaryExpression(val);
88
+ }
89
+ else if (t.isObjectExpression(val)) {
90
+ obj[key] = objectExpressionToObject(val, constTable, keyframesHashTable, variableTable);
91
+ }
92
+ else if (t.isMemberExpression(val)) {
93
+ const resolved = resolveConstTableMemberExpression(val, constTable);
94
+ obj[key] = resolved !== undefined ? resolved : '[unresolved]';
95
+ }
96
+ else if (t.isIdentifier(val)) {
97
+ if (constTable[val.name] !== undefined) {
98
+ obj[key] = constTable[val.name];
99
+ }
100
+ else {
101
+ obj[key] = '[unresolved identifier]';
102
+ }
103
+ }
104
+ else {
105
+ obj[key] = '[unsupported value type]';
106
+ }
107
+ });
108
+ return obj;
109
+ }
110
+ function collectLocalConsts(ast) {
111
+ const localConsts = {};
112
+ (0, core_1.traverse)(ast, {
113
+ VariableDeclarator(path) {
114
+ const { node } = path;
115
+ if (t.isIdentifier(node.id) &&
116
+ node.init &&
117
+ t.isStringLiteral(node.init)) {
118
+ localConsts[node.id.name] = node.init.value;
119
+ }
120
+ },
121
+ });
122
+ return localConsts;
123
+ }
124
+ function getPropertyKey(node, constTable, variableTable) {
125
+ if (t.isIdentifier(node)) {
126
+ if (constTable[node.name] && typeof constTable[node.name] === 'string') {
127
+ return constTable[node.name];
128
+ }
129
+ return node.name;
130
+ }
131
+ if (t.isStringLiteral(node))
132
+ return node.value;
133
+ if (t.isMemberExpression(node)) {
134
+ const result = resolveConstTableMemberExpression(node, constTable);
135
+ if (typeof result === 'string')
136
+ return result;
137
+ throw new Error(`Resolved key is not a string: ${JSON.stringify(result)}`);
138
+ }
139
+ if (t.isTemplateLiteral(node)) {
140
+ return evaluateTemplateLiteral(node, constTable, variableTable);
141
+ }
142
+ if (t.isBinaryExpression(node)) {
143
+ return evaluateBinaryExpression(node, constTable, variableTable);
144
+ }
145
+ throw new Error(`Unsupported property key type: ${node.type}`);
146
+ }
147
+ function evaluateTemplateLiteral(node, constTable, variableTable) {
148
+ let result = '';
149
+ for (let i = 0; i < node.quasis.length; i++) {
150
+ result += node.quasis[i].value.cooked || node.quasis[i].value.raw;
151
+ if (i < node.expressions.length) {
152
+ const expr = node.expressions[i];
153
+ const evaluatedExpr = evaluateExpression(expr, constTable, variableTable);
154
+ result += String(evaluatedExpr);
155
+ }
156
+ }
157
+ return result;
158
+ }
159
+ function evaluateBinaryExpression(node, constTable, variableTable) {
160
+ const left = evaluateExpression(node.left, constTable, variableTable);
161
+ const right = evaluateExpression(node.right, constTable, variableTable);
162
+ if (node.operator === '+') {
163
+ return String(left) + String(right);
164
+ }
165
+ throw new Error(`Unsupported binary operator: ${node.operator}`);
166
+ }
167
+ function evaluateExpression(node, constTable, variableTable) {
168
+ if (t.isStringLiteral(node)) {
169
+ return node.value;
170
+ }
171
+ if (t.isNumericLiteral(node)) {
172
+ return node.value;
173
+ }
174
+ if (t.isBooleanLiteral(node)) {
175
+ return node.value;
176
+ }
177
+ if (t.isNullLiteral(node)) {
178
+ return null;
179
+ }
180
+ if (t.isIdentifier(node)) {
181
+ if (constTable[node.name] !== undefined) {
182
+ return constTable[node.name];
183
+ }
184
+ if (keyframesHashTable[node.name] !== undefined) {
185
+ return keyframesHashTable[node.name];
186
+ }
187
+ return `[unresolved: ${node.name}]`;
188
+ }
189
+ if (t.isMemberExpression(node)) {
190
+ const resolved = resolveConstTableMemberExpression(node, constTable);
191
+ if (resolved !== undefined) {
192
+ return resolved;
193
+ }
194
+ const resolvedVar = resolveVariableTableMemberExpressionByNode(node, variableTable);
195
+ if (resolvedVar !== undefined) {
196
+ return resolvedVar;
197
+ }
198
+ return `[unresolved member expression]`;
199
+ }
200
+ if (t.isBinaryExpression(node)) {
201
+ return evaluateBinaryExpression(node, constTable, variableTable);
202
+ }
203
+ if (t.isTemplateLiteral(node)) {
204
+ return evaluateTemplateLiteral(node, constTable, variableTable);
205
+ }
206
+ if (t.isUnaryExpression(node)) {
207
+ return evaluateUnaryExpression(node);
208
+ }
209
+ throw new Error(`Unsupported expression type: ${node.type}`);
210
+ }
211
+ function evaluateUnaryExpression(node) {
212
+ const arg = node.argument;
213
+ switch (node.operator) {
214
+ case '-':
215
+ if (t.isNumericLiteral(arg))
216
+ return -arg.value;
217
+ break;
218
+ case '+':
219
+ if (t.isNumericLiteral(arg))
220
+ return +arg.value;
221
+ break;
222
+ default:
223
+ throw new Error(`Unsupported unary operator: ${node.operator}`);
224
+ }
225
+ throw new Error(`Unsupported UnaryExpression argument type: ${arg.type}`);
226
+ }
227
+ function resolveKeyframesTableMemberExpression(node, keyframesHashTable) {
228
+ if (t.isIdentifier(node)) {
229
+ return keyframesHashTable[node.name];
230
+ }
231
+ if (t.isMemberExpression(node)) {
232
+ if (t.isIdentifier(node.object)) {
233
+ return keyframesHashTable[node.object.name];
234
+ }
235
+ }
236
+ return undefined;
237
+ }
238
+ function resolveConstTableMemberExpression(node, constTable) {
239
+ if (t.isIdentifier(node.object) && t.isIdentifier(node.property)) {
240
+ const varName = node.object.name;
241
+ const key = node.property.name;
242
+ const tableValue = constTable[varName];
243
+ if (typeof tableValue === 'string') {
244
+ return tableValue;
245
+ }
246
+ if (tableValue && typeof tableValue === 'object' && key in tableValue) {
247
+ return tableValue[key];
248
+ }
249
+ }
250
+ return undefined;
251
+ }
252
+ function resolveVariableTableMemberExpressionByNode(node, variableTable) {
253
+ if (t.isIdentifier(node)) {
254
+ return variableTable[node.name];
255
+ }
256
+ if (t.isMemberExpression(node)) {
257
+ if (t.isIdentifier(node.object)) {
258
+ const varName = node.object.name;
259
+ let key;
260
+ if (t.isIdentifier(node.property)) {
261
+ key = node.property.name;
262
+ }
263
+ else if (t.isStringLiteral(node.property)) {
264
+ key = node.property.value;
265
+ }
266
+ if (key &&
267
+ variableTable[varName] &&
268
+ variableTable[varName][key] !== undefined) {
269
+ return variableTable[varName][key];
270
+ }
271
+ }
272
+ }
273
+ return undefined;
274
+ }
275
+ function scanForDefineConsts() {
276
+ const files = (0, glob_1.globSync)(PATTERN_PATH, GLOB_OPTIONS);
277
+ const constTableLocal = {};
278
+ for (const filePath of files) {
279
+ if (!isCSSDefineFile(filePath, 'defineConsts'))
280
+ continue;
281
+ this.addDependency(filePath);
282
+ const source = fs_1.default.readFileSync(filePath, 'utf8');
283
+ const ast = (0, core_1.parseSync)(source, {
284
+ sourceType: 'module',
285
+ presets: [
286
+ ['@babel/preset-typescript', { isTSX: true, allExtensions: true }],
287
+ ],
288
+ });
289
+ if (!ast)
290
+ continue;
291
+ for (const node of ast.program.body) {
292
+ let declarations = [];
293
+ if (t.isVariableDeclaration(node)) {
294
+ declarations = node.declarations;
295
+ }
296
+ else if (t.isExportNamedDeclaration(node) &&
297
+ node.declaration &&
298
+ t.isVariableDeclaration(node.declaration)) {
299
+ declarations = node.declaration.declarations;
300
+ }
301
+ for (const decl of declarations) {
302
+ if (t.isVariableDeclarator(decl) &&
303
+ t.isIdentifier(decl.id) &&
304
+ decl.init &&
305
+ t.isCallExpression(decl.init) &&
306
+ t.isMemberExpression(decl.init.callee) &&
307
+ t.isIdentifier(decl.init.callee.object, { name: 'css' }) &&
308
+ t.isIdentifier(decl.init.callee.property, { name: 'defineConsts' }) &&
309
+ decl.init.arguments.length === 1 &&
310
+ t.isObjectExpression(decl.init.arguments[0])) {
311
+ const varName = decl.id.name;
312
+ const obj = objectExpressionToObject(decl.init.arguments[0], constTableLocal, keyframesHashTable, variableTable);
313
+ constTableLocal[varName] = obj;
314
+ }
315
+ }
316
+ }
317
+ }
318
+ return constTableLocal;
319
+ }
320
+ function scanForKeyframes() {
321
+ const files = (0, glob_1.globSync)(PATTERN_PATH, GLOB_OPTIONS);
322
+ const keyframesHashTableLocal = {};
323
+ const keyframesObjectTableLocal = {};
324
+ for (const filePath of files) {
325
+ if (!isCSSDefineFile(filePath, 'keyframes'))
326
+ continue;
327
+ this.addDependency(filePath);
328
+ const source = fs_1.default.readFileSync(filePath, 'utf8');
329
+ const ast = (0, core_1.parseSync)(source, {
330
+ sourceType: 'module',
331
+ presets: [
332
+ ['@babel/preset-typescript', { isTSX: true, allExtensions: true }],
333
+ ],
334
+ });
335
+ if (!ast)
336
+ continue;
337
+ for (const node of ast.program.body) {
338
+ let declarations = [];
339
+ if (t.isVariableDeclaration(node)) {
340
+ declarations = node.declarations;
341
+ }
342
+ else if (t.isExportNamedDeclaration(node) &&
343
+ node.declaration &&
344
+ t.isVariableDeclaration(node.declaration)) {
345
+ declarations = node.declaration.declarations;
346
+ }
347
+ for (const decl of declarations) {
348
+ if (t.isVariableDeclarator(decl) &&
349
+ t.isIdentifier(decl.id) &&
350
+ decl.init &&
351
+ t.isCallExpression(decl.init) &&
352
+ t.isMemberExpression(decl.init.callee) &&
353
+ t.isIdentifier(decl.init.callee.object, { name: 'css' }) &&
354
+ t.isIdentifier(decl.init.callee.property, { name: 'keyframes' }) &&
355
+ decl.init.arguments.length === 1 &&
356
+ t.isObjectExpression(decl.init.arguments[0])) {
357
+ const varName = decl.id.name;
358
+ const obj = objectExpressionToObject(decl.init.arguments[0], constTable, keyframesHashTableLocal, variableTable);
359
+ const hash = (0, zss_engine_1.genBase36Hash)(obj, 1, 8);
360
+ keyframesHashTableLocal[varName] = hash;
361
+ keyframesObjectTableLocal[hash] = obj;
362
+ }
363
+ }
364
+ }
365
+ }
366
+ return {
367
+ keyframesHashTableLocal,
368
+ keyframesObjectTableLocal,
369
+ };
370
+ }
371
+ function scanForDefineVars() {
372
+ const files = (0, glob_1.globSync)(PATTERN_PATH, GLOB_OPTIONS);
373
+ const variableTableLocal = {};
374
+ const defineVarsObjectTableLocal = {};
375
+ for (const filePath of files) {
376
+ if (!isCSSDefineFile(filePath, 'defineVars'))
377
+ continue;
378
+ this.addDependency(filePath);
379
+ const source = fs_1.default.readFileSync(filePath, 'utf8');
380
+ const ast = (0, core_1.parseSync)(source, {
381
+ sourceType: 'module',
382
+ presets: [
383
+ ['@babel/preset-typescript', { isTSX: true, allExtensions: true }],
384
+ ],
385
+ });
386
+ if (!ast)
387
+ continue;
388
+ for (const node of ast.program.body) {
389
+ let declarations = [];
390
+ if (t.isVariableDeclaration(node)) {
391
+ declarations = node.declarations;
392
+ }
393
+ else if (t.isExportNamedDeclaration(node) &&
394
+ node.declaration &&
395
+ t.isVariableDeclaration(node.declaration)) {
396
+ declarations = node.declaration.declarations;
397
+ }
398
+ for (const decl of declarations) {
399
+ if (t.isVariableDeclarator(decl) &&
400
+ t.isIdentifier(decl.id) &&
401
+ decl.init &&
402
+ t.isCallExpression(decl.init) &&
403
+ t.isMemberExpression(decl.init.callee) &&
404
+ t.isIdentifier(decl.init.callee.object, { name: 'css' }) &&
405
+ t.isIdentifier(decl.init.callee.property, { name: 'defineVars' }) &&
406
+ decl.init.arguments.length === 1 &&
407
+ t.isObjectExpression(decl.init.arguments[0])) {
408
+ const varName = decl.id.name;
409
+ const obj = objectExpressionToObject(decl.init.arguments[0], constTable, keyframesHashTable, variableTableLocal);
410
+ variableTableLocal[varName] = obj;
411
+ defineVarsObjectTableLocal[varName] = obj;
412
+ }
413
+ }
414
+ }
415
+ }
416
+ return { variableTableLocal, defineVarsObjectTableLocal };
417
+ }
418
+ function scanForDefineTheme() {
419
+ const files = (0, glob_1.globSync)(PATTERN_PATH, GLOB_OPTIONS);
420
+ const variableTableLocal = {};
421
+ const defineThemeObjectTableLocal = {};
422
+ for (const filePath of files) {
423
+ if (!isCSSDefineFile(filePath, 'defineTheme'))
424
+ continue;
425
+ this.addDependency(filePath);
426
+ const source = fs_1.default.readFileSync(filePath, 'utf8');
427
+ const ast = (0, core_1.parseSync)(source, {
428
+ sourceType: 'module',
429
+ presets: [
430
+ ['@babel/preset-typescript', { isTSX: true, allExtensions: true }],
431
+ ],
432
+ });
433
+ if (!ast)
434
+ continue;
435
+ for (const node of ast.program.body) {
436
+ let declarations = [];
437
+ if (t.isVariableDeclaration(node)) {
438
+ declarations = node.declarations;
439
+ }
440
+ else if (t.isExportNamedDeclaration(node) &&
441
+ node.declaration &&
442
+ t.isVariableDeclaration(node.declaration)) {
443
+ declarations = node.declaration.declarations;
444
+ }
445
+ for (const decl of declarations) {
446
+ if (t.isVariableDeclarator(decl) &&
447
+ t.isIdentifier(decl.id) &&
448
+ decl.init &&
449
+ t.isCallExpression(decl.init) &&
450
+ t.isMemberExpression(decl.init.callee) &&
451
+ t.isIdentifier(decl.init.callee.object, { name: 'css' }) &&
452
+ t.isIdentifier(decl.init.callee.property, { name: 'defineTheme' }) &&
453
+ decl.init.arguments.length === 1 &&
454
+ t.isObjectExpression(decl.init.arguments[0])) {
455
+ const varName = decl.id.name;
456
+ const obj = objectExpressionToObject(decl.init.arguments[0], constTable, keyframesHashTable, variableTableLocal);
457
+ variableTableLocal[varName] = obj;
458
+ defineThemeObjectTableLocal[varName] = obj;
459
+ }
460
+ }
461
+ }
462
+ }
463
+ return { variableTableLocal, defineThemeObjectTableLocal };
464
+ }
465
+ function isCSSDefineFile(filePath, target) {
466
+ if (fs_1.default.statSync(filePath).isDirectory())
467
+ return false;
468
+ const code = fs_1.default.readFileSync(filePath, 'utf8');
469
+ let ast;
470
+ try {
471
+ ast = (0, core_1.parseSync)(code, {
472
+ sourceType: 'module',
473
+ presets: [
474
+ ['@babel/preset-typescript', { isTSX: true, allExtensions: true }],
475
+ '@babel/preset-react',
476
+ ],
477
+ });
478
+ }
479
+ catch (err) {
480
+ console.log(err);
481
+ return false;
482
+ }
483
+ if (!ast)
484
+ return false;
485
+ let found = false;
486
+ (0, core_1.traverse)(ast, {
487
+ CallExpression(path) {
488
+ const callee = path.node.callee;
489
+ if (callee.type === 'MemberExpression' &&
490
+ callee.object.type === 'Identifier' &&
491
+ callee.object.name === 'css' &&
492
+ callee.property.type === 'Identifier' &&
493
+ callee.property.name === target) {
494
+ found = true;
495
+ path.stop();
496
+ }
497
+ },
498
+ });
499
+ return found;
500
+ }
501
+ function loader(source) {
502
+ const callback = this.async();
503
+ this.addDependency(this.resourcePath);
504
+ constTable = scanForDefineConsts.call(this);
505
+ const { keyframesHashTableLocal, keyframesObjectTableLocal } = scanForKeyframes.call(this);
506
+ keyframesHashTable = keyframesHashTableLocal;
507
+ keyframesObjectTable = keyframesObjectTableLocal;
508
+ const { variableTableLocal: varsTable, defineVarsObjectTableLocal } = scanForDefineVars.call(this);
509
+ const { variableTableLocal: themeTable, defineThemeObjectTableLocal } = scanForDefineTheme.call(this);
510
+ variableTable = varsTable;
511
+ for (const k in themeTable) {
512
+ variableTable[k] = themeTable[k];
513
+ }
514
+ defineVarsObjectTable = defineVarsObjectTableLocal;
515
+ defineThemeObjectTable = defineThemeObjectTableLocal;
516
+ let extractedObject = null;
517
+ const extractedGlobalObjects = [];
518
+ let ast;
519
+ try {
520
+ ast = (0, core_1.parseSync)(source, {
521
+ sourceType: 'module',
522
+ presets: [
523
+ ['@babel/preset-typescript', { isTSX: true, allExtensions: true }],
524
+ '@babel/preset-react',
525
+ ],
526
+ });
527
+ }
528
+ catch (e) {
529
+ console.warn('[virtual-css-loader] parseSync error:', e);
530
+ if (callback)
531
+ return callback(null, source);
532
+ return source;
533
+ }
534
+ if (!ast) {
535
+ console.warn('[virtual-css-loader] parseSync returned null');
536
+ if (callback)
537
+ return callback(null, source);
538
+ return source;
539
+ }
540
+ const localConsts = collectLocalConsts(ast);
541
+ if (Object.keys(localConsts).length !== 0) {
542
+ for (const k in localConsts) {
543
+ constTable[k] = localConsts[k];
544
+ }
545
+ }
546
+ const plugin = {
547
+ visitor: {
548
+ CallExpression(path) {
549
+ const callee = path.node.callee;
550
+ if (t.isMemberExpression(callee) &&
551
+ t.isIdentifier(callee.object) &&
552
+ callee.object.name === 'css' &&
553
+ t.isIdentifier(callee.property)) {
554
+ const args = path.node.arguments;
555
+ if (callee.property.name === 'create' &&
556
+ args.length === 1 &&
557
+ t.isObjectExpression(args[0])) {
558
+ try {
559
+ extractedObject = objectExpressionToObject(args[0], constTable, keyframesHashTable, variableTable);
560
+ }
561
+ catch (e) {
562
+ console.warn('[virtual-css-loader] Failed to build object from AST:', e);
563
+ }
564
+ }
565
+ if (callee.property.name === 'global' &&
566
+ args.length === 1 &&
567
+ t.isObjectExpression(args[0])) {
568
+ try {
569
+ const globalObj = objectExpressionToObject(args[0], constTable, keyframesHashTable, variableTable);
570
+ extractedGlobalObjects.push(globalObj);
571
+ }
572
+ catch (e) {
573
+ console.warn('[virtual-css-loader] Failed to build global object from AST:', e);
574
+ }
575
+ }
576
+ }
577
+ },
578
+ },
579
+ };
580
+ (0, core_1.transformFromAstSync)(ast, source, {
581
+ code: false,
582
+ plugins: [plugin],
583
+ configFile: false,
584
+ });
585
+ if (!extractedObject && extractedGlobalObjects.length === 0) {
586
+ if (callback)
587
+ return callback(null, source);
588
+ return source;
589
+ }
590
+ const css = extractedObject ? (0, create_css_1.createCSS)(extractedObject) : '';
591
+ let globalCss = '';
592
+ for (const obj of extractedGlobalObjects) {
593
+ globalCss +=
594
+ (0, zss_engine_1.transpile)(obj, undefined, '--global').styleSheet + '\n';
595
+ }
596
+ let keyframeCss = '';
597
+ for (const [hash, obj] of Object.entries(keyframesObjectTable)) {
598
+ const keyframeWrapped = { [`@keyframes ${hash}`]: obj };
599
+ const { styleSheet } = (0, zss_engine_1.transpile)(keyframeWrapped, undefined, '--global');
600
+ keyframeCss += styleSheet + '\n';
601
+ }
602
+ let varCss = '';
603
+ for (const [, obj] of Object.entries(defineVarsObjectTable)) {
604
+ const { styleSheet } = (0, zss_engine_1.transpile)((0, create_css_1.createVars)(obj), undefined, '--global');
605
+ varCss += styleSheet + '\n';
606
+ }
607
+ let themeCss = '';
608
+ for (const [, obj] of Object.entries(defineThemeObjectTable)) {
609
+ const { styleSheet } = (0, zss_engine_1.transpile)((0, create_css_1.createTheme)(obj), undefined, '--global');
610
+ themeCss += styleSheet + '\n';
611
+ }
612
+ const finalCss = globalCss +
613
+ '\n' +
614
+ keyframeCss +
615
+ '\n' +
616
+ varCss +
617
+ '\n' +
618
+ themeCss +
619
+ '\n' +
620
+ css;
621
+ const virtualCssFileName = loader_utils_1.default.interpolateName(this, '[path][name].[hash:base64:8].virtual.css', {
622
+ content: finalCss,
623
+ context: this.rootContext,
624
+ });
625
+ const absVirtualCssFileName = path_1.default.resolve(this.rootContext, virtualCssFileName);
626
+ const pluginInstance = this._compiler?.options?.plugins.find((p) => p?.constructor?.name === 'PlumeriaPlugin');
627
+ pluginInstance?.registerStyle?.(absVirtualCssFileName, finalCss);
628
+ let importPath = path_1.default.posix.relative(path_1.default.dirname(this.resourcePath), absVirtualCssFileName);
629
+ if (!importPath.startsWith('.')) {
630
+ importPath = './' + importPath;
631
+ }
632
+ importPath = importPath.replace(/\\/g, '/');
633
+ const resultSource = source + `\nimport ${JSON.stringify(importPath)};`;
634
+ if (callback)
635
+ return callback(null, resultSource);
636
+ return resultSource;
637
+ }
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "@plumeria/webpack-plugin",
3
+ "version": "0.1.0",
4
+ "description": "Plumeria Webpack plugin",
5
+ "keywords": [
6
+ "react",
7
+ "css",
8
+ "css-in-js",
9
+ "plumeria",
10
+ "styling"
11
+ ],
12
+ "repository": "github:zss-in-js/plumeria",
13
+ "license": "MIT",
14
+ "sideEffects": false,
15
+ "main": "dist/index.js",
16
+ "types": "types/index.d.ts",
17
+ "files": [
18
+ "dist/",
19
+ "types/"
20
+ ],
21
+ "scripts": {
22
+ "build": "rimraf dist types && pnpm cjs",
23
+ "cjs": "tsc --project tsconfig.cjs.json"
24
+ },
25
+ "dependencies": {
26
+ "@babel/core": "^7.28.0",
27
+ "@babel/preset-react": "^7.27.1",
28
+ "@babel/preset-typescript": "^7.27.1",
29
+ "@babel/types": "^7.28.2",
30
+ "loader-utils": "^3.3.1",
31
+ "webpack-virtual-modules": "^0.6.2"
32
+ },
33
+ "devDependencies": {
34
+ "@rust-gear/glob": "^0.2.2",
35
+ "@types/babel__core": "^7.20.5",
36
+ "@types/loader-utils": "^2.0.6",
37
+ "@types/webpack": "^5.28.5",
38
+ "zss-engine": "^0.2.73"
39
+ },
40
+ "publishConfig": {
41
+ "access": "public"
42
+ }
43
+ }
@@ -0,0 +1,5 @@
1
+ import type { CSSProperties, CreateStyleType, CreateTheme, CreateValues } from 'zss-engine';
2
+ declare function createCSS<T extends Record<string, CSSProperties>>(object: CreateStyleType<T>): string;
3
+ declare const createVars: <const T extends CreateValues>(object: T) => Record<string, CreateValues>;
4
+ declare const createTheme: <const T extends CreateTheme>(object: T) => Record<string, Record<string, string | number | object>>;
5
+ export { createCSS, createVars, createTheme };
@@ -0,0 +1,7 @@
1
+ import type { Compiler } from 'webpack';
2
+ export default class PlumeriaPlugin {
3
+ private styles;
4
+ private virtualModules?;
5
+ apply(compiler: Compiler): void;
6
+ registerStyle(virtualFileName: string, css: string): void;
7
+ }
@@ -0,0 +1,13 @@
1
+ type CSSPrimitive = string | number | boolean | null;
2
+ type ParseErrorString = `[unresolved]` | `[unresolved identifier]` | `[unsupported value type]` | `[unresolved: ${string}]` | `[unresolved member expression]`;
3
+ type CSSValue = CSSPrimitive | CSSObject | ParseErrorString;
4
+ export type CSSObject = {
5
+ [key: string]: CSSValue;
6
+ };
7
+ export type ConstTable = Record<string, CSSObject | string>;
8
+ export type VariableTable = Record<string, CSSObject>;
9
+ export type KeyframesHashTable = Record<string, string>;
10
+ export type KeyframesObjectTable = Record<string, CSSObject>;
11
+ export type DefineVarsObjectTable = Record<string, CSSObject>;
12
+ export type DefineThemeObjectTable = Record<string, CSSObject>;
13
+ export {};
@@ -0,0 +1,2 @@
1
+ import type { LoaderContext } from 'webpack';
2
+ export default function loader(this: LoaderContext<unknown>, source: string): string | void;