@bamboocss/vite 1.47.0 → 1.48.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.cjs +321 -97
- package/dist/index.d.cts +0 -1
- package/dist/index.d.mts +2 -1
- package/dist/index.mjs +321 -97
- package/package.json +9 -9
package/dist/index.cjs
CHANGED
|
@@ -48,24 +48,121 @@ const loadCssOutputModule = createLazyCssOutputModule();
|
|
|
48
48
|
const createLazyFoldModule = (loadFold = () => Promise.resolve().then(() => require("./fold-module.cjs"))) => createRetryableLazy(loadFold);
|
|
49
49
|
/** One process-wide fold-module load shared by every plugin instance and Vite environment. */
|
|
50
50
|
const loadFoldModule = createLazyFoldModule();
|
|
51
|
-
/**
|
|
51
|
+
/**
|
|
52
|
+
* The one Builder a run compiles against, created only when a hook first needs it.
|
|
53
|
+
*
|
|
54
|
+
* Per host rather than per plugin instance: the compiler and the stylesheet share it now.
|
|
55
|
+
* @see `createCompilationHost`
|
|
56
|
+
*/
|
|
52
57
|
const createLazyBuilder = (loadNode = loadNodeModule) => createRetryableLazy(async () => {
|
|
53
58
|
const { Builder } = await loadNode();
|
|
54
59
|
return new Builder();
|
|
55
60
|
});
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
const
|
|
60
|
-
const
|
|
61
|
+
//#endregion
|
|
62
|
+
//#region src/compilation-host.ts
|
|
63
|
+
const createCompilationHost = (options = {}) => {
|
|
64
|
+
const { configPath, cwd } = options;
|
|
65
|
+
const loadBuilder = options.loadBuilder ?? createLazyBuilder();
|
|
66
|
+
let command = "build";
|
|
67
|
+
let builder;
|
|
68
|
+
let generation;
|
|
69
|
+
let nextGenerationId = 0;
|
|
70
|
+
/**
|
|
71
|
+
* The setup covering the pass currently open.
|
|
72
|
+
*
|
|
73
|
+
* A cold start reaches this twice — the compiler's `pre` `buildStart`, then the CSS
|
|
74
|
+
* plugin's — for one instant in which nothing can have changed on disk. Sharing one attempt
|
|
75
|
+
* across both is what keeps a project from loading and evaluating its config twice per
|
|
76
|
+
* build. Cleared once a stylesheet pass consumes it, and on any source mutation, so no
|
|
77
|
+
* later pass can be answered by a setup taken before an edit.
|
|
78
|
+
*/
|
|
79
|
+
let openSetup;
|
|
80
|
+
let openSetupStale = false;
|
|
81
|
+
let cssPass;
|
|
82
|
+
const settled = async (attempt) => {
|
|
83
|
+
try {
|
|
84
|
+
await attempt;
|
|
85
|
+
} catch {}
|
|
86
|
+
};
|
|
87
|
+
const publish = () => {
|
|
88
|
+
const context = builder.getContextOrThrow();
|
|
89
|
+
if (generation?.context !== context) generation = {
|
|
90
|
+
id: ++nextGenerationId,
|
|
91
|
+
context,
|
|
92
|
+
encoder: context.encoder.clone()
|
|
93
|
+
};
|
|
94
|
+
return generation;
|
|
95
|
+
};
|
|
96
|
+
const runSetup = async () => {
|
|
97
|
+
builder ??= await loadBuilder();
|
|
98
|
+
await builder.setup({
|
|
99
|
+
configPath,
|
|
100
|
+
cwd,
|
|
101
|
+
dev: command === "serve"
|
|
102
|
+
});
|
|
103
|
+
return publish();
|
|
104
|
+
};
|
|
105
|
+
/**
|
|
106
|
+
* The setup covering the pass currently open, started at most once.
|
|
107
|
+
*
|
|
108
|
+
* Started through a resolved promise, so a synchronous throw becomes the same
|
|
109
|
+
* rejected-attempt contract a failed module load has and a later hook can retry it. A
|
|
110
|
+
* source mutation observed while one is in flight does not cancel it — two overlapping
|
|
111
|
+
* `Builder.setup` calls would interleave their change detection — it queues a fresh one
|
|
112
|
+
* behind it.
|
|
113
|
+
*/
|
|
114
|
+
const setupOnce = () => {
|
|
115
|
+
const previous = openSetup;
|
|
116
|
+
if (previous && !openSetupStale) return previous;
|
|
117
|
+
openSetupStale = false;
|
|
118
|
+
const attempt = previous ? settled(previous).then(runSetup) : Promise.resolve().then(runSetup);
|
|
119
|
+
openSetup = attempt;
|
|
120
|
+
attempt.catch(() => {
|
|
121
|
+
if (openSetup === attempt) openSetup = void 0;
|
|
122
|
+
});
|
|
123
|
+
return attempt;
|
|
124
|
+
};
|
|
61
125
|
return {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
126
|
+
setCommand(next) {
|
|
127
|
+
command = next;
|
|
128
|
+
},
|
|
129
|
+
current: () => generation,
|
|
130
|
+
async ensureGeneration() {
|
|
131
|
+
if (cssPass) await settled(cssPass);
|
|
132
|
+
if (generation) return Promise.resolve(generation);
|
|
133
|
+
return setupOnce();
|
|
134
|
+
},
|
|
135
|
+
isCssPassActive: () => cssPass !== void 0,
|
|
136
|
+
async runCssPass(run) {
|
|
137
|
+
while (cssPass) await settled(cssPass);
|
|
138
|
+
let release;
|
|
139
|
+
cssPass = new Promise((resolve) => {
|
|
140
|
+
release = resolve;
|
|
141
|
+
});
|
|
142
|
+
try {
|
|
143
|
+
const passGeneration = await setupOnce();
|
|
144
|
+
return await run(builder, passGeneration);
|
|
145
|
+
} finally {
|
|
146
|
+
openSetup = void 0;
|
|
147
|
+
openSetupStale = false;
|
|
148
|
+
cssPass = void 0;
|
|
149
|
+
release();
|
|
150
|
+
}
|
|
151
|
+
},
|
|
152
|
+
async runCompilerWork(run) {
|
|
153
|
+
while (cssPass) await settled(cssPass);
|
|
154
|
+
return run();
|
|
155
|
+
},
|
|
156
|
+
reloadSource(filePath) {
|
|
157
|
+
openSetupStale = true;
|
|
158
|
+
builder?.reloadSource(filePath);
|
|
159
|
+
},
|
|
160
|
+
removeSource(filePath) {
|
|
161
|
+
openSetupStale = true;
|
|
162
|
+
builder?.removeSource(filePath);
|
|
163
|
+
}
|
|
67
164
|
};
|
|
68
|
-
}
|
|
165
|
+
};
|
|
69
166
|
//#endregion
|
|
70
167
|
//#region src/static-session.ts
|
|
71
168
|
const createStaticCompilationSession = () => {
|
|
@@ -184,14 +281,11 @@ const asError = (error, context) => error instanceof Error ? error : new Error(`
|
|
|
184
281
|
* process just wrote, which is a race on any watch rebuild.
|
|
185
282
|
*/
|
|
186
283
|
const bamboocssCss = (options) => {
|
|
187
|
-
const { configPath, cwd, loadCssOutput = loadCssOutputModule, session,
|
|
284
|
+
const { configPath, cwd, loadCssOutput = loadCssOutputModule, session, host = createCompilationHost({
|
|
285
|
+
configPath,
|
|
286
|
+
cwd
|
|
287
|
+
}), pruneCss = true } = options;
|
|
188
288
|
let builder;
|
|
189
|
-
const loadBuilder = createLazyBuilder();
|
|
190
|
-
const ensureBuilder = async () => {
|
|
191
|
-
const loaded = await loadBuilder();
|
|
192
|
-
builder = loaded;
|
|
193
|
-
return loaded;
|
|
194
|
-
};
|
|
195
289
|
let server;
|
|
196
290
|
let command = "build";
|
|
197
291
|
/** The run's own `build` options, for a bundler with no per-environment config. */
|
|
@@ -226,34 +320,36 @@ const bamboocssCss = (options) => {
|
|
|
226
320
|
let changeGeneration = 0;
|
|
227
321
|
let pendingGeneration = -1;
|
|
228
322
|
let servedCss;
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
323
|
+
/**
|
|
324
|
+
* Held by the host for its whole length, rather than only around each mutation.
|
|
325
|
+
*
|
|
326
|
+
* Extraction fills the encoder this sheet is emitted from and `toCss` reads it back, with a
|
|
327
|
+
* deliberate macrotask between them. The compiler shares the AST both halves run against,
|
|
328
|
+
* so a transform folding a module in that window would re-prepare a source the extraction
|
|
329
|
+
* pass has already read and `toCss` has not finished reporting on. The host makes compiler
|
|
330
|
+
* work wait instead; a fold is a few milliseconds and this is the one place correctness
|
|
331
|
+
* depends on it.
|
|
332
|
+
*/
|
|
333
|
+
const build = () => host.runCssPass(async (activeBuilder) => {
|
|
334
|
+
builder = activeBuilder;
|
|
335
|
+
await activeBuilder.emit();
|
|
336
|
+
activeBuilder.extract();
|
|
238
337
|
await new Promise((settle) => setImmediate(settle));
|
|
239
|
-
if (
|
|
240
|
-
session.utilityLayer =
|
|
338
|
+
if (activeBuilder.context) {
|
|
339
|
+
session.utilityLayer = activeBuilder.context.config.layers?.utilities ?? "utilities";
|
|
241
340
|
session.extractedFiles.clear();
|
|
242
341
|
for (const file of extractedSourceFiles()) session.extractedFiles.add(file);
|
|
243
342
|
}
|
|
244
343
|
let graphAtomHashes;
|
|
245
|
-
if (
|
|
246
|
-
|
|
247
|
-
graphAtomHashes = new Set(
|
|
344
|
+
if (activeBuilder.context) {
|
|
345
|
+
activeBuilder.context.encoder.atomizeObservedRecipes();
|
|
346
|
+
graphAtomHashes = new Set(activeBuilder.context.encoder.atomic);
|
|
248
347
|
}
|
|
249
|
-
const css =
|
|
250
|
-
layerParams: true,
|
|
251
|
-
includeRecipes: false
|
|
252
|
-
});
|
|
348
|
+
const css = activeBuilder.toCss({ layerParams: true });
|
|
253
349
|
session.prunableClasses.clear();
|
|
254
350
|
session.viewTransitionClasses.clear();
|
|
255
|
-
if (graphAtomHashes &&
|
|
256
|
-
const decoder =
|
|
351
|
+
if (graphAtomHashes && activeBuilder.context) {
|
|
352
|
+
const decoder = activeBuilder.context.decoder.collect(activeBuilder.context.encoder);
|
|
257
353
|
for (const atom of decoder.atomic) if (graphAtomHashes.has(atom.hash)) session.prunableClasses.add(atom.className);
|
|
258
354
|
for (const transition of decoder.view_transitions) {
|
|
259
355
|
session.viewTransitionClasses.add(transition.className);
|
|
@@ -261,7 +357,7 @@ const bamboocssCss = (options) => {
|
|
|
261
357
|
}
|
|
262
358
|
}
|
|
263
359
|
return css;
|
|
264
|
-
};
|
|
360
|
+
});
|
|
265
361
|
const generate = () => {
|
|
266
362
|
if (command === "serve" && pending && pendingGeneration === changeGeneration) return pending;
|
|
267
363
|
pendingGeneration = changeGeneration;
|
|
@@ -341,6 +437,7 @@ const bamboocssCss = (options) => {
|
|
|
341
437
|
sharedDuringBuild: true,
|
|
342
438
|
async configResolved(config) {
|
|
343
439
|
command = config.command;
|
|
440
|
+
host.setCommand(config.command);
|
|
344
441
|
session.sourcemap = config.build.sourcemap;
|
|
345
442
|
ssrBuildOptions = {
|
|
346
443
|
ssr: config.build.ssr,
|
|
@@ -354,11 +451,12 @@ const bamboocssCss = (options) => {
|
|
|
354
451
|
* edited all afternoon. Nothing watched it: `watch` is the CLI's own watcher, and a
|
|
355
452
|
* project running `vite dev` never reaches it.
|
|
356
453
|
*
|
|
357
|
-
* A restart rather than re-emitting the stylesheet
|
|
358
|
-
*
|
|
359
|
-
*
|
|
360
|
-
*
|
|
361
|
-
*
|
|
454
|
+
* A restart rather than re-emitting the stylesheet. The two plugins share one context now,
|
|
455
|
+
* and the compiler re-derives everything it holds when `Builder.setup` replaces it — so the
|
|
456
|
+
* half-updated state this used to prevent, with the compiler naming classes from the old
|
|
457
|
+
* config against a sheet emitted from the new one, can no longer happen. What a restart
|
|
458
|
+
* still buys is the rest of the server: a changed `outdir`, a preset that adds an entry
|
|
459
|
+
* point, and every module Vite has already transformed against the previous config.
|
|
362
460
|
*
|
|
363
461
|
* Through Vite's own list rather than a watcher of ours. Vite adds these paths to the
|
|
364
462
|
* files it watches, which is what reaches a config *outside* `root` — a monorepo with one
|
|
@@ -628,6 +726,22 @@ const compilerParsePath = (id, code) => {
|
|
|
628
726
|
return `${filePath}.__bamboo__.ts`;
|
|
629
727
|
};
|
|
630
728
|
/**
|
|
729
|
+
* Where to park a transform's text when it is not what the shared Project holds for the file.
|
|
730
|
+
*
|
|
731
|
+
* The compiler folds the bundler's view of a module — after every `enforce: 'pre'` plugin
|
|
732
|
+
* before it, and after Vite's own load. The stylesheet pass reads the same file off disk
|
|
733
|
+
* through the same ts-morph Project. When the two texts differ and the compiler writes its
|
|
734
|
+
* own under the file's path, that transform silently becomes the canonical source for the
|
|
735
|
+
* next extraction pass: the CSS would then be generated from a bundler artifact rather than
|
|
736
|
+
* from the checkout. Under a sibling path both readings exist and neither overwrites the
|
|
737
|
+
* other, which is the same reason `compilerParsePath` already does this for SFC submodules.
|
|
738
|
+
*
|
|
739
|
+
* The extension carries JSX-ness across, since it is what ts-morph keys its script kind on:
|
|
740
|
+
* anything but an unambiguously non-JSX `.ts`/`.mts`/`.cts` is parsed as `.tsx`, so a `<div>`
|
|
741
|
+
* in a `.js` file still parses and a `<T>value` assertion in a `.ts` file still means a cast.
|
|
742
|
+
*/
|
|
743
|
+
const auxiliaryParsePath = (filePath) => `${filePath}.__bamboo__.${/\.[cm]?ts$/i.test(filePath) ? "ts" : "tsx"}`;
|
|
744
|
+
/**
|
|
631
745
|
* Is this file part of the generated `styled-system` rather than the user's source?
|
|
632
746
|
*
|
|
633
747
|
* Resolved to a path and compared as a prefix, rather than by looking for the outdir's
|
|
@@ -682,6 +796,17 @@ const bamboocss = (options = {}) => {
|
|
|
682
796
|
if (maxRecipeStates !== void 0 && (!Number.isSafeInteger(maxRecipeStates) || maxRecipeStates < 1)) throw new Error("bamboocss: `maxRecipeStates` must be a positive safe integer.");
|
|
683
797
|
if ("renameCssAsset" in options) throw new Error("bamboocss: `renameCssAsset` has been replaced by `pruneCss`. Use `pruneCss: false` for what `renameCssAsset: false` did — it always disabled the pruning as well, since pruned bytes under the unpruned sheet's name is what lets a CDN serve a stale stylesheet. The new name says which of the two it is really about.");
|
|
684
798
|
const staticSession = createStaticCompilationSession();
|
|
799
|
+
/**
|
|
800
|
+
* One Builder, one resolved config, one context and one ts-morph project for the run.
|
|
801
|
+
*
|
|
802
|
+
* Created here rather than by either plugin because both need it and neither may own it:
|
|
803
|
+
* the compiler used to load a second config of its own, which is why a token edit could
|
|
804
|
+
* leave it naming classes from the old one against a sheet emitted from the new one.
|
|
805
|
+
*/
|
|
806
|
+
const host = createCompilationHost({
|
|
807
|
+
configPath,
|
|
808
|
+
cwd
|
|
809
|
+
});
|
|
685
810
|
const transformArtifactIntegrityKey = (0, node_crypto.randomBytes)(32);
|
|
686
811
|
const serializeTransformArtifact = (environment, artifact) => JSON.stringify([
|
|
687
812
|
TRANSFORM_META_KEY,
|
|
@@ -1326,6 +1451,8 @@ const bamboocss = (options = {}) => {
|
|
|
1326
1451
|
const foldOutputUnchanged = (state, dependent, changedFile) => {
|
|
1327
1452
|
const memoized = state.unchangedFolds.get(dependent);
|
|
1328
1453
|
if (memoized !== void 0) return memoized;
|
|
1454
|
+
if (host.isCssPassActive()) return false;
|
|
1455
|
+
if (!compilerStateIsCurrent()) return false;
|
|
1329
1456
|
const unchanged = state.changedRun < CHANGED_RUN_LIMIT && refoldMatchesSignature(state, dependent, changedFile);
|
|
1330
1457
|
state.changedRun = unchanged ? 0 : state.changedRun + 1;
|
|
1331
1458
|
state.unchangedFolds.set(dependent, unchanged);
|
|
@@ -1337,7 +1464,8 @@ const bamboocss = (options = {}) => {
|
|
|
1337
1464
|
try {
|
|
1338
1465
|
const retained = state.foldInputsByModule.get(dependent);
|
|
1339
1466
|
const code = retained?.input === signature.input ? retained.code : (0, node_fs.readFileSync)(signature.path, "utf8");
|
|
1340
|
-
const
|
|
1467
|
+
const requestedParsePath = retained?.input === signature.input ? retained.parsePath : signature.path;
|
|
1468
|
+
const parsePath = compilerSourcePath(signature.path, requestedParsePath, code);
|
|
1341
1469
|
const inputDigest = digest(code);
|
|
1342
1470
|
if (inputDigest !== signature.input) return false;
|
|
1343
1471
|
/**
|
|
@@ -1354,7 +1482,7 @@ const bamboocss = (options = {}) => {
|
|
|
1354
1482
|
*/
|
|
1355
1483
|
const reads = state.exportReadsByModule.get(dependent);
|
|
1356
1484
|
if (reads?.length && verifyExportReadsImpl) {
|
|
1357
|
-
const { verdict, crossings } = verifyExportReadsImpl(ctx,
|
|
1485
|
+
const { verdict, crossings } = verifyExportReadsImpl(ctx, parseForCompiler, reads, normalizeFsPath(changedFile), verifyDigestMemo);
|
|
1358
1486
|
if (verdict === "unchanged") {
|
|
1359
1487
|
recordFoldDependencies(state, dependent, signature.path, [...state.dependenciesByModule.get(dependent) ?? [], ...crossings]);
|
|
1360
1488
|
return true;
|
|
@@ -1369,8 +1497,9 @@ const bamboocss = (options = {}) => {
|
|
|
1369
1497
|
raw = memoized.result;
|
|
1370
1498
|
parserDependencies = memoized.parserDependencies;
|
|
1371
1499
|
} else {
|
|
1372
|
-
const sourceFile =
|
|
1373
|
-
|
|
1500
|
+
const sourceFile = addCompilerSource(signature.path, parsePath, code);
|
|
1501
|
+
if (!sourceFile) return false;
|
|
1502
|
+
const parserResult = parseForCompiler(parsePath, requestedParsePath === signature.path ? signature.path : parsePath);
|
|
1374
1503
|
if (!parserResult) return false;
|
|
1375
1504
|
raw = foldSourceImpl({
|
|
1376
1505
|
ctx,
|
|
@@ -1380,7 +1509,7 @@ const bamboocss = (options = {}) => {
|
|
|
1380
1509
|
runtimeCss,
|
|
1381
1510
|
styleCompiler,
|
|
1382
1511
|
maxRecipeStates,
|
|
1383
|
-
parseModule:
|
|
1512
|
+
parseModule: parseForCompiler,
|
|
1384
1513
|
recipeConfigCache: state.recipeConfigCache,
|
|
1385
1514
|
reportSurvivors: false,
|
|
1386
1515
|
sourceFile
|
|
@@ -1520,6 +1649,8 @@ const bamboocss = (options = {}) => {
|
|
|
1520
1649
|
return [...modules, ...added];
|
|
1521
1650
|
};
|
|
1522
1651
|
let ctx;
|
|
1652
|
+
/** The compiler's private parse sink for `ctx`. @see `CompilationGeneration.encoder` */
|
|
1653
|
+
let parseEncoder;
|
|
1523
1654
|
let foldSourceImpl;
|
|
1524
1655
|
let verifyExportReadsImpl;
|
|
1525
1656
|
let runtimeCss;
|
|
@@ -1559,25 +1690,97 @@ const bamboocss = (options = {}) => {
|
|
|
1559
1690
|
dependencies: expanded
|
|
1560
1691
|
};
|
|
1561
1692
|
};
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1693
|
+
/** Which context the published derivations below were built from. */
|
|
1694
|
+
let derivedGeneration = -1;
|
|
1695
|
+
/** Compiler-only sibling ASTs retained for each physical module. */
|
|
1696
|
+
const auxiliarySourcesByFile = /* @__PURE__ */ new Map();
|
|
1697
|
+
/**
|
|
1698
|
+
* Whether the compiler state below still describes the context the host is on.
|
|
1699
|
+
*
|
|
1700
|
+
* Only `ensureCompilerState` re-derives, and only an awaited hook may call it — so the two
|
|
1701
|
+
* synchronous entry points, the speculative prefold and the unchanged-dependent check, can
|
|
1702
|
+
* be reached after a stylesheet pass has published a config reload they have not seen. Both
|
|
1703
|
+
* decline rather than fold against a runtime `css` from the previous config.
|
|
1704
|
+
*/
|
|
1705
|
+
const compilerStateIsCurrent = () => {
|
|
1706
|
+
const current = host.current();
|
|
1707
|
+
return current !== void 0 && current.id === derivedGeneration;
|
|
1708
|
+
};
|
|
1571
1709
|
const ensureContext = async () => {
|
|
1572
|
-
ctx = await
|
|
1710
|
+
ctx = (await host.ensureGeneration()).context;
|
|
1573
1711
|
};
|
|
1712
|
+
/**
|
|
1713
|
+
* Load the fold chunk and derive everything that depends on the resolved context.
|
|
1714
|
+
*
|
|
1715
|
+
* Keyed on context *identity* rather than derived once. `Builder.setup` replaces its context
|
|
1716
|
+
* on a config reload, and the runtime `css`, the style-set compiler and the parse sink are
|
|
1717
|
+
* all closures over the previous one — a stale `runtimeCss` names classes from the old
|
|
1718
|
+
* config while the stylesheet is emitted from the new one, and nothing downstream can see
|
|
1719
|
+
* the difference. Re-derivation is cheap; both factories are a handful of bound methods.
|
|
1720
|
+
*
|
|
1721
|
+
* Published as a set, and only once every part of the attempt has succeeded, so a failed
|
|
1722
|
+
* chunk load leaves no half-compiler visible to HMR.
|
|
1723
|
+
*/
|
|
1574
1724
|
const ensureCompilerState = async () => {
|
|
1575
|
-
const
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1725
|
+
const [initialGeneration, fold] = await Promise.all([host.ensureGeneration(), loadFoldModule()]);
|
|
1726
|
+
const currentGeneration = await host.ensureGeneration();
|
|
1727
|
+
const generation = currentGeneration.id === initialGeneration.id ? initialGeneration : currentGeneration;
|
|
1728
|
+
if (derivedGeneration === generation.id && foldSourceImpl) {
|
|
1729
|
+
ctx = generation.context;
|
|
1730
|
+
return;
|
|
1731
|
+
}
|
|
1732
|
+
const derivedRuntimeCss = fold.createRuntimeCss(generation.context);
|
|
1733
|
+
const derivedStyleCompiler = fold.createStaticStyleSetCompiler(generation.context, derivedRuntimeCss);
|
|
1734
|
+
ctx = generation.context;
|
|
1735
|
+
parseEncoder = generation.encoder;
|
|
1736
|
+
foldSourceImpl = fold.foldSource;
|
|
1737
|
+
verifyExportReadsImpl = fold.verifyExportReads;
|
|
1738
|
+
runtimeCss = derivedRuntimeCss;
|
|
1739
|
+
styleCompiler = derivedStyleCompiler;
|
|
1740
|
+
derivedGeneration = generation.id;
|
|
1741
|
+
auxiliarySourcesByFile.clear();
|
|
1742
|
+
};
|
|
1743
|
+
/**
|
|
1744
|
+
* Parse a module for the compiler, never for the stylesheet.
|
|
1745
|
+
*
|
|
1746
|
+
* Every compiler parse goes through here so the private encoder cannot be forgotten at one
|
|
1747
|
+
* call site. Forgetting it at any of them puts that module's reading into the encoder the
|
|
1748
|
+
* sheet is emitted from, under a `parse` owner nothing retracts.
|
|
1749
|
+
*/
|
|
1750
|
+
const parseForCompiler = (filePath, hookFilePath = filePath) => ctx?.project.parseSourceFile(filePath, parseEncoder, { hookFilePath });
|
|
1751
|
+
/**
|
|
1752
|
+
* Where the compiler may hold `code` for `filePath` without displacing the checkout.
|
|
1753
|
+
*
|
|
1754
|
+
* The file's own path exactly when the shared Project already holds these bytes — then
|
|
1755
|
+
* `addSourceFile` is a lookup and there is nothing to displace. @see `auxiliaryParsePath`
|
|
1756
|
+
*/
|
|
1757
|
+
const compilerSourcePath = (filePath, requested, code) => {
|
|
1758
|
+
if (requested !== filePath) return requested;
|
|
1759
|
+
return ctx?.project.getSourceFile(filePath)?.getFullText() === code ? filePath : auxiliaryParsePath(filePath);
|
|
1760
|
+
};
|
|
1761
|
+
/** Add one compiler-owned source without letting it displace or outlive its physical file. */
|
|
1762
|
+
const addCompilerSource = (filePath, parsePath, code) => {
|
|
1763
|
+
if (!ctx) return;
|
|
1764
|
+
const auxiliary = parsePath !== filePath;
|
|
1765
|
+
const sourceFile = ctx.project.addSourceFile(parsePath, code, { auxiliary });
|
|
1766
|
+
if (auxiliary) {
|
|
1767
|
+
const physical = normalizeFsPath(filePath);
|
|
1768
|
+
const paths = auxiliarySourcesByFile.get(physical) ?? /* @__PURE__ */ new Set();
|
|
1769
|
+
paths.add(parsePath);
|
|
1770
|
+
auxiliarySourcesByFile.set(physical, paths);
|
|
1771
|
+
}
|
|
1772
|
+
return sourceFile;
|
|
1773
|
+
};
|
|
1774
|
+
/** Release compiler encoder owners and sibling ASTs when their physical module disappears. */
|
|
1775
|
+
const releaseCompilerSources = (filePath) => {
|
|
1776
|
+
if (!ctx) return;
|
|
1777
|
+
parseEncoder?.releaseFile(filePath);
|
|
1778
|
+
const physical = normalizeFsPath(filePath);
|
|
1779
|
+
for (const auxiliary of auxiliarySourcesByFile.get(physical) ?? []) {
|
|
1780
|
+
parseEncoder?.releaseFile(auxiliary);
|
|
1781
|
+
ctx.project.removeSourceFile(auxiliary);
|
|
1782
|
+
}
|
|
1783
|
+
auxiliarySourcesByFile.delete(physical);
|
|
1581
1784
|
};
|
|
1582
1785
|
const outputFinalizerTag = (value) => {
|
|
1583
1786
|
if (!value || typeof value !== "object") return void 0;
|
|
@@ -1694,6 +1897,7 @@ const bamboocss = (options = {}) => {
|
|
|
1694
1897
|
},
|
|
1695
1898
|
configResolved(config) {
|
|
1696
1899
|
command = config.command;
|
|
1900
|
+
host.setCommand(config.command);
|
|
1697
1901
|
defaultEmitAssets = config.build?.emitAssets ?? (!config.build?.ssr || config.build?.ssrEmitAssets === true);
|
|
1698
1902
|
const plugins = config.plugins;
|
|
1699
1903
|
if (plugins) {
|
|
@@ -1748,9 +1952,9 @@ const bamboocss = (options = {}) => {
|
|
|
1748
1952
|
const [filePath] = id.split("?");
|
|
1749
1953
|
if (!filePath) return;
|
|
1750
1954
|
for (const state of transformStateByEnvironment.values()) state.recipeConfigCache.clear();
|
|
1751
|
-
if (SFC_EXTENSIONS.test(filePath)) return;
|
|
1752
1955
|
if (change.event === "delete") {
|
|
1753
|
-
|
|
1956
|
+
host.removeSource(filePath);
|
|
1957
|
+
releaseCompilerSources(filePath);
|
|
1754
1958
|
const deleted = normalizeFsPath(filePath);
|
|
1755
1959
|
for (const state of transformStateByEnvironment.values()) for (const [moduleId, moduleFile] of [...state.filesByModule]) {
|
|
1756
1960
|
if (normalizeFsPath(moduleFile) !== deleted) continue;
|
|
@@ -1762,7 +1966,8 @@ const bamboocss = (options = {}) => {
|
|
|
1762
1966
|
}
|
|
1763
1967
|
return;
|
|
1764
1968
|
}
|
|
1765
|
-
|
|
1969
|
+
if (SFC_EXTENSIONS.test(filePath)) return;
|
|
1970
|
+
host.reloadSource(filePath);
|
|
1766
1971
|
/**
|
|
1767
1972
|
* Fold the edited file before the browser asks for it.
|
|
1768
1973
|
*
|
|
@@ -1781,12 +1986,14 @@ const bamboocss = (options = {}) => {
|
|
|
1781
1986
|
*/
|
|
1782
1987
|
if (command === "serve") setImmediate(() => {
|
|
1783
1988
|
if (!ctx || !foldSourceImpl || !runtimeCss || !styleCompiler) return;
|
|
1989
|
+
if (host.isCssPassActive() || !compilerStateIsCurrent()) return;
|
|
1784
1990
|
try {
|
|
1785
1991
|
const code = (0, node_fs.readFileSync)(filePath, "utf8");
|
|
1786
1992
|
const memoKey = foldMemoKey(filePath, digest(code));
|
|
1787
1993
|
if (foldMemoByContent.has(memoKey)) return;
|
|
1788
|
-
const sourceFile =
|
|
1789
|
-
|
|
1994
|
+
const sourceFile = addCompilerSource(filePath, filePath, code);
|
|
1995
|
+
if (!sourceFile) return;
|
|
1996
|
+
const parserResult = parseForCompiler(filePath);
|
|
1790
1997
|
if (!parserResult) return;
|
|
1791
1998
|
const folded = foldSourceImpl({
|
|
1792
1999
|
ctx,
|
|
@@ -1796,7 +2003,7 @@ const bamboocss = (options = {}) => {
|
|
|
1796
2003
|
runtimeCss,
|
|
1797
2004
|
styleCompiler,
|
|
1798
2005
|
maxRecipeStates,
|
|
1799
|
-
parseModule:
|
|
2006
|
+
parseModule: parseForCompiler,
|
|
1800
2007
|
recipeConfigCache: transformStateByEnvironment.get("client")?.recipeConfigCache ?? /* @__PURE__ */ new Map(),
|
|
1801
2008
|
reportSurvivors: true,
|
|
1802
2009
|
sourceFile
|
|
@@ -1924,8 +2131,8 @@ const bamboocss = (options = {}) => {
|
|
|
1924
2131
|
if (!ctx || !foldSourceImpl || !runtimeCss || !styleCompiler) return null;
|
|
1925
2132
|
const [filePath] = id.split("?");
|
|
1926
2133
|
if (isGeneratedOutput(filePath, ctx)) return null;
|
|
1927
|
-
const
|
|
1928
|
-
if (
|
|
2134
|
+
const requestedParsePath = compilerParsePath(id, code);
|
|
2135
|
+
if (requestedParsePath === null) return null;
|
|
1929
2136
|
const state = environmentState(this);
|
|
1930
2137
|
state.transformedModulesThisRun.add(id);
|
|
1931
2138
|
let inputDigest;
|
|
@@ -1933,46 +2140,62 @@ const bamboocss = (options = {}) => {
|
|
|
1933
2140
|
const previousDependencies = previousSignature && previousSignature.input === (inputDigest ??= digest(code)) ? state.dependenciesByModule.get(id) : void 0;
|
|
1934
2141
|
let result;
|
|
1935
2142
|
try {
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
}
|
|
2143
|
+
/**
|
|
2144
|
+
* One serialized region, holding every read and every mutation of the shared AST.
|
|
2145
|
+
*
|
|
2146
|
+
* Synchronous throughout, which is what makes waiting for the stylesheet pass once at
|
|
2147
|
+
* the top sufficient: nothing can open a pass between the wait and the work, because
|
|
2148
|
+
* nothing else runs. The fold is CPU-bound anyway, so there is no await to give up.
|
|
2149
|
+
*/
|
|
2150
|
+
const compiled = await host.runCompilerWork(() => {
|
|
2151
|
+
if (!ctx || !foldSourceImpl || !runtimeCss || !styleCompiler) return null;
|
|
2152
|
+
const path = compilerSourcePath(filePath, requestedParsePath, code);
|
|
2153
|
+
const memoKey = command === "serve" ? foldMemoKey(path, inputDigest ??= digest(code)) : void 0;
|
|
2154
|
+
const memoized = memoKey ? foldMemoByContent.get(memoKey) : void 0;
|
|
2155
|
+
if (memoized?.reportedSurvivors) return {
|
|
2156
|
+
valueReads: memoized.valueReads,
|
|
2157
|
+
result: withResolutionClosure(path, memoized.result, memoized.parserDependencies, previousDependencies)
|
|
2158
|
+
};
|
|
2159
|
+
const sourceFile = addCompilerSource(filePath, path, code);
|
|
2160
|
+
if (!sourceFile) return null;
|
|
2161
|
+
const parserResult = parseForCompiler(path, requestedParsePath === filePath ? filePath : path);
|
|
2162
|
+
if (!parserResult) return { unparsed: true };
|
|
1952
2163
|
const folded = foldSourceImpl({
|
|
1953
2164
|
ctx,
|
|
1954
2165
|
code,
|
|
1955
2166
|
parserResult,
|
|
1956
|
-
filePath:
|
|
2167
|
+
filePath: path,
|
|
1957
2168
|
runtimeCss,
|
|
1958
2169
|
styleCompiler,
|
|
1959
2170
|
maxRecipeStates,
|
|
1960
|
-
parseModule:
|
|
2171
|
+
parseModule: parseForCompiler,
|
|
1961
2172
|
recipeConfigCache: state.recipeConfigCache,
|
|
1962
2173
|
reportSurvivors: true,
|
|
1963
2174
|
sourceFile
|
|
1964
2175
|
});
|
|
1965
2176
|
const parserDependencies = parserResult.getDependencies();
|
|
1966
|
-
valueReads = parserResult.getExportReads?.() ?? [];
|
|
2177
|
+
const valueReads = parserResult.getExportReads?.() ?? [];
|
|
1967
2178
|
if (memoKey) foldMemoByContent.set(memoKey, {
|
|
1968
2179
|
result: folded,
|
|
1969
2180
|
parserDependencies,
|
|
1970
2181
|
valueReads,
|
|
1971
2182
|
reportedSurvivors: true
|
|
1972
2183
|
});
|
|
1973
|
-
|
|
2184
|
+
return {
|
|
2185
|
+
valueReads,
|
|
2186
|
+
result: withResolutionClosure(path, folded, parserDependencies, previousDependencies)
|
|
2187
|
+
};
|
|
2188
|
+
});
|
|
2189
|
+
if (!compiled) return null;
|
|
2190
|
+
if ("unparsed" in compiled) {
|
|
2191
|
+
state.transformArtifactsByModule.delete(id);
|
|
2192
|
+
recordFoldDependencies(state, id, filePath, []);
|
|
2193
|
+
state.foldSignatures.delete(id);
|
|
2194
|
+
state.foldInputsByModule.delete(id);
|
|
2195
|
+
return null;
|
|
1974
2196
|
}
|
|
1975
|
-
|
|
2197
|
+
result = compiled.result;
|
|
2198
|
+
state.exportReadsByModule.set(id, [...compiled.valueReads.map((read) => ({
|
|
1976
2199
|
kind: "value",
|
|
1977
2200
|
...read
|
|
1978
2201
|
})), ...result.exportReads]);
|
|
@@ -2028,10 +2251,10 @@ const bamboocss = (options = {}) => {
|
|
|
2028
2251
|
} } : {}
|
|
2029
2252
|
});
|
|
2030
2253
|
applyTransformArtifact(state, artifact, id, environmentName(this));
|
|
2031
|
-
if (artifact.signature && (command === "serve" ||
|
|
2254
|
+
if (artifact.signature && (command === "serve" || requestedParsePath !== filePath)) state.foldInputsByModule.set(id, {
|
|
2032
2255
|
code,
|
|
2033
2256
|
input: artifact.signature.input,
|
|
2034
|
-
parsePath
|
|
2257
|
+
parsePath: requestedParsePath
|
|
2035
2258
|
});
|
|
2036
2259
|
else state.foldInputsByModule.delete(id);
|
|
2037
2260
|
if (reportSkipped && result.skipped.length) _bamboocss_logger.logger.info("vite:transform", formatSkipped(filePath, result.skipped));
|
|
@@ -2093,6 +2316,7 @@ const bamboocss = (options = {}) => {
|
|
|
2093
2316
|
bamboocssCss({
|
|
2094
2317
|
configPath,
|
|
2095
2318
|
cwd,
|
|
2319
|
+
host,
|
|
2096
2320
|
session: staticSession,
|
|
2097
2321
|
pruneCss
|
|
2098
2322
|
}),
|
package/dist/index.d.cts
CHANGED
package/dist/index.d.mts
CHANGED
package/dist/index.mjs
CHANGED
|
@@ -43,24 +43,121 @@ const loadCssOutputModule = createLazyCssOutputModule();
|
|
|
43
43
|
const createLazyFoldModule = (loadFold = () => import("./fold-module.mjs")) => createRetryableLazy(loadFold);
|
|
44
44
|
/** One process-wide fold-module load shared by every plugin instance and Vite environment. */
|
|
45
45
|
const loadFoldModule = createLazyFoldModule();
|
|
46
|
-
/**
|
|
46
|
+
/**
|
|
47
|
+
* The one Builder a run compiles against, created only when a hook first needs it.
|
|
48
|
+
*
|
|
49
|
+
* Per host rather than per plugin instance: the compiler and the stylesheet share it now.
|
|
50
|
+
* @see `createCompilationHost`
|
|
51
|
+
*/
|
|
47
52
|
const createLazyBuilder = (loadNode = loadNodeModule) => createRetryableLazy(async () => {
|
|
48
53
|
const { Builder } = await loadNode();
|
|
49
54
|
return new Builder();
|
|
50
55
|
});
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
const
|
|
55
|
-
const
|
|
56
|
+
//#endregion
|
|
57
|
+
//#region src/compilation-host.ts
|
|
58
|
+
const createCompilationHost = (options = {}) => {
|
|
59
|
+
const { configPath, cwd } = options;
|
|
60
|
+
const loadBuilder = options.loadBuilder ?? createLazyBuilder();
|
|
61
|
+
let command = "build";
|
|
62
|
+
let builder;
|
|
63
|
+
let generation;
|
|
64
|
+
let nextGenerationId = 0;
|
|
65
|
+
/**
|
|
66
|
+
* The setup covering the pass currently open.
|
|
67
|
+
*
|
|
68
|
+
* A cold start reaches this twice — the compiler's `pre` `buildStart`, then the CSS
|
|
69
|
+
* plugin's — for one instant in which nothing can have changed on disk. Sharing one attempt
|
|
70
|
+
* across both is what keeps a project from loading and evaluating its config twice per
|
|
71
|
+
* build. Cleared once a stylesheet pass consumes it, and on any source mutation, so no
|
|
72
|
+
* later pass can be answered by a setup taken before an edit.
|
|
73
|
+
*/
|
|
74
|
+
let openSetup;
|
|
75
|
+
let openSetupStale = false;
|
|
76
|
+
let cssPass;
|
|
77
|
+
const settled = async (attempt) => {
|
|
78
|
+
try {
|
|
79
|
+
await attempt;
|
|
80
|
+
} catch {}
|
|
81
|
+
};
|
|
82
|
+
const publish = () => {
|
|
83
|
+
const context = builder.getContextOrThrow();
|
|
84
|
+
if (generation?.context !== context) generation = {
|
|
85
|
+
id: ++nextGenerationId,
|
|
86
|
+
context,
|
|
87
|
+
encoder: context.encoder.clone()
|
|
88
|
+
};
|
|
89
|
+
return generation;
|
|
90
|
+
};
|
|
91
|
+
const runSetup = async () => {
|
|
92
|
+
builder ??= await loadBuilder();
|
|
93
|
+
await builder.setup({
|
|
94
|
+
configPath,
|
|
95
|
+
cwd,
|
|
96
|
+
dev: command === "serve"
|
|
97
|
+
});
|
|
98
|
+
return publish();
|
|
99
|
+
};
|
|
100
|
+
/**
|
|
101
|
+
* The setup covering the pass currently open, started at most once.
|
|
102
|
+
*
|
|
103
|
+
* Started through a resolved promise, so a synchronous throw becomes the same
|
|
104
|
+
* rejected-attempt contract a failed module load has and a later hook can retry it. A
|
|
105
|
+
* source mutation observed while one is in flight does not cancel it — two overlapping
|
|
106
|
+
* `Builder.setup` calls would interleave their change detection — it queues a fresh one
|
|
107
|
+
* behind it.
|
|
108
|
+
*/
|
|
109
|
+
const setupOnce = () => {
|
|
110
|
+
const previous = openSetup;
|
|
111
|
+
if (previous && !openSetupStale) return previous;
|
|
112
|
+
openSetupStale = false;
|
|
113
|
+
const attempt = previous ? settled(previous).then(runSetup) : Promise.resolve().then(runSetup);
|
|
114
|
+
openSetup = attempt;
|
|
115
|
+
attempt.catch(() => {
|
|
116
|
+
if (openSetup === attempt) openSetup = void 0;
|
|
117
|
+
});
|
|
118
|
+
return attempt;
|
|
119
|
+
};
|
|
56
120
|
return {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
121
|
+
setCommand(next) {
|
|
122
|
+
command = next;
|
|
123
|
+
},
|
|
124
|
+
current: () => generation,
|
|
125
|
+
async ensureGeneration() {
|
|
126
|
+
if (cssPass) await settled(cssPass);
|
|
127
|
+
if (generation) return Promise.resolve(generation);
|
|
128
|
+
return setupOnce();
|
|
129
|
+
},
|
|
130
|
+
isCssPassActive: () => cssPass !== void 0,
|
|
131
|
+
async runCssPass(run) {
|
|
132
|
+
while (cssPass) await settled(cssPass);
|
|
133
|
+
let release;
|
|
134
|
+
cssPass = new Promise((resolve) => {
|
|
135
|
+
release = resolve;
|
|
136
|
+
});
|
|
137
|
+
try {
|
|
138
|
+
const passGeneration = await setupOnce();
|
|
139
|
+
return await run(builder, passGeneration);
|
|
140
|
+
} finally {
|
|
141
|
+
openSetup = void 0;
|
|
142
|
+
openSetupStale = false;
|
|
143
|
+
cssPass = void 0;
|
|
144
|
+
release();
|
|
145
|
+
}
|
|
146
|
+
},
|
|
147
|
+
async runCompilerWork(run) {
|
|
148
|
+
while (cssPass) await settled(cssPass);
|
|
149
|
+
return run();
|
|
150
|
+
},
|
|
151
|
+
reloadSource(filePath) {
|
|
152
|
+
openSetupStale = true;
|
|
153
|
+
builder?.reloadSource(filePath);
|
|
154
|
+
},
|
|
155
|
+
removeSource(filePath) {
|
|
156
|
+
openSetupStale = true;
|
|
157
|
+
builder?.removeSource(filePath);
|
|
158
|
+
}
|
|
62
159
|
};
|
|
63
|
-
}
|
|
160
|
+
};
|
|
64
161
|
//#endregion
|
|
65
162
|
//#region src/static-session.ts
|
|
66
163
|
const createStaticCompilationSession = () => {
|
|
@@ -179,14 +276,11 @@ const asError = (error, context) => error instanceof Error ? error : new Error(`
|
|
|
179
276
|
* process just wrote, which is a race on any watch rebuild.
|
|
180
277
|
*/
|
|
181
278
|
const bamboocssCss = (options) => {
|
|
182
|
-
const { configPath, cwd, loadCssOutput = loadCssOutputModule, session,
|
|
279
|
+
const { configPath, cwd, loadCssOutput = loadCssOutputModule, session, host = createCompilationHost({
|
|
280
|
+
configPath,
|
|
281
|
+
cwd
|
|
282
|
+
}), pruneCss = true } = options;
|
|
183
283
|
let builder;
|
|
184
|
-
const loadBuilder = createLazyBuilder();
|
|
185
|
-
const ensureBuilder = async () => {
|
|
186
|
-
const loaded = await loadBuilder();
|
|
187
|
-
builder = loaded;
|
|
188
|
-
return loaded;
|
|
189
|
-
};
|
|
190
284
|
let server;
|
|
191
285
|
let command = "build";
|
|
192
286
|
/** The run's own `build` options, for a bundler with no per-environment config. */
|
|
@@ -221,34 +315,36 @@ const bamboocssCss = (options) => {
|
|
|
221
315
|
let changeGeneration = 0;
|
|
222
316
|
let pendingGeneration = -1;
|
|
223
317
|
let servedCss;
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
318
|
+
/**
|
|
319
|
+
* Held by the host for its whole length, rather than only around each mutation.
|
|
320
|
+
*
|
|
321
|
+
* Extraction fills the encoder this sheet is emitted from and `toCss` reads it back, with a
|
|
322
|
+
* deliberate macrotask between them. The compiler shares the AST both halves run against,
|
|
323
|
+
* so a transform folding a module in that window would re-prepare a source the extraction
|
|
324
|
+
* pass has already read and `toCss` has not finished reporting on. The host makes compiler
|
|
325
|
+
* work wait instead; a fold is a few milliseconds and this is the one place correctness
|
|
326
|
+
* depends on it.
|
|
327
|
+
*/
|
|
328
|
+
const build = () => host.runCssPass(async (activeBuilder) => {
|
|
329
|
+
builder = activeBuilder;
|
|
330
|
+
await activeBuilder.emit();
|
|
331
|
+
activeBuilder.extract();
|
|
233
332
|
await new Promise((settle) => setImmediate(settle));
|
|
234
|
-
if (
|
|
235
|
-
session.utilityLayer =
|
|
333
|
+
if (activeBuilder.context) {
|
|
334
|
+
session.utilityLayer = activeBuilder.context.config.layers?.utilities ?? "utilities";
|
|
236
335
|
session.extractedFiles.clear();
|
|
237
336
|
for (const file of extractedSourceFiles()) session.extractedFiles.add(file);
|
|
238
337
|
}
|
|
239
338
|
let graphAtomHashes;
|
|
240
|
-
if (
|
|
241
|
-
|
|
242
|
-
graphAtomHashes = new Set(
|
|
339
|
+
if (activeBuilder.context) {
|
|
340
|
+
activeBuilder.context.encoder.atomizeObservedRecipes();
|
|
341
|
+
graphAtomHashes = new Set(activeBuilder.context.encoder.atomic);
|
|
243
342
|
}
|
|
244
|
-
const css =
|
|
245
|
-
layerParams: true,
|
|
246
|
-
includeRecipes: false
|
|
247
|
-
});
|
|
343
|
+
const css = activeBuilder.toCss({ layerParams: true });
|
|
248
344
|
session.prunableClasses.clear();
|
|
249
345
|
session.viewTransitionClasses.clear();
|
|
250
|
-
if (graphAtomHashes &&
|
|
251
|
-
const decoder =
|
|
346
|
+
if (graphAtomHashes && activeBuilder.context) {
|
|
347
|
+
const decoder = activeBuilder.context.decoder.collect(activeBuilder.context.encoder);
|
|
252
348
|
for (const atom of decoder.atomic) if (graphAtomHashes.has(atom.hash)) session.prunableClasses.add(atom.className);
|
|
253
349
|
for (const transition of decoder.view_transitions) {
|
|
254
350
|
session.viewTransitionClasses.add(transition.className);
|
|
@@ -256,7 +352,7 @@ const bamboocssCss = (options) => {
|
|
|
256
352
|
}
|
|
257
353
|
}
|
|
258
354
|
return css;
|
|
259
|
-
};
|
|
355
|
+
});
|
|
260
356
|
const generate = () => {
|
|
261
357
|
if (command === "serve" && pending && pendingGeneration === changeGeneration) return pending;
|
|
262
358
|
pendingGeneration = changeGeneration;
|
|
@@ -336,6 +432,7 @@ const bamboocssCss = (options) => {
|
|
|
336
432
|
sharedDuringBuild: true,
|
|
337
433
|
async configResolved(config) {
|
|
338
434
|
command = config.command;
|
|
435
|
+
host.setCommand(config.command);
|
|
339
436
|
session.sourcemap = config.build.sourcemap;
|
|
340
437
|
ssrBuildOptions = {
|
|
341
438
|
ssr: config.build.ssr,
|
|
@@ -349,11 +446,12 @@ const bamboocssCss = (options) => {
|
|
|
349
446
|
* edited all afternoon. Nothing watched it: `watch` is the CLI's own watcher, and a
|
|
350
447
|
* project running `vite dev` never reaches it.
|
|
351
448
|
*
|
|
352
|
-
* A restart rather than re-emitting the stylesheet
|
|
353
|
-
*
|
|
354
|
-
*
|
|
355
|
-
*
|
|
356
|
-
*
|
|
449
|
+
* A restart rather than re-emitting the stylesheet. The two plugins share one context now,
|
|
450
|
+
* and the compiler re-derives everything it holds when `Builder.setup` replaces it — so the
|
|
451
|
+
* half-updated state this used to prevent, with the compiler naming classes from the old
|
|
452
|
+
* config against a sheet emitted from the new one, can no longer happen. What a restart
|
|
453
|
+
* still buys is the rest of the server: a changed `outdir`, a preset that adds an entry
|
|
454
|
+
* point, and every module Vite has already transformed against the previous config.
|
|
357
455
|
*
|
|
358
456
|
* Through Vite's own list rather than a watcher of ours. Vite adds these paths to the
|
|
359
457
|
* files it watches, which is what reaches a config *outside* `root` — a monorepo with one
|
|
@@ -623,6 +721,22 @@ const compilerParsePath = (id, code) => {
|
|
|
623
721
|
return `${filePath}.__bamboo__.ts`;
|
|
624
722
|
};
|
|
625
723
|
/**
|
|
724
|
+
* Where to park a transform's text when it is not what the shared Project holds for the file.
|
|
725
|
+
*
|
|
726
|
+
* The compiler folds the bundler's view of a module — after every `enforce: 'pre'` plugin
|
|
727
|
+
* before it, and after Vite's own load. The stylesheet pass reads the same file off disk
|
|
728
|
+
* through the same ts-morph Project. When the two texts differ and the compiler writes its
|
|
729
|
+
* own under the file's path, that transform silently becomes the canonical source for the
|
|
730
|
+
* next extraction pass: the CSS would then be generated from a bundler artifact rather than
|
|
731
|
+
* from the checkout. Under a sibling path both readings exist and neither overwrites the
|
|
732
|
+
* other, which is the same reason `compilerParsePath` already does this for SFC submodules.
|
|
733
|
+
*
|
|
734
|
+
* The extension carries JSX-ness across, since it is what ts-morph keys its script kind on:
|
|
735
|
+
* anything but an unambiguously non-JSX `.ts`/`.mts`/`.cts` is parsed as `.tsx`, so a `<div>`
|
|
736
|
+
* in a `.js` file still parses and a `<T>value` assertion in a `.ts` file still means a cast.
|
|
737
|
+
*/
|
|
738
|
+
const auxiliaryParsePath = (filePath) => `${filePath}.__bamboo__.${/\.[cm]?ts$/i.test(filePath) ? "ts" : "tsx"}`;
|
|
739
|
+
/**
|
|
626
740
|
* Is this file part of the generated `styled-system` rather than the user's source?
|
|
627
741
|
*
|
|
628
742
|
* Resolved to a path and compared as a prefix, rather than by looking for the outdir's
|
|
@@ -677,6 +791,17 @@ const bamboocss = (options = {}) => {
|
|
|
677
791
|
if (maxRecipeStates !== void 0 && (!Number.isSafeInteger(maxRecipeStates) || maxRecipeStates < 1)) throw new Error("bamboocss: `maxRecipeStates` must be a positive safe integer.");
|
|
678
792
|
if ("renameCssAsset" in options) throw new Error("bamboocss: `renameCssAsset` has been replaced by `pruneCss`. Use `pruneCss: false` for what `renameCssAsset: false` did — it always disabled the pruning as well, since pruned bytes under the unpruned sheet's name is what lets a CDN serve a stale stylesheet. The new name says which of the two it is really about.");
|
|
679
793
|
const staticSession = createStaticCompilationSession();
|
|
794
|
+
/**
|
|
795
|
+
* One Builder, one resolved config, one context and one ts-morph project for the run.
|
|
796
|
+
*
|
|
797
|
+
* Created here rather than by either plugin because both need it and neither may own it:
|
|
798
|
+
* the compiler used to load a second config of its own, which is why a token edit could
|
|
799
|
+
* leave it naming classes from the old one against a sheet emitted from the new one.
|
|
800
|
+
*/
|
|
801
|
+
const host = createCompilationHost({
|
|
802
|
+
configPath,
|
|
803
|
+
cwd
|
|
804
|
+
});
|
|
680
805
|
const transformArtifactIntegrityKey = randomBytes(32);
|
|
681
806
|
const serializeTransformArtifact = (environment, artifact) => JSON.stringify([
|
|
682
807
|
TRANSFORM_META_KEY,
|
|
@@ -1321,6 +1446,8 @@ const bamboocss = (options = {}) => {
|
|
|
1321
1446
|
const foldOutputUnchanged = (state, dependent, changedFile) => {
|
|
1322
1447
|
const memoized = state.unchangedFolds.get(dependent);
|
|
1323
1448
|
if (memoized !== void 0) return memoized;
|
|
1449
|
+
if (host.isCssPassActive()) return false;
|
|
1450
|
+
if (!compilerStateIsCurrent()) return false;
|
|
1324
1451
|
const unchanged = state.changedRun < CHANGED_RUN_LIMIT && refoldMatchesSignature(state, dependent, changedFile);
|
|
1325
1452
|
state.changedRun = unchanged ? 0 : state.changedRun + 1;
|
|
1326
1453
|
state.unchangedFolds.set(dependent, unchanged);
|
|
@@ -1332,7 +1459,8 @@ const bamboocss = (options = {}) => {
|
|
|
1332
1459
|
try {
|
|
1333
1460
|
const retained = state.foldInputsByModule.get(dependent);
|
|
1334
1461
|
const code = retained?.input === signature.input ? retained.code : readFileSync(signature.path, "utf8");
|
|
1335
|
-
const
|
|
1462
|
+
const requestedParsePath = retained?.input === signature.input ? retained.parsePath : signature.path;
|
|
1463
|
+
const parsePath = compilerSourcePath(signature.path, requestedParsePath, code);
|
|
1336
1464
|
const inputDigest = digest(code);
|
|
1337
1465
|
if (inputDigest !== signature.input) return false;
|
|
1338
1466
|
/**
|
|
@@ -1349,7 +1477,7 @@ const bamboocss = (options = {}) => {
|
|
|
1349
1477
|
*/
|
|
1350
1478
|
const reads = state.exportReadsByModule.get(dependent);
|
|
1351
1479
|
if (reads?.length && verifyExportReadsImpl) {
|
|
1352
|
-
const { verdict, crossings } = verifyExportReadsImpl(ctx,
|
|
1480
|
+
const { verdict, crossings } = verifyExportReadsImpl(ctx, parseForCompiler, reads, normalizeFsPath(changedFile), verifyDigestMemo);
|
|
1353
1481
|
if (verdict === "unchanged") {
|
|
1354
1482
|
recordFoldDependencies(state, dependent, signature.path, [...state.dependenciesByModule.get(dependent) ?? [], ...crossings]);
|
|
1355
1483
|
return true;
|
|
@@ -1364,8 +1492,9 @@ const bamboocss = (options = {}) => {
|
|
|
1364
1492
|
raw = memoized.result;
|
|
1365
1493
|
parserDependencies = memoized.parserDependencies;
|
|
1366
1494
|
} else {
|
|
1367
|
-
const sourceFile =
|
|
1368
|
-
|
|
1495
|
+
const sourceFile = addCompilerSource(signature.path, parsePath, code);
|
|
1496
|
+
if (!sourceFile) return false;
|
|
1497
|
+
const parserResult = parseForCompiler(parsePath, requestedParsePath === signature.path ? signature.path : parsePath);
|
|
1369
1498
|
if (!parserResult) return false;
|
|
1370
1499
|
raw = foldSourceImpl({
|
|
1371
1500
|
ctx,
|
|
@@ -1375,7 +1504,7 @@ const bamboocss = (options = {}) => {
|
|
|
1375
1504
|
runtimeCss,
|
|
1376
1505
|
styleCompiler,
|
|
1377
1506
|
maxRecipeStates,
|
|
1378
|
-
parseModule:
|
|
1507
|
+
parseModule: parseForCompiler,
|
|
1379
1508
|
recipeConfigCache: state.recipeConfigCache,
|
|
1380
1509
|
reportSurvivors: false,
|
|
1381
1510
|
sourceFile
|
|
@@ -1515,6 +1644,8 @@ const bamboocss = (options = {}) => {
|
|
|
1515
1644
|
return [...modules, ...added];
|
|
1516
1645
|
};
|
|
1517
1646
|
let ctx;
|
|
1647
|
+
/** The compiler's private parse sink for `ctx`. @see `CompilationGeneration.encoder` */
|
|
1648
|
+
let parseEncoder;
|
|
1518
1649
|
let foldSourceImpl;
|
|
1519
1650
|
let verifyExportReadsImpl;
|
|
1520
1651
|
let runtimeCss;
|
|
@@ -1554,25 +1685,97 @@ const bamboocss = (options = {}) => {
|
|
|
1554
1685
|
dependencies: expanded
|
|
1555
1686
|
};
|
|
1556
1687
|
};
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1688
|
+
/** Which context the published derivations below were built from. */
|
|
1689
|
+
let derivedGeneration = -1;
|
|
1690
|
+
/** Compiler-only sibling ASTs retained for each physical module. */
|
|
1691
|
+
const auxiliarySourcesByFile = /* @__PURE__ */ new Map();
|
|
1692
|
+
/**
|
|
1693
|
+
* Whether the compiler state below still describes the context the host is on.
|
|
1694
|
+
*
|
|
1695
|
+
* Only `ensureCompilerState` re-derives, and only an awaited hook may call it — so the two
|
|
1696
|
+
* synchronous entry points, the speculative prefold and the unchanged-dependent check, can
|
|
1697
|
+
* be reached after a stylesheet pass has published a config reload they have not seen. Both
|
|
1698
|
+
* decline rather than fold against a runtime `css` from the previous config.
|
|
1699
|
+
*/
|
|
1700
|
+
const compilerStateIsCurrent = () => {
|
|
1701
|
+
const current = host.current();
|
|
1702
|
+
return current !== void 0 && current.id === derivedGeneration;
|
|
1703
|
+
};
|
|
1566
1704
|
const ensureContext = async () => {
|
|
1567
|
-
ctx = await
|
|
1705
|
+
ctx = (await host.ensureGeneration()).context;
|
|
1568
1706
|
};
|
|
1707
|
+
/**
|
|
1708
|
+
* Load the fold chunk and derive everything that depends on the resolved context.
|
|
1709
|
+
*
|
|
1710
|
+
* Keyed on context *identity* rather than derived once. `Builder.setup` replaces its context
|
|
1711
|
+
* on a config reload, and the runtime `css`, the style-set compiler and the parse sink are
|
|
1712
|
+
* all closures over the previous one — a stale `runtimeCss` names classes from the old
|
|
1713
|
+
* config while the stylesheet is emitted from the new one, and nothing downstream can see
|
|
1714
|
+
* the difference. Re-derivation is cheap; both factories are a handful of bound methods.
|
|
1715
|
+
*
|
|
1716
|
+
* Published as a set, and only once every part of the attempt has succeeded, so a failed
|
|
1717
|
+
* chunk load leaves no half-compiler visible to HMR.
|
|
1718
|
+
*/
|
|
1569
1719
|
const ensureCompilerState = async () => {
|
|
1570
|
-
const
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1720
|
+
const [initialGeneration, fold] = await Promise.all([host.ensureGeneration(), loadFoldModule()]);
|
|
1721
|
+
const currentGeneration = await host.ensureGeneration();
|
|
1722
|
+
const generation = currentGeneration.id === initialGeneration.id ? initialGeneration : currentGeneration;
|
|
1723
|
+
if (derivedGeneration === generation.id && foldSourceImpl) {
|
|
1724
|
+
ctx = generation.context;
|
|
1725
|
+
return;
|
|
1726
|
+
}
|
|
1727
|
+
const derivedRuntimeCss = fold.createRuntimeCss(generation.context);
|
|
1728
|
+
const derivedStyleCompiler = fold.createStaticStyleSetCompiler(generation.context, derivedRuntimeCss);
|
|
1729
|
+
ctx = generation.context;
|
|
1730
|
+
parseEncoder = generation.encoder;
|
|
1731
|
+
foldSourceImpl = fold.foldSource;
|
|
1732
|
+
verifyExportReadsImpl = fold.verifyExportReads;
|
|
1733
|
+
runtimeCss = derivedRuntimeCss;
|
|
1734
|
+
styleCompiler = derivedStyleCompiler;
|
|
1735
|
+
derivedGeneration = generation.id;
|
|
1736
|
+
auxiliarySourcesByFile.clear();
|
|
1737
|
+
};
|
|
1738
|
+
/**
|
|
1739
|
+
* Parse a module for the compiler, never for the stylesheet.
|
|
1740
|
+
*
|
|
1741
|
+
* Every compiler parse goes through here so the private encoder cannot be forgotten at one
|
|
1742
|
+
* call site. Forgetting it at any of them puts that module's reading into the encoder the
|
|
1743
|
+
* sheet is emitted from, under a `parse` owner nothing retracts.
|
|
1744
|
+
*/
|
|
1745
|
+
const parseForCompiler = (filePath, hookFilePath = filePath) => ctx?.project.parseSourceFile(filePath, parseEncoder, { hookFilePath });
|
|
1746
|
+
/**
|
|
1747
|
+
* Where the compiler may hold `code` for `filePath` without displacing the checkout.
|
|
1748
|
+
*
|
|
1749
|
+
* The file's own path exactly when the shared Project already holds these bytes — then
|
|
1750
|
+
* `addSourceFile` is a lookup and there is nothing to displace. @see `auxiliaryParsePath`
|
|
1751
|
+
*/
|
|
1752
|
+
const compilerSourcePath = (filePath, requested, code) => {
|
|
1753
|
+
if (requested !== filePath) return requested;
|
|
1754
|
+
return ctx?.project.getSourceFile(filePath)?.getFullText() === code ? filePath : auxiliaryParsePath(filePath);
|
|
1755
|
+
};
|
|
1756
|
+
/** Add one compiler-owned source without letting it displace or outlive its physical file. */
|
|
1757
|
+
const addCompilerSource = (filePath, parsePath, code) => {
|
|
1758
|
+
if (!ctx) return;
|
|
1759
|
+
const auxiliary = parsePath !== filePath;
|
|
1760
|
+
const sourceFile = ctx.project.addSourceFile(parsePath, code, { auxiliary });
|
|
1761
|
+
if (auxiliary) {
|
|
1762
|
+
const physical = normalizeFsPath(filePath);
|
|
1763
|
+
const paths = auxiliarySourcesByFile.get(physical) ?? /* @__PURE__ */ new Set();
|
|
1764
|
+
paths.add(parsePath);
|
|
1765
|
+
auxiliarySourcesByFile.set(physical, paths);
|
|
1766
|
+
}
|
|
1767
|
+
return sourceFile;
|
|
1768
|
+
};
|
|
1769
|
+
/** Release compiler encoder owners and sibling ASTs when their physical module disappears. */
|
|
1770
|
+
const releaseCompilerSources = (filePath) => {
|
|
1771
|
+
if (!ctx) return;
|
|
1772
|
+
parseEncoder?.releaseFile(filePath);
|
|
1773
|
+
const physical = normalizeFsPath(filePath);
|
|
1774
|
+
for (const auxiliary of auxiliarySourcesByFile.get(physical) ?? []) {
|
|
1775
|
+
parseEncoder?.releaseFile(auxiliary);
|
|
1776
|
+
ctx.project.removeSourceFile(auxiliary);
|
|
1777
|
+
}
|
|
1778
|
+
auxiliarySourcesByFile.delete(physical);
|
|
1576
1779
|
};
|
|
1577
1780
|
const outputFinalizerTag = (value) => {
|
|
1578
1781
|
if (!value || typeof value !== "object") return void 0;
|
|
@@ -1689,6 +1892,7 @@ const bamboocss = (options = {}) => {
|
|
|
1689
1892
|
},
|
|
1690
1893
|
configResolved(config) {
|
|
1691
1894
|
command = config.command;
|
|
1895
|
+
host.setCommand(config.command);
|
|
1692
1896
|
defaultEmitAssets = config.build?.emitAssets ?? (!config.build?.ssr || config.build?.ssrEmitAssets === true);
|
|
1693
1897
|
const plugins = config.plugins;
|
|
1694
1898
|
if (plugins) {
|
|
@@ -1743,9 +1947,9 @@ const bamboocss = (options = {}) => {
|
|
|
1743
1947
|
const [filePath] = id.split("?");
|
|
1744
1948
|
if (!filePath) return;
|
|
1745
1949
|
for (const state of transformStateByEnvironment.values()) state.recipeConfigCache.clear();
|
|
1746
|
-
if (SFC_EXTENSIONS.test(filePath)) return;
|
|
1747
1950
|
if (change.event === "delete") {
|
|
1748
|
-
|
|
1951
|
+
host.removeSource(filePath);
|
|
1952
|
+
releaseCompilerSources(filePath);
|
|
1749
1953
|
const deleted = normalizeFsPath(filePath);
|
|
1750
1954
|
for (const state of transformStateByEnvironment.values()) for (const [moduleId, moduleFile] of [...state.filesByModule]) {
|
|
1751
1955
|
if (normalizeFsPath(moduleFile) !== deleted) continue;
|
|
@@ -1757,7 +1961,8 @@ const bamboocss = (options = {}) => {
|
|
|
1757
1961
|
}
|
|
1758
1962
|
return;
|
|
1759
1963
|
}
|
|
1760
|
-
|
|
1964
|
+
if (SFC_EXTENSIONS.test(filePath)) return;
|
|
1965
|
+
host.reloadSource(filePath);
|
|
1761
1966
|
/**
|
|
1762
1967
|
* Fold the edited file before the browser asks for it.
|
|
1763
1968
|
*
|
|
@@ -1776,12 +1981,14 @@ const bamboocss = (options = {}) => {
|
|
|
1776
1981
|
*/
|
|
1777
1982
|
if (command === "serve") setImmediate(() => {
|
|
1778
1983
|
if (!ctx || !foldSourceImpl || !runtimeCss || !styleCompiler) return;
|
|
1984
|
+
if (host.isCssPassActive() || !compilerStateIsCurrent()) return;
|
|
1779
1985
|
try {
|
|
1780
1986
|
const code = readFileSync(filePath, "utf8");
|
|
1781
1987
|
const memoKey = foldMemoKey(filePath, digest(code));
|
|
1782
1988
|
if (foldMemoByContent.has(memoKey)) return;
|
|
1783
|
-
const sourceFile =
|
|
1784
|
-
|
|
1989
|
+
const sourceFile = addCompilerSource(filePath, filePath, code);
|
|
1990
|
+
if (!sourceFile) return;
|
|
1991
|
+
const parserResult = parseForCompiler(filePath);
|
|
1785
1992
|
if (!parserResult) return;
|
|
1786
1993
|
const folded = foldSourceImpl({
|
|
1787
1994
|
ctx,
|
|
@@ -1791,7 +1998,7 @@ const bamboocss = (options = {}) => {
|
|
|
1791
1998
|
runtimeCss,
|
|
1792
1999
|
styleCompiler,
|
|
1793
2000
|
maxRecipeStates,
|
|
1794
|
-
parseModule:
|
|
2001
|
+
parseModule: parseForCompiler,
|
|
1795
2002
|
recipeConfigCache: transformStateByEnvironment.get("client")?.recipeConfigCache ?? /* @__PURE__ */ new Map(),
|
|
1796
2003
|
reportSurvivors: true,
|
|
1797
2004
|
sourceFile
|
|
@@ -1919,8 +2126,8 @@ const bamboocss = (options = {}) => {
|
|
|
1919
2126
|
if (!ctx || !foldSourceImpl || !runtimeCss || !styleCompiler) return null;
|
|
1920
2127
|
const [filePath] = id.split("?");
|
|
1921
2128
|
if (isGeneratedOutput(filePath, ctx)) return null;
|
|
1922
|
-
const
|
|
1923
|
-
if (
|
|
2129
|
+
const requestedParsePath = compilerParsePath(id, code);
|
|
2130
|
+
if (requestedParsePath === null) return null;
|
|
1924
2131
|
const state = environmentState(this);
|
|
1925
2132
|
state.transformedModulesThisRun.add(id);
|
|
1926
2133
|
let inputDigest;
|
|
@@ -1928,46 +2135,62 @@ const bamboocss = (options = {}) => {
|
|
|
1928
2135
|
const previousDependencies = previousSignature && previousSignature.input === (inputDigest ??= digest(code)) ? state.dependenciesByModule.get(id) : void 0;
|
|
1929
2136
|
let result;
|
|
1930
2137
|
try {
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
}
|
|
2138
|
+
/**
|
|
2139
|
+
* One serialized region, holding every read and every mutation of the shared AST.
|
|
2140
|
+
*
|
|
2141
|
+
* Synchronous throughout, which is what makes waiting for the stylesheet pass once at
|
|
2142
|
+
* the top sufficient: nothing can open a pass between the wait and the work, because
|
|
2143
|
+
* nothing else runs. The fold is CPU-bound anyway, so there is no await to give up.
|
|
2144
|
+
*/
|
|
2145
|
+
const compiled = await host.runCompilerWork(() => {
|
|
2146
|
+
if (!ctx || !foldSourceImpl || !runtimeCss || !styleCompiler) return null;
|
|
2147
|
+
const path = compilerSourcePath(filePath, requestedParsePath, code);
|
|
2148
|
+
const memoKey = command === "serve" ? foldMemoKey(path, inputDigest ??= digest(code)) : void 0;
|
|
2149
|
+
const memoized = memoKey ? foldMemoByContent.get(memoKey) : void 0;
|
|
2150
|
+
if (memoized?.reportedSurvivors) return {
|
|
2151
|
+
valueReads: memoized.valueReads,
|
|
2152
|
+
result: withResolutionClosure(path, memoized.result, memoized.parserDependencies, previousDependencies)
|
|
2153
|
+
};
|
|
2154
|
+
const sourceFile = addCompilerSource(filePath, path, code);
|
|
2155
|
+
if (!sourceFile) return null;
|
|
2156
|
+
const parserResult = parseForCompiler(path, requestedParsePath === filePath ? filePath : path);
|
|
2157
|
+
if (!parserResult) return { unparsed: true };
|
|
1947
2158
|
const folded = foldSourceImpl({
|
|
1948
2159
|
ctx,
|
|
1949
2160
|
code,
|
|
1950
2161
|
parserResult,
|
|
1951
|
-
filePath:
|
|
2162
|
+
filePath: path,
|
|
1952
2163
|
runtimeCss,
|
|
1953
2164
|
styleCompiler,
|
|
1954
2165
|
maxRecipeStates,
|
|
1955
|
-
parseModule:
|
|
2166
|
+
parseModule: parseForCompiler,
|
|
1956
2167
|
recipeConfigCache: state.recipeConfigCache,
|
|
1957
2168
|
reportSurvivors: true,
|
|
1958
2169
|
sourceFile
|
|
1959
2170
|
});
|
|
1960
2171
|
const parserDependencies = parserResult.getDependencies();
|
|
1961
|
-
valueReads = parserResult.getExportReads?.() ?? [];
|
|
2172
|
+
const valueReads = parserResult.getExportReads?.() ?? [];
|
|
1962
2173
|
if (memoKey) foldMemoByContent.set(memoKey, {
|
|
1963
2174
|
result: folded,
|
|
1964
2175
|
parserDependencies,
|
|
1965
2176
|
valueReads,
|
|
1966
2177
|
reportedSurvivors: true
|
|
1967
2178
|
});
|
|
1968
|
-
|
|
2179
|
+
return {
|
|
2180
|
+
valueReads,
|
|
2181
|
+
result: withResolutionClosure(path, folded, parserDependencies, previousDependencies)
|
|
2182
|
+
};
|
|
2183
|
+
});
|
|
2184
|
+
if (!compiled) return null;
|
|
2185
|
+
if ("unparsed" in compiled) {
|
|
2186
|
+
state.transformArtifactsByModule.delete(id);
|
|
2187
|
+
recordFoldDependencies(state, id, filePath, []);
|
|
2188
|
+
state.foldSignatures.delete(id);
|
|
2189
|
+
state.foldInputsByModule.delete(id);
|
|
2190
|
+
return null;
|
|
1969
2191
|
}
|
|
1970
|
-
|
|
2192
|
+
result = compiled.result;
|
|
2193
|
+
state.exportReadsByModule.set(id, [...compiled.valueReads.map((read) => ({
|
|
1971
2194
|
kind: "value",
|
|
1972
2195
|
...read
|
|
1973
2196
|
})), ...result.exportReads]);
|
|
@@ -2023,10 +2246,10 @@ const bamboocss = (options = {}) => {
|
|
|
2023
2246
|
} } : {}
|
|
2024
2247
|
});
|
|
2025
2248
|
applyTransformArtifact(state, artifact, id, environmentName(this));
|
|
2026
|
-
if (artifact.signature && (command === "serve" ||
|
|
2249
|
+
if (artifact.signature && (command === "serve" || requestedParsePath !== filePath)) state.foldInputsByModule.set(id, {
|
|
2027
2250
|
code,
|
|
2028
2251
|
input: artifact.signature.input,
|
|
2029
|
-
parsePath
|
|
2252
|
+
parsePath: requestedParsePath
|
|
2030
2253
|
});
|
|
2031
2254
|
else state.foldInputsByModule.delete(id);
|
|
2032
2255
|
if (reportSkipped && result.skipped.length) logger.info("vite:transform", formatSkipped(filePath, result.skipped));
|
|
@@ -2088,6 +2311,7 @@ const bamboocss = (options = {}) => {
|
|
|
2088
2311
|
bamboocssCss({
|
|
2089
2312
|
configPath,
|
|
2090
2313
|
cwd,
|
|
2314
|
+
host,
|
|
2091
2315
|
session: staticSession,
|
|
2092
2316
|
pruneCss
|
|
2093
2317
|
}),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bamboocss/vite",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.48.0",
|
|
4
4
|
"description": "Vite integration for Bamboo CSS",
|
|
5
5
|
"homepage": "https://bamboocss.com",
|
|
6
6
|
"license": "MIT",
|
|
@@ -42,18 +42,18 @@
|
|
|
42
42
|
"postcss": "8.5.26",
|
|
43
43
|
"postcss-selector-parser": "7.1.5",
|
|
44
44
|
"ts-morph": "28.0.0",
|
|
45
|
-
"@bamboocss/
|
|
46
|
-
"@bamboocss/config": "1.
|
|
47
|
-
"@bamboocss/
|
|
48
|
-
"@bamboocss/
|
|
49
|
-
"@bamboocss/
|
|
50
|
-
"@bamboocss/shared": "1.
|
|
51
|
-
"@bamboocss/types": "1.
|
|
45
|
+
"@bamboocss/logger": "1.48.0",
|
|
46
|
+
"@bamboocss/config": "1.48.0",
|
|
47
|
+
"@bamboocss/core": "1.48.0",
|
|
48
|
+
"@bamboocss/node": "1.48.0",
|
|
49
|
+
"@bamboocss/extractor": "1.48.0",
|
|
50
|
+
"@bamboocss/shared": "1.48.0",
|
|
51
|
+
"@bamboocss/types": "1.48.0"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
54
|
"@jridgewell/trace-mapping": "^0.3.31",
|
|
55
55
|
"vite": "7.2.6",
|
|
56
|
-
"@bamboocss/fixture": "1.
|
|
56
|
+
"@bamboocss/fixture": "1.48.0"
|
|
57
57
|
},
|
|
58
58
|
"peerDependencies": {
|
|
59
59
|
"vite": ">=5"
|