@plumeria/turbopack-loader 16.4.2 → 17.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/dist/index.d.ts +7 -0
- package/dist/index.js +99 -76
- package/dist/split-css-rules.js +16 -10
- package/package.json +3 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
export interface LoaderOptions {
|
|
2
|
+
include?: string[];
|
|
3
|
+
exclude?: string[];
|
|
4
|
+
styleProp?: string;
|
|
5
|
+
}
|
|
1
6
|
interface LoaderContext {
|
|
2
7
|
resourcePath: string;
|
|
3
8
|
context: string;
|
|
@@ -5,6 +10,8 @@ interface LoaderContext {
|
|
|
5
10
|
async: () => (err: Error | null, content?: string) => void;
|
|
6
11
|
addDependency: (path: string) => void;
|
|
7
12
|
clearDependencies: () => void;
|
|
13
|
+
getOptions?: () => LoaderOptions | undefined;
|
|
14
|
+
query?: LoaderOptions | string;
|
|
8
15
|
}
|
|
9
16
|
export default function loader(this: LoaderContext, source: string): Promise<void>;
|
|
10
17
|
export {};
|
package/dist/index.js
CHANGED
|
@@ -39,22 +39,55 @@ const fs = __importStar(require("fs"));
|
|
|
39
39
|
const path = __importStar(require("path"));
|
|
40
40
|
const zss_engine_1 = require("zss-engine");
|
|
41
41
|
const utils_1 = require("@plumeria/utils");
|
|
42
|
+
const compiler_1 = require("@plumeria/compiler");
|
|
42
43
|
const split_css_rules_1 = require("./split-css-rules");
|
|
43
44
|
const file_lock_1 = require("./file-lock");
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
45
|
+
const GENERATED_MARKER = '/* plumeria: generated */';
|
|
46
|
+
const DEFAULT_INCLUDE = ['**/*.{js,jsx,ts,tsx}'];
|
|
47
|
+
const DEFAULT_EXCLUDE = ['**/node_modules/**', '**/dist/**', '**/.next/**'];
|
|
48
|
+
let productionCss = null;
|
|
49
|
+
async function generateProductionCss(virtualFilePath, options) {
|
|
50
|
+
const lockDir = virtualFilePath + '.lock';
|
|
51
|
+
await (0, file_lock_1.acquireLock)(lockDir);
|
|
52
|
+
try {
|
|
53
|
+
let current = '';
|
|
52
54
|
try {
|
|
53
|
-
|
|
55
|
+
current = fs.readFileSync(virtualFilePath, 'utf-8');
|
|
54
56
|
}
|
|
55
57
|
catch (e) {
|
|
56
58
|
}
|
|
59
|
+
if (current.startsWith(GENERATED_MARKER))
|
|
60
|
+
return;
|
|
61
|
+
const css = (0, compiler_1.compileCSS)({
|
|
62
|
+
include: options.include ?? DEFAULT_INCLUDE,
|
|
63
|
+
exclude: options.exclude ?? DEFAULT_EXCLUDE,
|
|
64
|
+
cwd: process.cwd(),
|
|
65
|
+
styleProp: options.styleProp ?? utils_1.DEFAULT_STYLE_PROP,
|
|
66
|
+
});
|
|
67
|
+
const optimized = await (0, utils_1.optimizer)(css);
|
|
68
|
+
const tempPath = `${virtualFilePath}.${process.pid}.tmp`;
|
|
69
|
+
fs.writeFileSync(tempPath, `${GENERATED_MARKER}\n${optimized}`, 'utf-8');
|
|
70
|
+
fs.renameSync(tempPath, virtualFilePath);
|
|
71
|
+
}
|
|
72
|
+
finally {
|
|
73
|
+
(0, file_lock_1.releaseLockSync)(lockDir);
|
|
57
74
|
}
|
|
75
|
+
}
|
|
76
|
+
const ensureProductionCss = (virtualFilePath, options) => {
|
|
77
|
+
if (!productionCss) {
|
|
78
|
+
productionCss = generateProductionCss(virtualFilePath, options);
|
|
79
|
+
}
|
|
80
|
+
return productionCss;
|
|
81
|
+
};
|
|
82
|
+
async function loader(source) {
|
|
83
|
+
const callback = this.async();
|
|
84
|
+
const loaderOptions = this.getOptions?.() ??
|
|
85
|
+
(typeof this.query === 'object' ? this.query : undefined) ??
|
|
86
|
+
{};
|
|
87
|
+
const styleProp = loaderOptions.styleProp ?? utils_1.DEFAULT_STYLE_PROP;
|
|
88
|
+
const resourcePath = this.resourcePath;
|
|
89
|
+
const isProduction = process.env.NODE_ENV === 'production';
|
|
90
|
+
const VIRTUAL_FILE_PATH = path.resolve(__dirname, '..', 'zero-virtual.css');
|
|
58
91
|
if (resourcePath.includes('node_modules') ||
|
|
59
92
|
!source.includes('@plumeria/core')) {
|
|
60
93
|
return callback(null, source);
|
|
@@ -335,17 +368,7 @@ async function loader(source) {
|
|
|
335
368
|
const processedDecls = new Set();
|
|
336
369
|
const idSpans = new Set();
|
|
337
370
|
const excludedSpans = new Set();
|
|
338
|
-
const
|
|
339
|
-
const init = decl.init;
|
|
340
|
-
if (init && utils_1.t.isCallExpression(init) && utils_1.t.isIdentifier(init.callee)) {
|
|
341
|
-
const varName = init.callee.value;
|
|
342
|
-
if ((localCreateStyles[varName] &&
|
|
343
|
-
localCreateStyles[varName].type === 'variant') ||
|
|
344
|
-
mergedVariantsTable[varName]) {
|
|
345
|
-
throwCompilationError(`Plumeria: Assigning the return value of css.variants() to a variable is not supported.\nPlease pass the variant function directly to styleName or css.use(). Found assignment to: ${utils_1.t.isIdentifier(decl.id) ? decl.id.value : 'unknown'}`, init);
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
};
|
|
371
|
+
const referenceIdents = (0, utils_1.collectReferenceIdentifiers)(ast);
|
|
349
372
|
const registerStyle = (node, declSpan, isExported) => {
|
|
350
373
|
let propName;
|
|
351
374
|
const init = node.init;
|
|
@@ -449,7 +472,6 @@ async function loader(source) {
|
|
|
449
472
|
else if (propName === 'createTheme' &&
|
|
450
473
|
init.arguments.length >= 2 &&
|
|
451
474
|
utils_1.t.isObjectExpression(init.arguments[1].expression)) {
|
|
452
|
-
isThemeCSS = true;
|
|
453
475
|
if (utils_1.t.isIdentifier(node.id)) {
|
|
454
476
|
idSpans.add(node.id.span.start);
|
|
455
477
|
}
|
|
@@ -570,7 +592,6 @@ async function loader(source) {
|
|
|
570
592
|
if (utils_1.t.isVariableDeclaration(node.declaration)) {
|
|
571
593
|
processedDecls.add(node.declaration);
|
|
572
594
|
node.declaration.declarations.forEach((decl) => {
|
|
573
|
-
checkVariantAssignment(decl);
|
|
574
595
|
registerStyle(decl, node.span, true);
|
|
575
596
|
checkStyleAliasAssignment(decl);
|
|
576
597
|
});
|
|
@@ -580,7 +601,6 @@ async function loader(source) {
|
|
|
580
601
|
if (processedDecls.has(node))
|
|
581
602
|
return;
|
|
582
603
|
node.declarations.forEach((decl) => {
|
|
583
|
-
checkVariantAssignment(decl);
|
|
584
604
|
registerStyle(decl, node.span, false);
|
|
585
605
|
checkStyleAliasAssignment(decl);
|
|
586
606
|
});
|
|
@@ -635,7 +655,6 @@ async function loader(source) {
|
|
|
635
655
|
else if (propName === 'createTheme' &&
|
|
636
656
|
args.length >= 2 &&
|
|
637
657
|
utils_1.t.isObjectExpression(args[1].expression)) {
|
|
638
|
-
isThemeCSS = true;
|
|
639
658
|
let selector = '';
|
|
640
659
|
const selectorExpr = args[0].expression;
|
|
641
660
|
if (utils_1.t.isStringLiteral(selectorExpr)) {
|
|
@@ -717,10 +736,17 @@ async function loader(source) {
|
|
|
717
736
|
else if (utils_1.t.isMemberExpression(expr) &&
|
|
718
737
|
utils_1.t.isIdentifier(expr.object) &&
|
|
719
738
|
(utils_1.t.isIdentifier(expr.property) || expr.property.type === 'Computed')) {
|
|
720
|
-
if (expr.property.type === 'Computed')
|
|
721
|
-
return null;
|
|
722
739
|
const varName = expr.object.value;
|
|
723
|
-
|
|
740
|
+
let propName;
|
|
741
|
+
if (expr.property.type === 'Computed') {
|
|
742
|
+
const keyExpr = expr.property.expression;
|
|
743
|
+
if (!utils_1.t.isStringLiteral(keyExpr))
|
|
744
|
+
return null;
|
|
745
|
+
propName = keyExpr.value;
|
|
746
|
+
}
|
|
747
|
+
else {
|
|
748
|
+
propName = expr.property.value;
|
|
749
|
+
}
|
|
724
750
|
const styleInfo = localCreateStyles[varName];
|
|
725
751
|
if (styleInfo?.obj[propName]) {
|
|
726
752
|
const style = styleInfo.obj[propName];
|
|
@@ -829,6 +855,14 @@ async function loader(source) {
|
|
|
829
855
|
else if (node.type === 'ParenthesisExpression') {
|
|
830
856
|
return collectConditions(node.expression, currentTestStrings);
|
|
831
857
|
}
|
|
858
|
+
if (currentTestStrings.length > 0 &&
|
|
859
|
+
utils_1.t.isMemberExpression(node) &&
|
|
860
|
+
utils_1.t.isIdentifier(node.object) &&
|
|
861
|
+
node.property.type === 'Computed' &&
|
|
862
|
+
resolveCreateObject(node.object.value)) {
|
|
863
|
+
const varName = node.object.value;
|
|
864
|
+
throwCompilationError(`Plumeria: "${getSource(node)}" cannot be used inside a condition, because its bracket key is not a literal.\nMove the condition into the brackets instead, e.g. ${varName}[cond ? 'a' : 'b'].`, node);
|
|
865
|
+
}
|
|
832
866
|
assertResolvable(node);
|
|
833
867
|
return false;
|
|
834
868
|
};
|
|
@@ -1306,17 +1340,6 @@ async function loader(source) {
|
|
|
1306
1340
|
return;
|
|
1307
1341
|
}
|
|
1308
1342
|
}
|
|
1309
|
-
if (localStyle && localStyle.type === 'variant') {
|
|
1310
|
-
const variantMap = localStyle.hashMap[propName];
|
|
1311
|
-
if (variantMap) {
|
|
1312
|
-
replacements.push({
|
|
1313
|
-
start: node.span.start - baseByteOffset,
|
|
1314
|
-
end: node.span.end - baseByteOffset,
|
|
1315
|
-
content: `(${JSON.stringify(variantMap)})`,
|
|
1316
|
-
});
|
|
1317
|
-
return;
|
|
1318
|
-
}
|
|
1319
|
-
}
|
|
1320
1343
|
let hash = scannedTables.createHashTable[uniqueKey];
|
|
1321
1344
|
if (!hash) {
|
|
1322
1345
|
hash = mergedCreateTable[varName];
|
|
@@ -1377,13 +1400,21 @@ async function loader(source) {
|
|
|
1377
1400
|
return;
|
|
1378
1401
|
if (idSpans.has(node.span.start))
|
|
1379
1402
|
return;
|
|
1380
|
-
|
|
1381
|
-
|
|
1403
|
+
if (!referenceIdents.references.has(node.span.start))
|
|
1404
|
+
return;
|
|
1405
|
+
const prefix = referenceIdents.shorthands.has(node.span.start)
|
|
1406
|
+
? `${node.value}: `
|
|
1407
|
+
: '';
|
|
1408
|
+
const pushReplacement = (content) => {
|
|
1382
1409
|
replacements.push({
|
|
1383
1410
|
start: node.span.start - baseByteOffset,
|
|
1384
1411
|
end: node.span.end - baseByteOffset,
|
|
1385
|
-
content:
|
|
1412
|
+
content: `${prefix}${content}`,
|
|
1386
1413
|
});
|
|
1414
|
+
};
|
|
1415
|
+
const styleInfo = localCreateStyles[node.value];
|
|
1416
|
+
if (styleInfo) {
|
|
1417
|
+
pushReplacement(`(${JSON.stringify(styleInfo.hashMap)})`);
|
|
1387
1418
|
return;
|
|
1388
1419
|
}
|
|
1389
1420
|
const varName = node.value;
|
|
@@ -1402,11 +1433,7 @@ async function loader(source) {
|
|
|
1402
1433
|
hashMap[key] = atomicMap[key];
|
|
1403
1434
|
}
|
|
1404
1435
|
});
|
|
1405
|
-
|
|
1406
|
-
start: node.span.start - baseByteOffset,
|
|
1407
|
-
end: node.span.end - baseByteOffset,
|
|
1408
|
-
content: `(${JSON.stringify(hashMap)})`,
|
|
1409
|
-
});
|
|
1436
|
+
pushReplacement(`(${JSON.stringify(hashMap)})`);
|
|
1410
1437
|
}
|
|
1411
1438
|
}
|
|
1412
1439
|
let themeHash = mergedCreateThemeHashTable[varName];
|
|
@@ -1416,11 +1443,7 @@ async function loader(source) {
|
|
|
1416
1443
|
if (themeHash) {
|
|
1417
1444
|
const atomicMap = scannedTables.createAtomicMapTable[themeHash];
|
|
1418
1445
|
if (atomicMap) {
|
|
1419
|
-
|
|
1420
|
-
start: node.span.start - baseByteOffset,
|
|
1421
|
-
end: node.span.end - baseByteOffset,
|
|
1422
|
-
content: `(${JSON.stringify(atomicMap)})`,
|
|
1423
|
-
});
|
|
1446
|
+
pushReplacement(`(${JSON.stringify(atomicMap)})`);
|
|
1424
1447
|
return;
|
|
1425
1448
|
}
|
|
1426
1449
|
}
|
|
@@ -1431,11 +1454,7 @@ async function loader(source) {
|
|
|
1431
1454
|
if (staticHash) {
|
|
1432
1455
|
const staticObj = scannedTables.createStaticObjectTable[staticHash];
|
|
1433
1456
|
if (staticObj) {
|
|
1434
|
-
|
|
1435
|
-
start: node.span.start - baseByteOffset,
|
|
1436
|
-
end: node.span.end - baseByteOffset,
|
|
1437
|
-
content: `(${JSON.stringify(staticObj)})`,
|
|
1438
|
-
});
|
|
1457
|
+
pushReplacement(`(${JSON.stringify(staticObj)})`);
|
|
1439
1458
|
}
|
|
1440
1459
|
}
|
|
1441
1460
|
},
|
|
@@ -1443,7 +1462,7 @@ async function loader(source) {
|
|
|
1443
1462
|
if (node.name.type !== 'Identifier')
|
|
1444
1463
|
return;
|
|
1445
1464
|
const attrName = node.name.value;
|
|
1446
|
-
if (attrName !==
|
|
1465
|
+
if (attrName !== styleProp) {
|
|
1447
1466
|
let parentTagName = '';
|
|
1448
1467
|
for (const [, val] of jsxOpeningElementMap) {
|
|
1449
1468
|
const found = val.attributes
|
|
@@ -1728,12 +1747,27 @@ async function loader(source) {
|
|
|
1728
1747
|
}
|
|
1729
1748
|
},
|
|
1730
1749
|
});
|
|
1750
|
+
const buildExportedInit = (info) => {
|
|
1751
|
+
const keys = Object.keys(info.obj);
|
|
1752
|
+
if (isProduction || keys.length === 0) {
|
|
1753
|
+
return JSON.stringify('');
|
|
1754
|
+
}
|
|
1755
|
+
const head = JSON.stringify(`Plumeria: "${info.name}.`);
|
|
1756
|
+
const tail = JSON.stringify(`" was read at runtime. The file that read it was not compiled ` +
|
|
1757
|
+
`because it does not reference "@plumeria/core" — add ` +
|
|
1758
|
+
`import '@plumeria/core'; to it (see the stack below). Defined in ` +
|
|
1759
|
+
`${path.relative(process.cwd(), resourcePath)}.`);
|
|
1760
|
+
return (`(()=>{const k=new Set(${JSON.stringify(keys)});` +
|
|
1761
|
+
`return new Proxy({},{get(t,p){` +
|
|
1762
|
+
`if(typeof p==="string"&&k.has(p))throw new Error(${head}+p+${tail});` +
|
|
1763
|
+
`return t[p];}});})()`);
|
|
1764
|
+
};
|
|
1731
1765
|
Object.values(localCreateStyles).forEach((info) => {
|
|
1732
1766
|
if (info.isExported) {
|
|
1733
1767
|
replacements.push({
|
|
1734
1768
|
start: info.initSpan.start,
|
|
1735
1769
|
end: info.initSpan.end,
|
|
1736
|
-
content:
|
|
1770
|
+
content: buildExportedInit(info),
|
|
1737
1771
|
});
|
|
1738
1772
|
}
|
|
1739
1773
|
else {
|
|
@@ -1764,16 +1798,16 @@ async function loader(source) {
|
|
|
1764
1798
|
if (!relativeImportPath.startsWith('.')) {
|
|
1765
1799
|
relativeImportPath = './' + relativeImportPath;
|
|
1766
1800
|
}
|
|
1767
|
-
const
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
return callback(null, transformedSource);
|
|
1801
|
+
const postfix = `\nimport "${relativeImportPath}";`;
|
|
1802
|
+
if (isProduction) {
|
|
1803
|
+
await ensureProductionCss(VIRTUAL_FILE_PATH, loaderOptions);
|
|
1804
|
+
return callback(null, transformedSource + postfix);
|
|
1771
1805
|
}
|
|
1772
1806
|
if (extractedSheets.length > 0 && process.env.NODE_ENV === 'development') {
|
|
1773
1807
|
const LOCK_DIR_PATH = VIRTUAL_FILE_PATH + '.lock';
|
|
1774
1808
|
await (0, file_lock_1.acquireLock)(LOCK_DIR_PATH);
|
|
1809
|
+
let currentCss = '';
|
|
1775
1810
|
try {
|
|
1776
|
-
let currentCss = '';
|
|
1777
1811
|
try {
|
|
1778
1812
|
currentCss = fs.readFileSync(VIRTUAL_FILE_PATH, 'utf-8');
|
|
1779
1813
|
}
|
|
@@ -1789,18 +1823,14 @@ async function loader(source) {
|
|
|
1789
1823
|
hasNewRule = true;
|
|
1790
1824
|
}
|
|
1791
1825
|
}
|
|
1792
|
-
if (hasNewRule
|
|
1826
|
+
if (hasNewRule) {
|
|
1793
1827
|
const nextCss = (0, utils_1.orderMediaLast)(Array.from(ruleSet)).join('\n\n') + '\n';
|
|
1794
1828
|
fs.writeFileSync(VIRTUAL_FILE_PATH, nextCss, 'utf-8');
|
|
1795
|
-
lastValidCss = nextCss;
|
|
1796
|
-
}
|
|
1797
|
-
else {
|
|
1798
|
-
lastValidCss = currentCss;
|
|
1799
1829
|
}
|
|
1800
1830
|
}
|
|
1801
1831
|
catch (innerError) {
|
|
1802
1832
|
try {
|
|
1803
|
-
fs.writeFileSync(VIRTUAL_FILE_PATH,
|
|
1833
|
+
fs.writeFileSync(VIRTUAL_FILE_PATH, currentCss, 'utf-8');
|
|
1804
1834
|
}
|
|
1805
1835
|
catch (e) {
|
|
1806
1836
|
}
|
|
@@ -1810,13 +1840,6 @@ async function loader(source) {
|
|
|
1810
1840
|
(0, file_lock_1.releaseLockSync)(LOCK_DIR_PATH);
|
|
1811
1841
|
}
|
|
1812
1842
|
}
|
|
1813
|
-
else if (!isProduction) {
|
|
1814
|
-
try {
|
|
1815
|
-
lastValidCss = fs.readFileSync(VIRTUAL_FILE_PATH, 'utf-8');
|
|
1816
|
-
}
|
|
1817
|
-
catch (e) {
|
|
1818
|
-
}
|
|
1819
|
-
}
|
|
1820
1843
|
return callback(null, transformedSource + postfix);
|
|
1821
1844
|
}
|
|
1822
1845
|
catch (error) {
|
package/dist/split-css-rules.js
CHANGED
|
@@ -7,6 +7,14 @@ function splitCssRules(css) {
|
|
|
7
7
|
let depth = 0;
|
|
8
8
|
let inComment = false;
|
|
9
9
|
let inString = null;
|
|
10
|
+
let hasContent = false;
|
|
11
|
+
const flush = () => {
|
|
12
|
+
const trimmed = currentRule.trim();
|
|
13
|
+
if (trimmed)
|
|
14
|
+
rules.push(trimmed);
|
|
15
|
+
currentRule = '';
|
|
16
|
+
hasContent = false;
|
|
17
|
+
};
|
|
10
18
|
for (let i = 0; i < css.length; i++) {
|
|
11
19
|
const char = css[i];
|
|
12
20
|
const nextChar = css[i + 1];
|
|
@@ -16,6 +24,8 @@ function splitCssRules(css) {
|
|
|
16
24
|
currentRule += '/';
|
|
17
25
|
i++;
|
|
18
26
|
inComment = false;
|
|
27
|
+
if (depth === 0 && !hasContent)
|
|
28
|
+
flush();
|
|
19
29
|
}
|
|
20
30
|
continue;
|
|
21
31
|
}
|
|
@@ -41,26 +51,22 @@ function splitCssRules(css) {
|
|
|
41
51
|
if (char === '"' || char === "'") {
|
|
42
52
|
currentRule += char;
|
|
43
53
|
inString = char;
|
|
54
|
+
hasContent = true;
|
|
44
55
|
continue;
|
|
45
56
|
}
|
|
46
57
|
currentRule += char;
|
|
58
|
+
if (char.trim())
|
|
59
|
+
hasContent = true;
|
|
47
60
|
if (char === '{') {
|
|
48
61
|
depth++;
|
|
49
62
|
}
|
|
50
63
|
else if (char === '}') {
|
|
51
64
|
depth--;
|
|
52
|
-
if (depth === 0)
|
|
53
|
-
|
|
54
|
-
if (trimmed)
|
|
55
|
-
rules.push(trimmed);
|
|
56
|
-
currentRule = '';
|
|
57
|
-
}
|
|
65
|
+
if (depth === 0)
|
|
66
|
+
flush();
|
|
58
67
|
}
|
|
59
68
|
else if (char === ';' && depth === 0) {
|
|
60
|
-
|
|
61
|
-
if (trimmed)
|
|
62
|
-
rules.push(trimmed);
|
|
63
|
-
currentRule = '';
|
|
69
|
+
flush();
|
|
64
70
|
}
|
|
65
71
|
}
|
|
66
72
|
const trimmed = currentRule.trim();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@plumeria/turbopack-loader",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "17.0.0",
|
|
4
4
|
"description": "Plumeria Turbopack-loader",
|
|
5
5
|
"author": "Refirst 11",
|
|
6
6
|
"license": "MIT",
|
|
@@ -22,7 +22,8 @@
|
|
|
22
22
|
"zero-virtual.css"
|
|
23
23
|
],
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@plumeria/
|
|
25
|
+
"@plumeria/compiler": "^17.0.0",
|
|
26
|
+
"@plumeria/utils": "^17.0.0"
|
|
26
27
|
},
|
|
27
28
|
"devDependencies": {
|
|
28
29
|
"@swc/core": "1.15.43",
|