@bamboocss/vite 1.53.1 → 1.54.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/css-output-module.cjs +411 -17
- package/dist/css-output-module.mjs +409 -18
- package/dist/fold-module.cjs +1 -1
- package/dist/fold-module.mjs +1 -1
- package/dist/index.cjs +346 -51
- package/dist/index.d.cts +11 -0
- package/dist/index.d.mts +11 -0
- package/dist/index.mjs +346 -51
- package/package.json +11 -10
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { t as bare } from "./class-name.mjs";
|
|
2
|
+
import { basename, join } from "node:path";
|
|
2
3
|
import { toHash, truncateList } from "@bamboocss/shared";
|
|
4
|
+
import { existsSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
3
5
|
import remapping from "@ampproject/remapping";
|
|
6
|
+
import { GenMapping, addMapping, toEncodedMap } from "@jridgewell/gen-mapping";
|
|
4
7
|
import MagicString from "magic-string";
|
|
5
8
|
import postcss from "postcss";
|
|
6
9
|
import selectorParser from "postcss-selector-parser";
|
|
@@ -170,43 +173,431 @@ const generatedCssSource = (output) => {
|
|
|
170
173
|
const source = typeof output.source === "string" ? output.source : Buffer.from(output.source).toString();
|
|
171
174
|
return source.includes("--made-with-bamboo") ? source : void 0;
|
|
172
175
|
};
|
|
173
|
-
/** Whether this bundle replaces a previously generated Bamboo stylesheet. */
|
|
174
|
-
const containsGeneratedCssAsset = (bundle) => Object.values(bundle).some((output) => generatedCssSource(output) !== void 0);
|
|
175
176
|
/**
|
|
176
|
-
*
|
|
177
|
-
*
|
|
178
|
-
* Rollup has already expanded `[hash]` when `generateBundle` runs. Mutating only `source`
|
|
179
|
-
* would therefore leave two different reachable subsets under one CDN key. The extra final
|
|
180
|
-
* hash is not cosmetic: it makes late graph reachability cache-safe.
|
|
181
|
-
*
|
|
182
|
-
* Renaming is therefore not a choice this takes. Pruned bytes under the unpruned sheet's name
|
|
183
|
-
* is the one outcome that must never be reachable, and a sheet nothing was removed from keeps
|
|
184
|
-
* its name because its bytes are unchanged — so "rename" is a consequence of "the bytes moved",
|
|
185
|
-
* not a second option. `prune` is the only knob.
|
|
177
|
+
* Whether this bundle replaces a previously generated Bamboo stylesheet — or, given the set of
|
|
178
|
+
* assets a pass already handled, whether any generated sheet is still waiting for one.
|
|
186
179
|
*/
|
|
180
|
+
const containsGeneratedCssAsset = (bundle, handled, handledNames) => Object.values(bundle).some((output) => generatedCssSource(output) !== void 0 && !handled?.has(output) && !handledNames?.has(output.fileName));
|
|
187
181
|
const optimizeStaticCssAssets = (bundle, session, options = {}) => {
|
|
188
|
-
const { environment, prune = true, requiredClasses, sourcemap = session.sourcemap } = options;
|
|
182
|
+
const { environment, prune = true, requiredClasses, sourcemap = session.sourcemap, handled, handledNames, split } = options;
|
|
189
183
|
/** Assets in this bundle that carry the generated stylesheet, pruned or not. */
|
|
190
184
|
let sheets = 0;
|
|
185
|
+
/** Their file names, after any rename below. */
|
|
186
|
+
const names = [];
|
|
187
|
+
const results = [];
|
|
191
188
|
for (const output of Object.values(bundle)) {
|
|
192
189
|
const source = generatedCssSource(output);
|
|
193
190
|
if (source === void 0) continue;
|
|
191
|
+
if (handled?.has(output) || handledNames?.has(output.fileName)) continue;
|
|
192
|
+
handled?.add(output);
|
|
193
|
+
handledNames?.add(output.fileName);
|
|
194
194
|
sheets++;
|
|
195
|
-
|
|
195
|
+
names.push(output.fileName);
|
|
196
|
+
const original = output.fileName;
|
|
197
|
+
const pruned = pruneStaticCss(source, session, {
|
|
196
198
|
environment,
|
|
197
199
|
prune,
|
|
198
200
|
requiredClasses
|
|
199
201
|
});
|
|
200
|
-
if (!prune)
|
|
202
|
+
if (!prune) {
|
|
203
|
+
results.push({
|
|
204
|
+
original,
|
|
205
|
+
fileName: original,
|
|
206
|
+
source,
|
|
207
|
+
optimized: source,
|
|
208
|
+
asset: output,
|
|
209
|
+
moved: /* @__PURE__ */ new Set()
|
|
210
|
+
});
|
|
211
|
+
continue;
|
|
212
|
+
}
|
|
213
|
+
let optimized = pruned;
|
|
214
|
+
let moved = /* @__PURE__ */ new Set();
|
|
215
|
+
if (split?.ownership.size) {
|
|
216
|
+
const divided = splitStaticCss(pruned, session, split.ownership);
|
|
217
|
+
optimized = divided.css;
|
|
218
|
+
moved = divided.moved;
|
|
219
|
+
for (const [chunk, css] of divided.chunks) split.emit(chunk, css);
|
|
220
|
+
}
|
|
201
221
|
output.source = optimized;
|
|
202
|
-
if (optimized === source)
|
|
222
|
+
if (optimized === source) {
|
|
223
|
+
results.push({
|
|
224
|
+
original,
|
|
225
|
+
fileName: original,
|
|
226
|
+
source,
|
|
227
|
+
optimized,
|
|
228
|
+
asset: output,
|
|
229
|
+
moved
|
|
230
|
+
});
|
|
231
|
+
continue;
|
|
232
|
+
}
|
|
233
|
+
names.pop();
|
|
203
234
|
const nextName = output.fileName.replace(/\.css$/, `.b-${toHash(optimized)}.css`);
|
|
204
235
|
if (bundle[nextName] && bundle[nextName] !== output) throw new Error(`bamboocss: final CSS asset name collision at ${JSON.stringify(nextName)}.`);
|
|
205
236
|
const previous = output.fileName;
|
|
206
237
|
output.fileName = nextName;
|
|
238
|
+
names.push(nextName);
|
|
239
|
+
handledNames?.add(nextName);
|
|
240
|
+
results.push({
|
|
241
|
+
original,
|
|
242
|
+
fileName: nextName,
|
|
243
|
+
source,
|
|
244
|
+
optimized,
|
|
245
|
+
asset: output,
|
|
246
|
+
moved
|
|
247
|
+
});
|
|
207
248
|
replaceAssetReferences(bundle, previous, nextName, sourcemap);
|
|
249
|
+
try {
|
|
250
|
+
bundle[nextName] = output;
|
|
251
|
+
if (bundle[nextName] === output && nextName !== previous) delete bundle[previous];
|
|
252
|
+
} catch {}
|
|
253
|
+
}
|
|
254
|
+
return {
|
|
255
|
+
sheets,
|
|
256
|
+
names,
|
|
257
|
+
results
|
|
258
|
+
};
|
|
259
|
+
};
|
|
260
|
+
/** Text outputs a stylesheet's name can appear in. Fonts and images are skipped unread. */
|
|
261
|
+
const REFERENCING_EXTENSIONS = /\.(?:[cm]?js|html?|css|json|txt|map|webmanifest|svg|xml)$/i;
|
|
262
|
+
const CHUNK_EXTENSIONS = /\.[cm]?js$/i;
|
|
263
|
+
/**
|
|
264
|
+
* Rewrite one written file the way `replaceChunkReference` rewrites a chunk in memory.
|
|
265
|
+
*
|
|
266
|
+
* A chunk with a sourcemap — a sibling `.map`, or one inlined — has its mappings carried
|
|
267
|
+
* across the edit: the replacement changes the length of a line, and every mapping after it
|
|
268
|
+
* on that line would otherwise be off by the difference.
|
|
269
|
+
*/
|
|
270
|
+
const replaceFileReference = (path, previous, next) => {
|
|
271
|
+
const code = readFileSync(path, "utf8");
|
|
272
|
+
if (!code.includes(previous)) return false;
|
|
273
|
+
if (!CHUNK_EXTENSIONS.test(path)) {
|
|
274
|
+
writeFileSync(path, code.replaceAll(previous, next));
|
|
275
|
+
return true;
|
|
276
|
+
}
|
|
277
|
+
const magic = new MagicString(code);
|
|
278
|
+
let index = code.indexOf(previous);
|
|
279
|
+
while (index !== -1) {
|
|
280
|
+
magic.overwrite(index, index + previous.length, next);
|
|
281
|
+
index = code.indexOf(previous, index + previous.length);
|
|
282
|
+
}
|
|
283
|
+
let rewritten = magic.toString();
|
|
284
|
+
const inlineMap = code.match(INLINE_SOURCE_MAP)?.[0];
|
|
285
|
+
const mapPath = `${path}.map`;
|
|
286
|
+
const rawMap = inlineMap ? JSON.parse(Buffer.from(inlineMap.slice(inlineMap.indexOf("base64,") + 7), "base64").toString()) : existsSync(mapPath) ? JSON.parse(readFileSync(mapPath, "utf8")) : void 0;
|
|
287
|
+
if (rawMap) {
|
|
288
|
+
const combined = remapping([magic.generateMap({
|
|
289
|
+
source: basename(path),
|
|
290
|
+
hires: "boundary"
|
|
291
|
+
}), rawMap], () => null);
|
|
292
|
+
if (rawMap.file) combined.file = rawMap.file;
|
|
293
|
+
if (rawMap.debugId) combined.debugId = rawMap.debugId;
|
|
294
|
+
if (inlineMap) rewritten = rewritten.replace(INLINE_SOURCE_MAP, "") + `\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,${Buffer.from(combined.toString()).toString("base64")}`;
|
|
295
|
+
else writeFileSync(mapPath, combined.toString());
|
|
296
|
+
}
|
|
297
|
+
writeFileSync(path, rewritten);
|
|
298
|
+
return true;
|
|
299
|
+
};
|
|
300
|
+
/**
|
|
301
|
+
* Prune every deferred sheet against the whole run's reachability, on disk.
|
|
302
|
+
*
|
|
303
|
+
* From the *unpruned* source, not from the file: the file was pruned against a partial run and
|
|
304
|
+
* may lack a rule a later environment reaches, and pruning cannot put a rule back. When the
|
|
305
|
+
* final bytes are the provisional bytes — the common case, since a later environment usually
|
|
306
|
+
* reaches nothing new — nothing on disk moves and every recorded name stays right. When they
|
|
307
|
+
* differ, the same contract as `optimizeStaticCssAssets` applies: the bytes and the name move
|
|
308
|
+
* together, every written reference moves with them across environments, and a copy of the
|
|
309
|
+
* provisional sheet a framework wrote into another output is replaced the same way.
|
|
310
|
+
*/
|
|
311
|
+
const finalizeDeferredSheets = (sheets, session, options) => {
|
|
312
|
+
const { requiredClasses, prune = true, outputs, bundle, sourcemap = session.sourcemap } = options;
|
|
313
|
+
const finalized = [];
|
|
314
|
+
for (const sheet of sheets) {
|
|
315
|
+
if (!existsSync(join(sheet.dir, sheet.fileName))) continue;
|
|
316
|
+
let final = pruneStaticCss(sheet.source, session, {
|
|
317
|
+
prune,
|
|
318
|
+
requiredClasses
|
|
319
|
+
});
|
|
320
|
+
if (sheet.moved?.size) final = splitStaticCss(final, session, new Map([...sheet.moved].map((className) => [className, ""]))).css;
|
|
321
|
+
if (!prune || final === sheet.provisional) {
|
|
322
|
+
finalized.push({
|
|
323
|
+
...sheet,
|
|
324
|
+
before: sheet.provisional.length,
|
|
325
|
+
after: sheet.provisional.length
|
|
326
|
+
});
|
|
327
|
+
continue;
|
|
328
|
+
}
|
|
329
|
+
const nextName = sheet.originalFileName.replace(/\.css$/, `.b-${toHash(final)}.css`);
|
|
330
|
+
const directories = new Set([sheet.dir]);
|
|
331
|
+
for (const output of outputs) directories.add(output.dir);
|
|
332
|
+
for (const dir of directories) {
|
|
333
|
+
const copy = join(dir, sheet.fileName);
|
|
334
|
+
if (!existsSync(copy)) continue;
|
|
335
|
+
if (dir !== sheet.dir && readFileSync(copy, "utf8") !== sheet.provisional) continue;
|
|
336
|
+
writeFileSync(join(dir, nextName), final);
|
|
337
|
+
rmSync(copy, { force: true });
|
|
338
|
+
}
|
|
339
|
+
const seen = /* @__PURE__ */ new Set();
|
|
340
|
+
for (const output of outputs) for (const file of output.files) {
|
|
341
|
+
if (!REFERENCING_EXTENSIONS.test(file)) continue;
|
|
342
|
+
const target = join(output.dir, file);
|
|
343
|
+
if (seen.has(target) || file === sheet.fileName) continue;
|
|
344
|
+
seen.add(target);
|
|
345
|
+
if (!existsSync(target)) continue;
|
|
346
|
+
replaceFileReference(target, sheet.fileName, nextName);
|
|
347
|
+
}
|
|
348
|
+
if (sheet.asset) {
|
|
349
|
+
sheet.asset.source = final;
|
|
350
|
+
sheet.asset.fileName = nextName;
|
|
351
|
+
if (sheet.bundle) {
|
|
352
|
+
try {
|
|
353
|
+
sheet.bundle[nextName] = sheet.asset;
|
|
354
|
+
if (sheet.bundle[nextName] === sheet.asset) delete sheet.bundle[sheet.fileName];
|
|
355
|
+
} catch {}
|
|
356
|
+
replaceAssetReferences(sheet.bundle, sheet.fileName, nextName, sheet.sourcemap);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
if (bundle) replaceAssetReferences(bundle, sheet.fileName, nextName, sourcemap);
|
|
360
|
+
finalized.push({
|
|
361
|
+
...sheet,
|
|
362
|
+
renamed: nextName,
|
|
363
|
+
before: sheet.provisional.length,
|
|
364
|
+
after: final.length
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
return finalized;
|
|
368
|
+
};
|
|
369
|
+
/** The at-rules a rule sits under, outermost first, as name and params. */
|
|
370
|
+
const ancestryOf = (rule) => {
|
|
371
|
+
const chain = [];
|
|
372
|
+
let parent = rule.parent;
|
|
373
|
+
while (parent && parent.type !== "root") {
|
|
374
|
+
if (parent.type === "atrule") {
|
|
375
|
+
const atRule = parent;
|
|
376
|
+
chain.unshift({
|
|
377
|
+
name: atRule.name,
|
|
378
|
+
params: atRule.params
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
parent = parent.parent;
|
|
382
|
+
}
|
|
383
|
+
return chain;
|
|
384
|
+
};
|
|
385
|
+
/** The container in `root` under the same at-rule chain, created where absent. */
|
|
386
|
+
const containerFor = (root, chain) => {
|
|
387
|
+
let container = root;
|
|
388
|
+
for (const { name, params } of chain) {
|
|
389
|
+
let next = container.nodes?.find((node) => node.type === "atrule" && node.name === name && node.params === params);
|
|
390
|
+
if (!next) {
|
|
391
|
+
next = postcss.atRule({
|
|
392
|
+
name,
|
|
393
|
+
params,
|
|
394
|
+
nodes: []
|
|
395
|
+
});
|
|
396
|
+
container.append(next);
|
|
397
|
+
}
|
|
398
|
+
container = next;
|
|
399
|
+
}
|
|
400
|
+
return container;
|
|
401
|
+
};
|
|
402
|
+
/**
|
|
403
|
+
* Move every utility rule a lazily loaded chunk owns into a sheet of that chunk's own.
|
|
404
|
+
*
|
|
405
|
+
* Reads the finished entry sheet — pruned, sublayered, minified or not — and walks its
|
|
406
|
+
* utility rules. A selector naming exactly one class that `ownership` assigns to a chunk is
|
|
407
|
+
* moved to that chunk's sheet under the same at-rule chain: the utilities layer, its sublayer,
|
|
408
|
+
* any media or container query. A rule with several selectors is split per selector, since a
|
|
409
|
+
* merged rule's members can belong to different chunks. Whatever nothing owns stays.
|
|
410
|
+
*
|
|
411
|
+
* Each chunk sheet opens with the entry's sublayer order statement, so whichever sheet the
|
|
412
|
+
* document happens to parse first establishes the same order. That is what makes the split
|
|
413
|
+
* safe at all: precedence lives in the sublayers, not in where a rule sits.
|
|
414
|
+
*/
|
|
415
|
+
const splitStaticCss = (css, session, ownership) => {
|
|
416
|
+
const chunks = /* @__PURE__ */ new Map();
|
|
417
|
+
const moved = /* @__PURE__ */ new Set();
|
|
418
|
+
if (!ownership.size || !css.includes("--made-with-bamboo")) return {
|
|
419
|
+
css,
|
|
420
|
+
chunks,
|
|
421
|
+
moved
|
|
422
|
+
};
|
|
423
|
+
const root = postcss.parse(css);
|
|
424
|
+
const roots = /* @__PURE__ */ new Map();
|
|
425
|
+
const rootFor = (chunk) => {
|
|
426
|
+
let chunkRoot = roots.get(chunk);
|
|
427
|
+
if (!chunkRoot) {
|
|
428
|
+
chunkRoot = postcss.root();
|
|
429
|
+
roots.set(chunk, chunkRoot);
|
|
430
|
+
}
|
|
431
|
+
return chunkRoot;
|
|
432
|
+
};
|
|
433
|
+
const isUtilityRule = (rule) => {
|
|
434
|
+
let parent = rule.parent;
|
|
435
|
+
while (parent) {
|
|
436
|
+
if (parent.type === "atrule") {
|
|
437
|
+
const atRule = parent;
|
|
438
|
+
if (atRule.name === "layer" && atRule.params === session.utilityLayer) return true;
|
|
439
|
+
}
|
|
440
|
+
parent = parent.parent;
|
|
441
|
+
}
|
|
442
|
+
return false;
|
|
443
|
+
};
|
|
444
|
+
let order;
|
|
445
|
+
root.walkAtRules("layer", (atRule) => {
|
|
446
|
+
if (order || atRule.nodes) return;
|
|
447
|
+
const parent = atRule.parent;
|
|
448
|
+
if (parent?.type === "atrule" && parent.params === session.utilityLayer) order = atRule;
|
|
449
|
+
});
|
|
450
|
+
root.walkRules((rule) => {
|
|
451
|
+
if (!isUtilityRule(rule)) return;
|
|
452
|
+
const kept = [];
|
|
453
|
+
const taken = /* @__PURE__ */ new Map();
|
|
454
|
+
for (const selector of rule.selectors) {
|
|
455
|
+
let owner;
|
|
456
|
+
try {
|
|
457
|
+
selectorParser((selectors) => {
|
|
458
|
+
const classes = /* @__PURE__ */ new Set();
|
|
459
|
+
selectors.walkClasses((classNode) => {
|
|
460
|
+
classes.add(bare(classNode.toString().slice(1)));
|
|
461
|
+
});
|
|
462
|
+
if (classes.size !== 1) return;
|
|
463
|
+
const [className] = classes;
|
|
464
|
+
owner = ownership.get(className);
|
|
465
|
+
if (owner !== void 0) moved.add(className);
|
|
466
|
+
}).processSync(selector);
|
|
467
|
+
} catch {}
|
|
468
|
+
if (owner === void 0) kept.push(selector);
|
|
469
|
+
else (taken.get(owner) ?? taken.set(owner, []).get(owner)).push(selector);
|
|
470
|
+
}
|
|
471
|
+
if (!taken.size) return;
|
|
472
|
+
const chain = ancestryOf(rule);
|
|
473
|
+
for (const [chunk, selectors] of taken) containerFor(rootFor(chunk), chain).append(rule.clone({ selectors }));
|
|
474
|
+
if (kept.length) rule.selectors = kept;
|
|
475
|
+
else rule.remove();
|
|
476
|
+
});
|
|
477
|
+
let removed = true;
|
|
478
|
+
while (removed) {
|
|
479
|
+
removed = false;
|
|
480
|
+
root.walkAtRules((atRule) => {
|
|
481
|
+
if (atRule.nodes?.length !== 0) return;
|
|
482
|
+
atRule.remove();
|
|
483
|
+
removed = true;
|
|
484
|
+
});
|
|
208
485
|
}
|
|
209
|
-
|
|
486
|
+
for (const [chunk, chunkRoot] of roots) {
|
|
487
|
+
if (order) chunkRoot.nodes.find((node) => node.type === "atrule" && node.name === "layer" && node.params === session.utilityLayer)?.prepend(order.clone());
|
|
488
|
+
chunks.set(chunk, chunkRoot.toString());
|
|
489
|
+
}
|
|
490
|
+
return {
|
|
491
|
+
css: root.toString(),
|
|
492
|
+
chunks,
|
|
493
|
+
moved
|
|
494
|
+
};
|
|
495
|
+
};
|
|
496
|
+
/** A class token of a selector, escapes and all: `.hover\\:c_red600` up to its unescaped `:`. */
|
|
497
|
+
const CLASS_TOKEN = /\.((?:\\.|[^\\\s.:>+~[\](),])+)/g;
|
|
498
|
+
/**
|
|
499
|
+
* The top-level comma-separated parts of a selector list as written, each with its offset.
|
|
500
|
+
*
|
|
501
|
+
* `rule.selectors` splits the same way but loses where each part sits, and a merged rule's
|
|
502
|
+
* selectors sit on separate lines in the unminified sheet a dev server serves.
|
|
503
|
+
*/
|
|
504
|
+
const selectorParts = (raw) => {
|
|
505
|
+
const parts = [];
|
|
506
|
+
let depth = 0;
|
|
507
|
+
let start = 0;
|
|
508
|
+
for (let index = 0; index < raw.length; index++) {
|
|
509
|
+
const char = raw[index];
|
|
510
|
+
if (char === "\\") index++;
|
|
511
|
+
else if (char === "(" || char === "[") depth++;
|
|
512
|
+
else if (char === ")" || char === "]") depth--;
|
|
513
|
+
else if (char === "," && depth === 0) {
|
|
514
|
+
parts.push({
|
|
515
|
+
text: raw.slice(start, index),
|
|
516
|
+
offset: start
|
|
517
|
+
});
|
|
518
|
+
start = index + 1;
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
parts.push({
|
|
522
|
+
text: raw.slice(start),
|
|
523
|
+
offset: start
|
|
524
|
+
});
|
|
525
|
+
return parts.map((part) => {
|
|
526
|
+
const leading = part.text.length - part.text.trimStart().length;
|
|
527
|
+
return {
|
|
528
|
+
text: part.text.trim(),
|
|
529
|
+
offset: part.offset + leading
|
|
530
|
+
};
|
|
531
|
+
});
|
|
532
|
+
};
|
|
533
|
+
/** `start` advanced over `text` up to `offset`, in 1-based lines and columns. */
|
|
534
|
+
const positionAt = (text, offset, start) => {
|
|
535
|
+
let { line, column } = start;
|
|
536
|
+
for (let index = 0; index < offset; index++) if (text[index] === "\n") {
|
|
537
|
+
line++;
|
|
538
|
+
column = 1;
|
|
539
|
+
} else column++;
|
|
540
|
+
return {
|
|
541
|
+
line,
|
|
542
|
+
column
|
|
543
|
+
};
|
|
544
|
+
};
|
|
545
|
+
/**
|
|
546
|
+
* A source map from each rule of the served stylesheet to the call site its atom was first
|
|
547
|
+
* encoded at, for DevTools to name the file and line a rule came from.
|
|
548
|
+
*
|
|
549
|
+
* Read off the finished sheet rather than threaded through its generation: rules enter the
|
|
550
|
+
* postcss tree as strings, which strips their positions, and the optimizer re-parses the text
|
|
551
|
+
* twice more. One parse here costs the same as one of those and needs no cooperation from
|
|
552
|
+
* either. A rule maps at its selector, and a merged rule maps each of its selectors, since
|
|
553
|
+
* the optimizer folds rules from different call sites into one. `sourcesContent` is left for
|
|
554
|
+
* Vite to fill from disk, which it does for a dev stylesheet's map before inlining it.
|
|
555
|
+
*/
|
|
556
|
+
const cssSourceMap = (css, origins) => {
|
|
557
|
+
const byBareClass = /* @__PURE__ */ new Map();
|
|
558
|
+
for (const [className, origin] of origins) {
|
|
559
|
+
const name = bare(className);
|
|
560
|
+
if (!byBareClass.has(name)) byBareClass.set(name, origin);
|
|
561
|
+
}
|
|
562
|
+
if (!byBareClass.size) return void 0;
|
|
563
|
+
const originOf = (selector) => {
|
|
564
|
+
for (const match of selector.matchAll(CLASS_TOKEN)) {
|
|
565
|
+
const origin = byBareClass.get(bare(match[1]));
|
|
566
|
+
if (origin) return origin;
|
|
567
|
+
}
|
|
568
|
+
};
|
|
569
|
+
const map = new GenMapping();
|
|
570
|
+
let mapped = 0;
|
|
571
|
+
postcss.parse(css).walkRules((rule) => {
|
|
572
|
+
const start = rule.source?.start;
|
|
573
|
+
if (!start) return;
|
|
574
|
+
const raw = rule.raws.selector?.raw ?? rule.selector;
|
|
575
|
+
for (const part of selectorParts(raw)) {
|
|
576
|
+
const origin = originOf(part.text);
|
|
577
|
+
if (!origin) continue;
|
|
578
|
+
const generated = positionAt(raw, part.offset, start);
|
|
579
|
+
addMapping(map, {
|
|
580
|
+
generated: {
|
|
581
|
+
line: generated.line,
|
|
582
|
+
column: generated.column - 1
|
|
583
|
+
},
|
|
584
|
+
source: origin.filePath,
|
|
585
|
+
original: {
|
|
586
|
+
line: origin.line,
|
|
587
|
+
column: origin.column - 1
|
|
588
|
+
}
|
|
589
|
+
});
|
|
590
|
+
mapped++;
|
|
591
|
+
}
|
|
592
|
+
});
|
|
593
|
+
if (!mapped) return void 0;
|
|
594
|
+
const encoded = toEncodedMap(map);
|
|
595
|
+
return {
|
|
596
|
+
version: 3,
|
|
597
|
+
mappings: encoded.mappings,
|
|
598
|
+
names: [...encoded.names],
|
|
599
|
+
sources: encoded.sources.map((source) => source ?? "")
|
|
600
|
+
};
|
|
210
601
|
};
|
|
211
602
|
//#endregion
|
|
212
|
-
export { containsGeneratedCssAsset, optimizeStaticCssAssets, pruneStaticCss };
|
|
603
|
+
export { containsGeneratedCssAsset, cssSourceMap, finalizeDeferredSheets, optimizeStaticCssAssets, pruneStaticCss, splitStaticCss };
|
package/dist/fold-module.cjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const require_chunk = require("./chunk.cjs");
|
|
2
|
+
let node_path = require("node:path");
|
|
2
3
|
let _bamboocss_shared = require("@bamboocss/shared");
|
|
3
4
|
let node_crypto = require("node:crypto");
|
|
4
|
-
let node_path = require("node:path");
|
|
5
5
|
let magic_string = require("magic-string");
|
|
6
6
|
magic_string = require_chunk.__toESM(magic_string);
|
|
7
7
|
let _bamboocss_config_ts_path = require("@bamboocss/config/ts-path");
|
package/dist/fold-module.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { dirname, relative, resolve } from "node:path";
|
|
1
2
|
import { compact, createCssUncached, createMergeCss, memo, viewTransitionClassName } from "@bamboocss/shared";
|
|
2
3
|
import { createHash } from "node:crypto";
|
|
3
|
-
import { dirname, relative, resolve } from "node:path";
|
|
4
4
|
import MagicString from "magic-string";
|
|
5
5
|
import { resolveTsPathPattern } from "@bamboocss/config/ts-path";
|
|
6
6
|
import { box, maybeBoxNode } from "@bamboocss/extractor";
|