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