@bamboocss/vite 1.20.4 → 1.22.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/client.d.ts +13 -0
- package/dist/index.cjs +146 -13
- package/dist/index.d.cts +62 -8
- package/dist/index.d.mts +62 -8
- package/dist/index.mjs +145 -14
- package/package.json +12 -10
package/client.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ambient declaration for the virtual stylesheet, so `import 'virtual:bamboo.css'`
|
|
3
|
+
* typechecks.
|
|
4
|
+
*
|
|
5
|
+
* Reference it once, next to the `vite/client` reference a vite project already has:
|
|
6
|
+
*
|
|
7
|
+
* /// <reference types="@bamboocss/vite/client" />
|
|
8
|
+
*
|
|
9
|
+
* Shipped as a separate entry rather than folded into the package's own types, because a
|
|
10
|
+
* `declare module` in the main entry would apply to every consumer of the exported API —
|
|
11
|
+
* including builds that do not use the plugin.
|
|
12
|
+
*/
|
|
13
|
+
declare module 'virtual:bamboo.css' {}
|
package/dist/index.cjs
CHANGED
|
@@ -24,6 +24,8 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
24
24
|
enumerable: true
|
|
25
25
|
}) : target, mod));
|
|
26
26
|
//#endregion
|
|
27
|
+
let _bamboocss_node = require("@bamboocss/node");
|
|
28
|
+
let _bamboocss_logger = require("@bamboocss/logger");
|
|
27
29
|
let _bamboocss_config_ts_path = require("@bamboocss/config/ts-path");
|
|
28
30
|
let _bamboocss_extractor = require("@bamboocss/extractor");
|
|
29
31
|
let magic_string = require("magic-string");
|
|
@@ -32,8 +34,90 @@ let ts_morph = require("ts-morph");
|
|
|
32
34
|
let _bamboocss_core = require("@bamboocss/core");
|
|
33
35
|
let _bamboocss_shared = require("@bamboocss/shared");
|
|
34
36
|
let node_path = require("node:path");
|
|
35
|
-
|
|
36
|
-
|
|
37
|
+
//#region src/css.ts
|
|
38
|
+
/**
|
|
39
|
+
* What a project imports to get the stylesheet.
|
|
40
|
+
*
|
|
41
|
+
* Spelled with a `.css` extension because that is how vite decides what a module is: the
|
|
42
|
+
* id is all it has for a module with no file behind it, so `virtual:bamboo` would be
|
|
43
|
+
* bundled as javascript and injected as a script.
|
|
44
|
+
*/
|
|
45
|
+
const VIRTUAL_CSS_ID = "virtual:bamboo.css";
|
|
46
|
+
/**
|
|
47
|
+
* Rollup's convention for a module with no file: a leading NUL tells every other plugin
|
|
48
|
+
* not to try reading it off disk.
|
|
49
|
+
*/
|
|
50
|
+
const RESOLVED_ID = `\0${VIRTUAL_CSS_ID}`;
|
|
51
|
+
/**
|
|
52
|
+
* Serve bamboo's stylesheet as a virtual module, in dev and in build.
|
|
53
|
+
*
|
|
54
|
+
* This is the integration itself, not an optimisation: without it nothing emits css and
|
|
55
|
+
* the generated `styled-system` runtime names classes no rule exists for.
|
|
56
|
+
*
|
|
57
|
+
* A virtual module rather than a file written to disk, because vite already owns the two
|
|
58
|
+
* things a file would have to reimplement. In dev it injects css over the websocket and
|
|
59
|
+
* replaces it in place, so an edit repaints without reloading; in build it hashes the
|
|
60
|
+
* content into the asset graph and lets the bundler decide where it lands. Writing
|
|
61
|
+
* `styles.css` and asking the project to import it means the build reads a file the same
|
|
62
|
+
* process just wrote, which is a race on any watch rebuild.
|
|
63
|
+
*/
|
|
64
|
+
const bamboocssCss = (options = {}) => {
|
|
65
|
+
const { configPath, cwd } = options;
|
|
66
|
+
const builder = new _bamboocss_node.Builder();
|
|
67
|
+
let server;
|
|
68
|
+
/**
|
|
69
|
+
* Serialised, because both `load` and the watcher can reach it and `Builder` keeps one
|
|
70
|
+
* context. Two overlapping passes would extract into the same encoder and emit the
|
|
71
|
+
* stylesheet twice over.
|
|
72
|
+
*/
|
|
73
|
+
let pending;
|
|
74
|
+
const build = async () => {
|
|
75
|
+
await builder.setup({
|
|
76
|
+
configPath,
|
|
77
|
+
cwd
|
|
78
|
+
});
|
|
79
|
+
await builder.emit();
|
|
80
|
+
builder.extract();
|
|
81
|
+
return builder.toCss({ layerParams: true });
|
|
82
|
+
};
|
|
83
|
+
const generate = () => {
|
|
84
|
+
pending = Promise.resolve(pending).catch(() => void 0).then(build);
|
|
85
|
+
return pending;
|
|
86
|
+
};
|
|
87
|
+
return {
|
|
88
|
+
name: "bamboocss:css",
|
|
89
|
+
resolveId(id) {
|
|
90
|
+
if (id === "virtual:bamboo.css") return RESOLVED_ID;
|
|
91
|
+
return null;
|
|
92
|
+
},
|
|
93
|
+
async load(id) {
|
|
94
|
+
if (id !== RESOLVED_ID) return null;
|
|
95
|
+
const css = await generate();
|
|
96
|
+
if (this.addWatchFile) for (const file of builder.context?.getFiles() ?? []) this.addWatchFile(builder.context.runtime.path.abs(builder.context.config.cwd, file));
|
|
97
|
+
return css;
|
|
98
|
+
},
|
|
99
|
+
configureServer(devServer) {
|
|
100
|
+
server = devServer;
|
|
101
|
+
const invalidate = (file) => {
|
|
102
|
+
const ctx = builder.context;
|
|
103
|
+
if (!ctx) return;
|
|
104
|
+
if (!ctx.getFiles().some((f) => ctx.runtime.path.abs(ctx.config.cwd, f) === file)) return;
|
|
105
|
+
const mod = server?.moduleGraph.getModuleById(RESOLVED_ID);
|
|
106
|
+
if (!mod) return;
|
|
107
|
+
server?.moduleGraph.invalidateModule(mod);
|
|
108
|
+
server?.ws.send({
|
|
109
|
+
type: "update",
|
|
110
|
+
updates: []
|
|
111
|
+
});
|
|
112
|
+
_bamboocss_logger.logger.debug("vite", `styles invalidated by ${file}`);
|
|
113
|
+
};
|
|
114
|
+
devServer.watcher.on("change", invalidate);
|
|
115
|
+
devServer.watcher.on("add", invalidate);
|
|
116
|
+
devServer.watcher.on("unlink", invalidate);
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
};
|
|
120
|
+
//#endregion
|
|
37
121
|
//#region src/fold-partial.ts
|
|
38
122
|
/**
|
|
39
123
|
* Statically resolvable means: every box in the tree carries a known value.
|
|
@@ -480,9 +564,6 @@ const planPartialFold = (argument, boxNode, styles, deps) => {
|
|
|
480
564
|
if (!partition) return void 0;
|
|
481
565
|
const className = deps.runtimeCss(partition.staticStyles);
|
|
482
566
|
if (!className && !partition.finite.length) return void 0;
|
|
483
|
-
if (deps.ctx.config.cssMode === "grouped") {
|
|
484
|
-
if ((className ? 1 : 0) + partition.finite.length + (partition.dynamicText.length ? 1 : 0) > 1) return void 0;
|
|
485
|
-
}
|
|
486
567
|
return {
|
|
487
568
|
className,
|
|
488
569
|
dynamicText: partition.dynamicText.length ? `{ ${partition.dynamicText.join(", ")} }` : void 0,
|
|
@@ -676,7 +757,6 @@ const ensureCxImport = (call, calleeRoot, isBambooCssModule, isGeneratedCssModul
|
|
|
676
757
|
//#region src/runtime-css.ts
|
|
677
758
|
/** The shape `createCss` and `createMergeCss` both take, derived from a resolved context. */
|
|
678
759
|
const createCssContext = (ctx) => ({
|
|
679
|
-
grouped: ctx.config.cssMode === "grouped",
|
|
680
760
|
hash: Boolean(ctx.hash.className),
|
|
681
761
|
conditions: {
|
|
682
762
|
shift: ctx.conditions.shift,
|
|
@@ -1502,6 +1582,23 @@ const isGeneratedOutput = (filePath, ctx) => {
|
|
|
1502
1582
|
const file = slashed(filePath);
|
|
1503
1583
|
return file === root || file.startsWith(`${root}/`);
|
|
1504
1584
|
};
|
|
1585
|
+
/**
|
|
1586
|
+
* The skip reasons that leave a `css()`-family call in the output.
|
|
1587
|
+
*
|
|
1588
|
+
* `overlapping` is handled by the enclosing fold, and `not-imported` is somebody else's
|
|
1589
|
+
* function of the same name — neither leaves a call of ours. `not-foldable` is a `cva`/`sva`
|
|
1590
|
+
* definition, which keeps the recipe runtime rather than the css engine; see `strict`.
|
|
1591
|
+
*/
|
|
1592
|
+
const SURVIVES_TO_RUNTIME = new Set([
|
|
1593
|
+
"dynamic",
|
|
1594
|
+
"raw-call",
|
|
1595
|
+
"unsupported-kind",
|
|
1596
|
+
"no-call-expression",
|
|
1597
|
+
"empty",
|
|
1598
|
+
"unresolved-token"
|
|
1599
|
+
]);
|
|
1600
|
+
/** 1-indexed line of a source offset, for an error a user can navigate to. */
|
|
1601
|
+
const lineAt = (code, offset) => code.slice(0, offset).split("\n").length;
|
|
1505
1602
|
const formatSkipped = (id, skipped) => {
|
|
1506
1603
|
const counts = /* @__PURE__ */ new Map();
|
|
1507
1604
|
for (const entry of skipped) counts.set(entry.reason, (counts.get(entry.reason) ?? 0) + 1);
|
|
@@ -1510,16 +1607,17 @@ const formatSkipped = (id, skipped) => {
|
|
|
1510
1607
|
/**
|
|
1511
1608
|
* Vite integration for Bamboo CSS.
|
|
1512
1609
|
*
|
|
1513
|
-
*
|
|
1514
|
-
*
|
|
1610
|
+
* Two plugins, because they do unrelated jobs on different schedules. The first emits the
|
|
1611
|
+
* stylesheet as a virtual module and runs in dev and build alike — that is the integration,
|
|
1612
|
+
* and nothing styles without it. The second is the optional build-time fold.
|
|
1515
1613
|
*
|
|
1516
|
-
*
|
|
1614
|
+
* The fold runs with `enforce: 'pre'` so it sees module source as close as possible to what
|
|
1517
1615
|
* the CSS extractor reads off disk. A plugin that rewrites style calls before bamboo
|
|
1518
1616
|
* sees them would otherwise make the two disagree, and a folded class could end up
|
|
1519
1617
|
* with no matching rule.
|
|
1520
1618
|
*/
|
|
1521
1619
|
const bamboocss = (options = {}) => {
|
|
1522
|
-
const { transform =
|
|
1620
|
+
const { transform = true, partial, configPath, cwd, reportSkipped = false, reportSummary = true, strict = false } = options;
|
|
1523
1621
|
/** Totals across the build, for the summary. */
|
|
1524
1622
|
const totals = {
|
|
1525
1623
|
folded: 0,
|
|
@@ -1527,6 +1625,8 @@ const bamboocss = (options = {}) => {
|
|
|
1527
1625
|
filesWithFolds: 0,
|
|
1528
1626
|
skipped: /* @__PURE__ */ new Map()
|
|
1529
1627
|
};
|
|
1628
|
+
/** Under `strict`, every call that would still reach the runtime. */
|
|
1629
|
+
const survivors = [];
|
|
1530
1630
|
let ctx;
|
|
1531
1631
|
let runtimeCss;
|
|
1532
1632
|
let setup;
|
|
@@ -1540,8 +1640,11 @@ const bamboocss = (options = {}) => {
|
|
|
1540
1640
|
});
|
|
1541
1641
|
await setup;
|
|
1542
1642
|
};
|
|
1543
|
-
return {
|
|
1544
|
-
|
|
1643
|
+
return [bamboocssCss({
|
|
1644
|
+
configPath,
|
|
1645
|
+
cwd
|
|
1646
|
+
}), {
|
|
1647
|
+
name: "bamboocss:fold",
|
|
1545
1648
|
enforce: "pre",
|
|
1546
1649
|
apply: "build",
|
|
1547
1650
|
async buildStart() {
|
|
@@ -1550,6 +1653,7 @@ const bamboocss = (options = {}) => {
|
|
|
1550
1653
|
totals.files = 0;
|
|
1551
1654
|
totals.filesWithFolds = 0;
|
|
1552
1655
|
totals.skipped.clear();
|
|
1656
|
+
survivors.length = 0;
|
|
1553
1657
|
await ensureContext();
|
|
1554
1658
|
},
|
|
1555
1659
|
/**
|
|
@@ -1611,6 +1715,23 @@ const bamboocss = (options = {}) => {
|
|
|
1611
1715
|
totals.folded += result.folded.length;
|
|
1612
1716
|
if (result.folded.length) totals.filesWithFolds++;
|
|
1613
1717
|
for (const entry of result.skipped) totals.skipped.set(entry.reason, (totals.skipped.get(entry.reason) ?? 0) + 1);
|
|
1718
|
+
if (strict) {
|
|
1719
|
+
for (const entry of result.skipped) {
|
|
1720
|
+
if (!SURVIVES_TO_RUNTIME.has(entry.reason)) continue;
|
|
1721
|
+
survivors.push({
|
|
1722
|
+
file: filePath,
|
|
1723
|
+
line: lineAt(code, entry.start),
|
|
1724
|
+
name: entry.name,
|
|
1725
|
+
reason: entry.reason
|
|
1726
|
+
});
|
|
1727
|
+
}
|
|
1728
|
+
if (result.code.includes("cssLeaf(")) survivors.push({
|
|
1729
|
+
file: filePath,
|
|
1730
|
+
line: lineAt(result.code, result.code.indexOf("cssLeaf(")),
|
|
1731
|
+
name: "cssLeaf",
|
|
1732
|
+
reason: "lowered-leaf"
|
|
1733
|
+
});
|
|
1734
|
+
}
|
|
1614
1735
|
if (reportSkipped && result.skipped.length) _bamboocss_logger.logger.info("vite:transform", formatSkipped(filePath, result.skipped));
|
|
1615
1736
|
for (const dependency of result.dependencies) this.addWatchFile?.(dependency);
|
|
1616
1737
|
if (!result.folded.length) return null;
|
|
@@ -1621,6 +1742,16 @@ const bamboocss = (options = {}) => {
|
|
|
1621
1742
|
};
|
|
1622
1743
|
},
|
|
1623
1744
|
buildEnd() {
|
|
1745
|
+
if (strict && survivors.length) {
|
|
1746
|
+
const byFile = /* @__PURE__ */ new Map();
|
|
1747
|
+
for (const entry of survivors) {
|
|
1748
|
+
const list = byFile.get(entry.file) ?? [];
|
|
1749
|
+
list.push(entry);
|
|
1750
|
+
byFile.set(entry.file, list);
|
|
1751
|
+
}
|
|
1752
|
+
const detail = Array.from(byFile.entries()).map(([file, entries]) => [` ${file}`, ...entries.map((e) => ` ${e.line}: ${e.name}() — ${e.reason}`)].join("\n")).join("\n");
|
|
1753
|
+
throw new Error(`bamboocss: ${survivors.length} call(s) could not be folded, and \`strict\` is on.\n\n${detail}\n\nEach one keeps \`styled-system/css\` in the bundle, so the engine cannot be dropped however many other calls folded. Make the values static, move the variation into a \`cva\` variant, or generate them with \`staticCss\` — or set \`strict: false\` to accept the runtime.`);
|
|
1754
|
+
}
|
|
1624
1755
|
if (!transform || !reportSummary) return;
|
|
1625
1756
|
const declined = Array.from(totals.skipped.values()).reduce((sum, count) => sum + count, 0);
|
|
1626
1757
|
const total = totals.folded + declined;
|
|
@@ -1629,10 +1760,12 @@ const bamboocss = (options = {}) => {
|
|
|
1629
1760
|
const reasons = Array.from(totals.skipped.entries()).sort((a, b) => b[1] - a[1]).map(([reason, count]) => `${reason}=${count}`).join(" ");
|
|
1630
1761
|
_bamboocss_logger.logger.info("vite:transform", `Folded ${totals.folded}/${total} (${share}%) across ${totals.filesWithFolds}/${totals.files} files` + (reasons ? ` — declined: ${reasons}` : ""));
|
|
1631
1762
|
}
|
|
1632
|
-
};
|
|
1763
|
+
}];
|
|
1633
1764
|
};
|
|
1634
1765
|
//#endregion
|
|
1766
|
+
exports.VIRTUAL_CSS_ID = VIRTUAL_CSS_ID;
|
|
1635
1767
|
exports.bamboocss = bamboocss;
|
|
1768
|
+
exports.bamboocssCss = bamboocssCss;
|
|
1636
1769
|
exports.createRuntimeCss = createRuntimeCss;
|
|
1637
1770
|
exports.default = bamboocss;
|
|
1638
1771
|
exports.foldSource = foldSource;
|
package/dist/index.d.cts
CHANGED
|
@@ -1,8 +1,36 @@
|
|
|
1
|
+
import { Plugin } from "vite";
|
|
1
2
|
import { Context } from "@bamboocss/core";
|
|
2
3
|
import { Dict, ParserResultInterface } from "@bamboocss/types";
|
|
3
4
|
import MagicString from "magic-string";
|
|
4
|
-
import { Plugin } from "vite";
|
|
5
5
|
|
|
6
|
+
//#region src/css.d.ts
|
|
7
|
+
/**
|
|
8
|
+
* What a project imports to get the stylesheet.
|
|
9
|
+
*
|
|
10
|
+
* Spelled with a `.css` extension because that is how vite decides what a module is: the
|
|
11
|
+
* id is all it has for a module with no file behind it, so `virtual:bamboo` would be
|
|
12
|
+
* bundled as javascript and injected as a script.
|
|
13
|
+
*/
|
|
14
|
+
declare const VIRTUAL_CSS_ID = "virtual:bamboo.css";
|
|
15
|
+
interface BambooCssPluginOptions {
|
|
16
|
+
configPath?: string;
|
|
17
|
+
cwd?: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Serve bamboo's stylesheet as a virtual module, in dev and in build.
|
|
21
|
+
*
|
|
22
|
+
* This is the integration itself, not an optimisation: without it nothing emits css and
|
|
23
|
+
* the generated `styled-system` runtime names classes no rule exists for.
|
|
24
|
+
*
|
|
25
|
+
* A virtual module rather than a file written to disk, because vite already owns the two
|
|
26
|
+
* things a file would have to reimplement. In dev it injects css over the websocket and
|
|
27
|
+
* replaces it in place, so an edit repaints without reloading; in build it hashes the
|
|
28
|
+
* content into the asset graph and lets the bundler decide where it lands. Writing
|
|
29
|
+
* `styles.css` and asking the project to import it means the build reads a file the same
|
|
30
|
+
* process just wrote, which is a race on any watch rebuild.
|
|
31
|
+
*/
|
|
32
|
+
declare const bamboocssCss: (options?: BambooCssPluginOptions) => Plugin;
|
|
33
|
+
//#endregion
|
|
6
34
|
//#region src/runtime-css.d.ts
|
|
7
35
|
/**
|
|
8
36
|
* The generated runtime's `css`, rebuilt in-process from a resolved context.
|
|
@@ -101,9 +129,18 @@ interface BambooVitePluginOptions {
|
|
|
101
129
|
* Rewrite statically-resolvable `css()` and pattern calls into literal class
|
|
102
130
|
* strings, so they cost nothing at runtime.
|
|
103
131
|
*
|
|
104
|
-
*
|
|
132
|
+
* On by default, and build-only — it never runs in `vite dev`, where the parse would land
|
|
133
|
+
* on every hot update and a dev bundle gains nothing from pre-resolved calls.
|
|
105
134
|
*
|
|
106
|
-
*
|
|
135
|
+
* What it buys is per-call CPU, not bytes: the runtime still ships, because dropping it
|
|
136
|
+
* needs *every* call site in the graph to fold. Bundle size moves slightly against you —
|
|
137
|
+
* measured at -0.8% raw and +1.0% gzipped on `sandbox/runtime-perf`, since distinct class
|
|
138
|
+
* literals compress worse than the repeated `css({ … })` calls they replace. Set it to
|
|
139
|
+
* `false` if that trade is the wrong way round for you, or to keep builds faster: folding
|
|
140
|
+
* re-parses each module with `ts-morph`, roughly 0.3ms for a small component and 3ms for a
|
|
141
|
+
* 147-line file with 24 call sites.
|
|
142
|
+
*
|
|
143
|
+
* @default true
|
|
107
144
|
*/
|
|
108
145
|
transform?: boolean;
|
|
109
146
|
/**
|
|
@@ -135,18 +172,35 @@ interface BambooVitePluginOptions {
|
|
|
135
172
|
* @default true
|
|
136
173
|
*/
|
|
137
174
|
reportSummary?: boolean;
|
|
175
|
+
/**
|
|
176
|
+
* Fail the build when a `css()` or pattern call is left for the runtime.
|
|
177
|
+
*
|
|
178
|
+
* The fold's value is not the per-call CPU it saves — it is that a bundle where *every*
|
|
179
|
+
* such call folded no longer imports `styled-system/css` at all, and the engine behind it
|
|
180
|
+
* drops out. One survivor keeps the whole thing, so a coverage percentage cannot tell you
|
|
181
|
+
* whether you got the prize. This can.
|
|
182
|
+
*
|
|
183
|
+
* Deliberately silent about `cva`/`sva`. A `cva(...)` definition returns a function and can
|
|
184
|
+
* never collapse to a class string, so failing on it would make this unusable for anyone
|
|
185
|
+
* writing recipes — and recipes keep their own much smaller runtime by design. What this
|
|
186
|
+
* guarantees is narrower and checkable: nothing still calls `css()`.
|
|
187
|
+
*
|
|
188
|
+
* @default false
|
|
189
|
+
*/
|
|
190
|
+
strict?: boolean;
|
|
138
191
|
}
|
|
139
192
|
/**
|
|
140
193
|
* Vite integration for Bamboo CSS.
|
|
141
194
|
*
|
|
142
|
-
*
|
|
143
|
-
*
|
|
195
|
+
* Two plugins, because they do unrelated jobs on different schedules. The first emits the
|
|
196
|
+
* stylesheet as a virtual module and runs in dev and build alike — that is the integration,
|
|
197
|
+
* and nothing styles without it. The second is the optional build-time fold.
|
|
144
198
|
*
|
|
145
|
-
*
|
|
199
|
+
* The fold runs with `enforce: 'pre'` so it sees module source as close as possible to what
|
|
146
200
|
* the CSS extractor reads off disk. A plugin that rewrites style calls before bamboo
|
|
147
201
|
* sees them would otherwise make the two disagree, and a folded class could end up
|
|
148
202
|
* with no matching rule.
|
|
149
203
|
*/
|
|
150
|
-
declare const bamboocss: (options?: BambooVitePluginOptions) => Plugin;
|
|
204
|
+
declare const bamboocss: (options?: BambooVitePluginOptions) => Plugin[];
|
|
151
205
|
//#endregion
|
|
152
|
-
export { type BambooVitePluginOptions, type FoldOptions, type FoldResult, type FoldedCall, type RuntimeCss, type SkipReason, type SkippedCall, bamboocss, bamboocss as default, createRuntimeCss, foldSource };
|
|
206
|
+
export { type BambooCssPluginOptions, type BambooVitePluginOptions, type FoldOptions, type FoldResult, type FoldedCall, type RuntimeCss, type SkipReason, type SkippedCall, VIRTUAL_CSS_ID, bamboocss, bamboocss as default, bamboocssCss, createRuntimeCss, foldSource };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,8 +1,36 @@
|
|
|
1
1
|
import MagicString from "magic-string";
|
|
2
2
|
import { Context } from "@bamboocss/core";
|
|
3
|
-
import { Dict, ParserResultInterface } from "@bamboocss/types";
|
|
4
3
|
import { Plugin } from "vite";
|
|
4
|
+
import { Dict, ParserResultInterface } from "@bamboocss/types";
|
|
5
5
|
|
|
6
|
+
//#region src/css.d.ts
|
|
7
|
+
/**
|
|
8
|
+
* What a project imports to get the stylesheet.
|
|
9
|
+
*
|
|
10
|
+
* Spelled with a `.css` extension because that is how vite decides what a module is: the
|
|
11
|
+
* id is all it has for a module with no file behind it, so `virtual:bamboo` would be
|
|
12
|
+
* bundled as javascript and injected as a script.
|
|
13
|
+
*/
|
|
14
|
+
declare const VIRTUAL_CSS_ID = "virtual:bamboo.css";
|
|
15
|
+
interface BambooCssPluginOptions {
|
|
16
|
+
configPath?: string;
|
|
17
|
+
cwd?: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Serve bamboo's stylesheet as a virtual module, in dev and in build.
|
|
21
|
+
*
|
|
22
|
+
* This is the integration itself, not an optimisation: without it nothing emits css and
|
|
23
|
+
* the generated `styled-system` runtime names classes no rule exists for.
|
|
24
|
+
*
|
|
25
|
+
* A virtual module rather than a file written to disk, because vite already owns the two
|
|
26
|
+
* things a file would have to reimplement. In dev it injects css over the websocket and
|
|
27
|
+
* replaces it in place, so an edit repaints without reloading; in build it hashes the
|
|
28
|
+
* content into the asset graph and lets the bundler decide where it lands. Writing
|
|
29
|
+
* `styles.css` and asking the project to import it means the build reads a file the same
|
|
30
|
+
* process just wrote, which is a race on any watch rebuild.
|
|
31
|
+
*/
|
|
32
|
+
declare const bamboocssCss: (options?: BambooCssPluginOptions) => Plugin;
|
|
33
|
+
//#endregion
|
|
6
34
|
//#region src/runtime-css.d.ts
|
|
7
35
|
/**
|
|
8
36
|
* The generated runtime's `css`, rebuilt in-process from a resolved context.
|
|
@@ -101,9 +129,18 @@ interface BambooVitePluginOptions {
|
|
|
101
129
|
* Rewrite statically-resolvable `css()` and pattern calls into literal class
|
|
102
130
|
* strings, so they cost nothing at runtime.
|
|
103
131
|
*
|
|
104
|
-
*
|
|
132
|
+
* On by default, and build-only — it never runs in `vite dev`, where the parse would land
|
|
133
|
+
* on every hot update and a dev bundle gains nothing from pre-resolved calls.
|
|
105
134
|
*
|
|
106
|
-
*
|
|
135
|
+
* What it buys is per-call CPU, not bytes: the runtime still ships, because dropping it
|
|
136
|
+
* needs *every* call site in the graph to fold. Bundle size moves slightly against you —
|
|
137
|
+
* measured at -0.8% raw and +1.0% gzipped on `sandbox/runtime-perf`, since distinct class
|
|
138
|
+
* literals compress worse than the repeated `css({ … })` calls they replace. Set it to
|
|
139
|
+
* `false` if that trade is the wrong way round for you, or to keep builds faster: folding
|
|
140
|
+
* re-parses each module with `ts-morph`, roughly 0.3ms for a small component and 3ms for a
|
|
141
|
+
* 147-line file with 24 call sites.
|
|
142
|
+
*
|
|
143
|
+
* @default true
|
|
107
144
|
*/
|
|
108
145
|
transform?: boolean;
|
|
109
146
|
/**
|
|
@@ -135,18 +172,35 @@ interface BambooVitePluginOptions {
|
|
|
135
172
|
* @default true
|
|
136
173
|
*/
|
|
137
174
|
reportSummary?: boolean;
|
|
175
|
+
/**
|
|
176
|
+
* Fail the build when a `css()` or pattern call is left for the runtime.
|
|
177
|
+
*
|
|
178
|
+
* The fold's value is not the per-call CPU it saves — it is that a bundle where *every*
|
|
179
|
+
* such call folded no longer imports `styled-system/css` at all, and the engine behind it
|
|
180
|
+
* drops out. One survivor keeps the whole thing, so a coverage percentage cannot tell you
|
|
181
|
+
* whether you got the prize. This can.
|
|
182
|
+
*
|
|
183
|
+
* Deliberately silent about `cva`/`sva`. A `cva(...)` definition returns a function and can
|
|
184
|
+
* never collapse to a class string, so failing on it would make this unusable for anyone
|
|
185
|
+
* writing recipes — and recipes keep their own much smaller runtime by design. What this
|
|
186
|
+
* guarantees is narrower and checkable: nothing still calls `css()`.
|
|
187
|
+
*
|
|
188
|
+
* @default false
|
|
189
|
+
*/
|
|
190
|
+
strict?: boolean;
|
|
138
191
|
}
|
|
139
192
|
/**
|
|
140
193
|
* Vite integration for Bamboo CSS.
|
|
141
194
|
*
|
|
142
|
-
*
|
|
143
|
-
*
|
|
195
|
+
* Two plugins, because they do unrelated jobs on different schedules. The first emits the
|
|
196
|
+
* stylesheet as a virtual module and runs in dev and build alike — that is the integration,
|
|
197
|
+
* and nothing styles without it. The second is the optional build-time fold.
|
|
144
198
|
*
|
|
145
|
-
*
|
|
199
|
+
* The fold runs with `enforce: 'pre'` so it sees module source as close as possible to what
|
|
146
200
|
* the CSS extractor reads off disk. A plugin that rewrites style calls before bamboo
|
|
147
201
|
* sees them would otherwise make the two disagree, and a folded class could end up
|
|
148
202
|
* with no matching rule.
|
|
149
203
|
*/
|
|
150
|
-
declare const bamboocss: (options?: BambooVitePluginOptions) => Plugin;
|
|
204
|
+
declare const bamboocss: (options?: BambooVitePluginOptions) => Plugin[];
|
|
151
205
|
//#endregion
|
|
152
|
-
export { type BambooVitePluginOptions, type FoldOptions, type FoldResult, type FoldedCall, type RuntimeCss, type SkipReason, type SkippedCall, bamboocss, bamboocss as default, createRuntimeCss, foldSource };
|
|
206
|
+
export { type BambooCssPluginOptions, type BambooVitePluginOptions, type FoldOptions, type FoldResult, type FoldedCall, type RuntimeCss, type SkipReason, type SkippedCall, VIRTUAL_CSS_ID, bamboocss, bamboocss as default, bamboocssCss, createRuntimeCss, foldSource };
|
package/dist/index.mjs
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { Builder, loadConfigAndCreateContext } from "@bamboocss/node";
|
|
2
|
+
import { logger } from "@bamboocss/logger";
|
|
1
3
|
import { resolveTsPathPattern } from "@bamboocss/config/ts-path";
|
|
2
4
|
import { box, maybeBoxNode, unbox } from "@bamboocss/extractor";
|
|
3
5
|
import MagicString from "magic-string";
|
|
@@ -5,8 +7,90 @@ import { Node, SyntaxKind, VariableDeclarationKind } from "ts-morph";
|
|
|
5
7
|
import { Recipes } from "@bamboocss/core";
|
|
6
8
|
import { compact, createCssUncached, createMergeCss, getSlotCompoundVariant, memo, withoutSpace } from "@bamboocss/shared";
|
|
7
9
|
import { resolve } from "node:path";
|
|
8
|
-
|
|
9
|
-
|
|
10
|
+
//#region src/css.ts
|
|
11
|
+
/**
|
|
12
|
+
* What a project imports to get the stylesheet.
|
|
13
|
+
*
|
|
14
|
+
* Spelled with a `.css` extension because that is how vite decides what a module is: the
|
|
15
|
+
* id is all it has for a module with no file behind it, so `virtual:bamboo` would be
|
|
16
|
+
* bundled as javascript and injected as a script.
|
|
17
|
+
*/
|
|
18
|
+
const VIRTUAL_CSS_ID = "virtual:bamboo.css";
|
|
19
|
+
/**
|
|
20
|
+
* Rollup's convention for a module with no file: a leading NUL tells every other plugin
|
|
21
|
+
* not to try reading it off disk.
|
|
22
|
+
*/
|
|
23
|
+
const RESOLVED_ID = `\0${VIRTUAL_CSS_ID}`;
|
|
24
|
+
/**
|
|
25
|
+
* Serve bamboo's stylesheet as a virtual module, in dev and in build.
|
|
26
|
+
*
|
|
27
|
+
* This is the integration itself, not an optimisation: without it nothing emits css and
|
|
28
|
+
* the generated `styled-system` runtime names classes no rule exists for.
|
|
29
|
+
*
|
|
30
|
+
* A virtual module rather than a file written to disk, because vite already owns the two
|
|
31
|
+
* things a file would have to reimplement. In dev it injects css over the websocket and
|
|
32
|
+
* replaces it in place, so an edit repaints without reloading; in build it hashes the
|
|
33
|
+
* content into the asset graph and lets the bundler decide where it lands. Writing
|
|
34
|
+
* `styles.css` and asking the project to import it means the build reads a file the same
|
|
35
|
+
* process just wrote, which is a race on any watch rebuild.
|
|
36
|
+
*/
|
|
37
|
+
const bamboocssCss = (options = {}) => {
|
|
38
|
+
const { configPath, cwd } = options;
|
|
39
|
+
const builder = new Builder();
|
|
40
|
+
let server;
|
|
41
|
+
/**
|
|
42
|
+
* Serialised, because both `load` and the watcher can reach it and `Builder` keeps one
|
|
43
|
+
* context. Two overlapping passes would extract into the same encoder and emit the
|
|
44
|
+
* stylesheet twice over.
|
|
45
|
+
*/
|
|
46
|
+
let pending;
|
|
47
|
+
const build = async () => {
|
|
48
|
+
await builder.setup({
|
|
49
|
+
configPath,
|
|
50
|
+
cwd
|
|
51
|
+
});
|
|
52
|
+
await builder.emit();
|
|
53
|
+
builder.extract();
|
|
54
|
+
return builder.toCss({ layerParams: true });
|
|
55
|
+
};
|
|
56
|
+
const generate = () => {
|
|
57
|
+
pending = Promise.resolve(pending).catch(() => void 0).then(build);
|
|
58
|
+
return pending;
|
|
59
|
+
};
|
|
60
|
+
return {
|
|
61
|
+
name: "bamboocss:css",
|
|
62
|
+
resolveId(id) {
|
|
63
|
+
if (id === "virtual:bamboo.css") return RESOLVED_ID;
|
|
64
|
+
return null;
|
|
65
|
+
},
|
|
66
|
+
async load(id) {
|
|
67
|
+
if (id !== RESOLVED_ID) return null;
|
|
68
|
+
const css = await generate();
|
|
69
|
+
if (this.addWatchFile) for (const file of builder.context?.getFiles() ?? []) this.addWatchFile(builder.context.runtime.path.abs(builder.context.config.cwd, file));
|
|
70
|
+
return css;
|
|
71
|
+
},
|
|
72
|
+
configureServer(devServer) {
|
|
73
|
+
server = devServer;
|
|
74
|
+
const invalidate = (file) => {
|
|
75
|
+
const ctx = builder.context;
|
|
76
|
+
if (!ctx) return;
|
|
77
|
+
if (!ctx.getFiles().some((f) => ctx.runtime.path.abs(ctx.config.cwd, f) === file)) return;
|
|
78
|
+
const mod = server?.moduleGraph.getModuleById(RESOLVED_ID);
|
|
79
|
+
if (!mod) return;
|
|
80
|
+
server?.moduleGraph.invalidateModule(mod);
|
|
81
|
+
server?.ws.send({
|
|
82
|
+
type: "update",
|
|
83
|
+
updates: []
|
|
84
|
+
});
|
|
85
|
+
logger.debug("vite", `styles invalidated by ${file}`);
|
|
86
|
+
};
|
|
87
|
+
devServer.watcher.on("change", invalidate);
|
|
88
|
+
devServer.watcher.on("add", invalidate);
|
|
89
|
+
devServer.watcher.on("unlink", invalidate);
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
};
|
|
93
|
+
//#endregion
|
|
10
94
|
//#region src/fold-partial.ts
|
|
11
95
|
/**
|
|
12
96
|
* Statically resolvable means: every box in the tree carries a known value.
|
|
@@ -453,9 +537,6 @@ const planPartialFold = (argument, boxNode, styles, deps) => {
|
|
|
453
537
|
if (!partition) return void 0;
|
|
454
538
|
const className = deps.runtimeCss(partition.staticStyles);
|
|
455
539
|
if (!className && !partition.finite.length) return void 0;
|
|
456
|
-
if (deps.ctx.config.cssMode === "grouped") {
|
|
457
|
-
if ((className ? 1 : 0) + partition.finite.length + (partition.dynamicText.length ? 1 : 0) > 1) return void 0;
|
|
458
|
-
}
|
|
459
540
|
return {
|
|
460
541
|
className,
|
|
461
542
|
dynamicText: partition.dynamicText.length ? `{ ${partition.dynamicText.join(", ")} }` : void 0,
|
|
@@ -649,7 +730,6 @@ const ensureCxImport = (call, calleeRoot, isBambooCssModule, isGeneratedCssModul
|
|
|
649
730
|
//#region src/runtime-css.ts
|
|
650
731
|
/** The shape `createCss` and `createMergeCss` both take, derived from a resolved context. */
|
|
651
732
|
const createCssContext = (ctx) => ({
|
|
652
|
-
grouped: ctx.config.cssMode === "grouped",
|
|
653
733
|
hash: Boolean(ctx.hash.className),
|
|
654
734
|
conditions: {
|
|
655
735
|
shift: ctx.conditions.shift,
|
|
@@ -1475,6 +1555,23 @@ const isGeneratedOutput = (filePath, ctx) => {
|
|
|
1475
1555
|
const file = slashed(filePath);
|
|
1476
1556
|
return file === root || file.startsWith(`${root}/`);
|
|
1477
1557
|
};
|
|
1558
|
+
/**
|
|
1559
|
+
* The skip reasons that leave a `css()`-family call in the output.
|
|
1560
|
+
*
|
|
1561
|
+
* `overlapping` is handled by the enclosing fold, and `not-imported` is somebody else's
|
|
1562
|
+
* function of the same name — neither leaves a call of ours. `not-foldable` is a `cva`/`sva`
|
|
1563
|
+
* definition, which keeps the recipe runtime rather than the css engine; see `strict`.
|
|
1564
|
+
*/
|
|
1565
|
+
const SURVIVES_TO_RUNTIME = new Set([
|
|
1566
|
+
"dynamic",
|
|
1567
|
+
"raw-call",
|
|
1568
|
+
"unsupported-kind",
|
|
1569
|
+
"no-call-expression",
|
|
1570
|
+
"empty",
|
|
1571
|
+
"unresolved-token"
|
|
1572
|
+
]);
|
|
1573
|
+
/** 1-indexed line of a source offset, for an error a user can navigate to. */
|
|
1574
|
+
const lineAt = (code, offset) => code.slice(0, offset).split("\n").length;
|
|
1478
1575
|
const formatSkipped = (id, skipped) => {
|
|
1479
1576
|
const counts = /* @__PURE__ */ new Map();
|
|
1480
1577
|
for (const entry of skipped) counts.set(entry.reason, (counts.get(entry.reason) ?? 0) + 1);
|
|
@@ -1483,16 +1580,17 @@ const formatSkipped = (id, skipped) => {
|
|
|
1483
1580
|
/**
|
|
1484
1581
|
* Vite integration for Bamboo CSS.
|
|
1485
1582
|
*
|
|
1486
|
-
*
|
|
1487
|
-
*
|
|
1583
|
+
* Two plugins, because they do unrelated jobs on different schedules. The first emits the
|
|
1584
|
+
* stylesheet as a virtual module and runs in dev and build alike — that is the integration,
|
|
1585
|
+
* and nothing styles without it. The second is the optional build-time fold.
|
|
1488
1586
|
*
|
|
1489
|
-
*
|
|
1587
|
+
* The fold runs with `enforce: 'pre'` so it sees module source as close as possible to what
|
|
1490
1588
|
* the CSS extractor reads off disk. A plugin that rewrites style calls before bamboo
|
|
1491
1589
|
* sees them would otherwise make the two disagree, and a folded class could end up
|
|
1492
1590
|
* with no matching rule.
|
|
1493
1591
|
*/
|
|
1494
1592
|
const bamboocss = (options = {}) => {
|
|
1495
|
-
const { transform =
|
|
1593
|
+
const { transform = true, partial, configPath, cwd, reportSkipped = false, reportSummary = true, strict = false } = options;
|
|
1496
1594
|
/** Totals across the build, for the summary. */
|
|
1497
1595
|
const totals = {
|
|
1498
1596
|
folded: 0,
|
|
@@ -1500,6 +1598,8 @@ const bamboocss = (options = {}) => {
|
|
|
1500
1598
|
filesWithFolds: 0,
|
|
1501
1599
|
skipped: /* @__PURE__ */ new Map()
|
|
1502
1600
|
};
|
|
1601
|
+
/** Under `strict`, every call that would still reach the runtime. */
|
|
1602
|
+
const survivors = [];
|
|
1503
1603
|
let ctx;
|
|
1504
1604
|
let runtimeCss;
|
|
1505
1605
|
let setup;
|
|
@@ -1513,8 +1613,11 @@ const bamboocss = (options = {}) => {
|
|
|
1513
1613
|
});
|
|
1514
1614
|
await setup;
|
|
1515
1615
|
};
|
|
1516
|
-
return {
|
|
1517
|
-
|
|
1616
|
+
return [bamboocssCss({
|
|
1617
|
+
configPath,
|
|
1618
|
+
cwd
|
|
1619
|
+
}), {
|
|
1620
|
+
name: "bamboocss:fold",
|
|
1518
1621
|
enforce: "pre",
|
|
1519
1622
|
apply: "build",
|
|
1520
1623
|
async buildStart() {
|
|
@@ -1523,6 +1626,7 @@ const bamboocss = (options = {}) => {
|
|
|
1523
1626
|
totals.files = 0;
|
|
1524
1627
|
totals.filesWithFolds = 0;
|
|
1525
1628
|
totals.skipped.clear();
|
|
1629
|
+
survivors.length = 0;
|
|
1526
1630
|
await ensureContext();
|
|
1527
1631
|
},
|
|
1528
1632
|
/**
|
|
@@ -1584,6 +1688,23 @@ const bamboocss = (options = {}) => {
|
|
|
1584
1688
|
totals.folded += result.folded.length;
|
|
1585
1689
|
if (result.folded.length) totals.filesWithFolds++;
|
|
1586
1690
|
for (const entry of result.skipped) totals.skipped.set(entry.reason, (totals.skipped.get(entry.reason) ?? 0) + 1);
|
|
1691
|
+
if (strict) {
|
|
1692
|
+
for (const entry of result.skipped) {
|
|
1693
|
+
if (!SURVIVES_TO_RUNTIME.has(entry.reason)) continue;
|
|
1694
|
+
survivors.push({
|
|
1695
|
+
file: filePath,
|
|
1696
|
+
line: lineAt(code, entry.start),
|
|
1697
|
+
name: entry.name,
|
|
1698
|
+
reason: entry.reason
|
|
1699
|
+
});
|
|
1700
|
+
}
|
|
1701
|
+
if (result.code.includes("cssLeaf(")) survivors.push({
|
|
1702
|
+
file: filePath,
|
|
1703
|
+
line: lineAt(result.code, result.code.indexOf("cssLeaf(")),
|
|
1704
|
+
name: "cssLeaf",
|
|
1705
|
+
reason: "lowered-leaf"
|
|
1706
|
+
});
|
|
1707
|
+
}
|
|
1587
1708
|
if (reportSkipped && result.skipped.length) logger.info("vite:transform", formatSkipped(filePath, result.skipped));
|
|
1588
1709
|
for (const dependency of result.dependencies) this.addWatchFile?.(dependency);
|
|
1589
1710
|
if (!result.folded.length) return null;
|
|
@@ -1594,6 +1715,16 @@ const bamboocss = (options = {}) => {
|
|
|
1594
1715
|
};
|
|
1595
1716
|
},
|
|
1596
1717
|
buildEnd() {
|
|
1718
|
+
if (strict && survivors.length) {
|
|
1719
|
+
const byFile = /* @__PURE__ */ new Map();
|
|
1720
|
+
for (const entry of survivors) {
|
|
1721
|
+
const list = byFile.get(entry.file) ?? [];
|
|
1722
|
+
list.push(entry);
|
|
1723
|
+
byFile.set(entry.file, list);
|
|
1724
|
+
}
|
|
1725
|
+
const detail = Array.from(byFile.entries()).map(([file, entries]) => [` ${file}`, ...entries.map((e) => ` ${e.line}: ${e.name}() — ${e.reason}`)].join("\n")).join("\n");
|
|
1726
|
+
throw new Error(`bamboocss: ${survivors.length} call(s) could not be folded, and \`strict\` is on.\n\n${detail}\n\nEach one keeps \`styled-system/css\` in the bundle, so the engine cannot be dropped however many other calls folded. Make the values static, move the variation into a \`cva\` variant, or generate them with \`staticCss\` — or set \`strict: false\` to accept the runtime.`);
|
|
1727
|
+
}
|
|
1597
1728
|
if (!transform || !reportSummary) return;
|
|
1598
1729
|
const declined = Array.from(totals.skipped.values()).reduce((sum, count) => sum + count, 0);
|
|
1599
1730
|
const total = totals.folded + declined;
|
|
@@ -1602,7 +1733,7 @@ const bamboocss = (options = {}) => {
|
|
|
1602
1733
|
const reasons = Array.from(totals.skipped.entries()).sort((a, b) => b[1] - a[1]).map(([reason, count]) => `${reason}=${count}`).join(" ");
|
|
1603
1734
|
logger.info("vite:transform", `Folded ${totals.folded}/${total} (${share}%) across ${totals.filesWithFolds}/${totals.files} files` + (reasons ? ` — declined: ${reasons}` : ""));
|
|
1604
1735
|
}
|
|
1605
|
-
};
|
|
1736
|
+
}];
|
|
1606
1737
|
};
|
|
1607
1738
|
//#endregion
|
|
1608
|
-
export { bamboocss, bamboocss as default, createRuntimeCss, foldSource };
|
|
1739
|
+
export { VIRTUAL_CSS_ID, bamboocss, bamboocss as default, bamboocssCss, createRuntimeCss, foldSource };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bamboocss/vite",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.22.0",
|
|
4
4
|
"description": "Vite integration for Bamboo CSS",
|
|
5
5
|
"homepage": "https://bamboocss.com",
|
|
6
6
|
"license": "MIT",
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
"directory": "packages/vite"
|
|
12
12
|
},
|
|
13
13
|
"files": [
|
|
14
|
+
"client.d.ts",
|
|
14
15
|
"dist"
|
|
15
16
|
],
|
|
16
17
|
"sideEffects": false,
|
|
@@ -27,7 +28,8 @@
|
|
|
27
28
|
"default": "./dist/index.mjs"
|
|
28
29
|
}
|
|
29
30
|
},
|
|
30
|
-
"./package.json": "./package.json"
|
|
31
|
+
"./package.json": "./package.json",
|
|
32
|
+
"./client": "./client.d.ts"
|
|
31
33
|
},
|
|
32
34
|
"publishConfig": {
|
|
33
35
|
"access": "public"
|
|
@@ -35,18 +37,18 @@
|
|
|
35
37
|
"dependencies": {
|
|
36
38
|
"magic-string": "0.30.21",
|
|
37
39
|
"ts-morph": "28.0.0",
|
|
38
|
-
"@bamboocss/
|
|
39
|
-
"@bamboocss/
|
|
40
|
-
"@bamboocss/
|
|
41
|
-
"@bamboocss/
|
|
42
|
-
"@bamboocss/node": "1.
|
|
43
|
-
"@bamboocss/shared": "1.
|
|
44
|
-
"@bamboocss/types": "1.
|
|
40
|
+
"@bamboocss/config": "1.22.0",
|
|
41
|
+
"@bamboocss/core": "1.22.0",
|
|
42
|
+
"@bamboocss/logger": "1.22.0",
|
|
43
|
+
"@bamboocss/extractor": "1.22.0",
|
|
44
|
+
"@bamboocss/node": "1.22.0",
|
|
45
|
+
"@bamboocss/shared": "1.22.0",
|
|
46
|
+
"@bamboocss/types": "1.22.0"
|
|
45
47
|
},
|
|
46
48
|
"devDependencies": {
|
|
47
49
|
"@jridgewell/trace-mapping": "^0.3.31",
|
|
48
50
|
"vite": "7.2.6",
|
|
49
|
-
"@bamboocss/fixture": "1.
|
|
51
|
+
"@bamboocss/fixture": "1.22.0"
|
|
50
52
|
},
|
|
51
53
|
"peerDependencies": {
|
|
52
54
|
"vite": ">=5"
|