@fastkit/plugboy 1.2.2 → 1.4.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/README.md +108 -0
- package/dist/cli.mjs +2 -2
- package/dist/plugboy.d.mts +87 -3
- package/dist/plugboy.mjs +1 -1
- package/dist/{workspace-B66AR1T-.mjs → workspace-B6BoRqWL.mjs} +297 -60
- package/dist/workspace-B6BoRqWL.mjs.map +1 -0
- package/package.json +1 -1
- package/dist/workspace-B66AR1T-.mjs.map +0 -1
|
@@ -79,7 +79,8 @@ const TSDOWN_SYNC_OPTIONS = [
|
|
|
79
79
|
"skipNodeModulesBundle",
|
|
80
80
|
"onSuccess",
|
|
81
81
|
"copy",
|
|
82
|
-
"deps"
|
|
82
|
+
"deps",
|
|
83
|
+
"target"
|
|
83
84
|
];
|
|
84
85
|
//#endregion
|
|
85
86
|
//#region src/types/project.ts
|
|
@@ -453,7 +454,7 @@ function isProjectPackageJson(json) {
|
|
|
453
454
|
return !!json.private && PROJECT_REQUIRED_FIELDS.every((filed) => !!json[filed]);
|
|
454
455
|
}
|
|
455
456
|
async function resolveUserProjectConfig(userConfig) {
|
|
456
|
-
const { workspacesDir = "packages", scripts = [], peerDependencies = {}, tsconfig, readme = (json) => `# ${json.name}\n`, plugins, optimizeCSS = true, hooks } = userConfig;
|
|
457
|
+
const { workspacesDir = "packages", scripts = [], peerDependencies = {}, tsconfig, readme = (json) => `# ${json.name}\n`, plugins, optimizeCSS = true, hooks, target, css } = userConfig;
|
|
457
458
|
return {
|
|
458
459
|
workspacesDir,
|
|
459
460
|
scripts: Array.isArray(scripts) ? scripts : [{
|
|
@@ -465,7 +466,9 @@ async function resolveUserProjectConfig(userConfig) {
|
|
|
465
466
|
readme,
|
|
466
467
|
plugins: await resolveUserPluginOption(plugins),
|
|
467
468
|
optimizeCSS: optimizeCSS === true ? {} : optimizeCSS,
|
|
468
|
-
hooks
|
|
469
|
+
hooks,
|
|
470
|
+
target,
|
|
471
|
+
css
|
|
469
472
|
};
|
|
470
473
|
}
|
|
471
474
|
function defineProjectConfig(config) {
|
|
@@ -1054,6 +1057,38 @@ async function getProject(searchDir, allowMissing, skipLoadConfig) {
|
|
|
1054
1057
|
});
|
|
1055
1058
|
}
|
|
1056
1059
|
//#endregion
|
|
1060
|
+
//#region src/workspace/stylesheets.ts
|
|
1061
|
+
/** `foo.mjs` -> `foo.css`, mirroring how `@tsdown/css` names a chunk's CSS. */
|
|
1062
|
+
function toCssFileName(jsFileName) {
|
|
1063
|
+
return jsFileName.replace(/(?:\.module)?(\.[cm]?js)$/, ".css");
|
|
1064
|
+
}
|
|
1065
|
+
/** The stylesheets a package declares: `./<entry>.css` per `css: true` entry. */
|
|
1066
|
+
function declaredStylesheets(workspace) {
|
|
1067
|
+
return new Set(workspace.exports.filter((exp) => exp.id.endsWith(".css")).map((exp) => path.posix.basename(exp.id)));
|
|
1068
|
+
}
|
|
1069
|
+
/**
|
|
1070
|
+
* Every stylesheet the build has written to `dir`, as file names.
|
|
1071
|
+
*
|
|
1072
|
+
* The bundle is not the whole story: `plugboy-assemble-entry-css` writes an
|
|
1073
|
+
* entry's stylesheet directly to disk when the build produced none for it, so a
|
|
1074
|
+
* `writeBundle` stage that only walked the bundle assets would skip exactly the
|
|
1075
|
+
* file that needed the most work. The declared exports fill that in — they are the
|
|
1076
|
+
* stylesheets the package publishes, so anything present under one of those names
|
|
1077
|
+
* belongs in the set.
|
|
1078
|
+
*/
|
|
1079
|
+
async function listEmittedStylesheets(workspace, dir, bundle) {
|
|
1080
|
+
const names = /* @__PURE__ */ new Set();
|
|
1081
|
+
for (const chunk of Object.values(bundle)) if (chunk.type === "asset" && chunk.fileName.endsWith(".css")) names.add(chunk.fileName);
|
|
1082
|
+
await Promise.all([...declaredStylesheets(workspace)].map(async (name) => {
|
|
1083
|
+
if (names.has(name)) return;
|
|
1084
|
+
try {
|
|
1085
|
+
await fs$1.access(path.join(dir, name));
|
|
1086
|
+
names.add(name);
|
|
1087
|
+
} catch {}
|
|
1088
|
+
}));
|
|
1089
|
+
return [...names];
|
|
1090
|
+
}
|
|
1091
|
+
//#endregion
|
|
1057
1092
|
//#region src/postcss/plugin.ts
|
|
1058
1093
|
async function getPostcss(options) {
|
|
1059
1094
|
const { layer, media, combineRules, cssnano } = options;
|
|
@@ -1074,38 +1109,137 @@ async function getPostcss(options) {
|
|
|
1074
1109
|
const SOURCE_MAPPING_URL_COMMENT_RE = /\/\*# sourceMappingURL=.+? \*\//g;
|
|
1075
1110
|
const allLayerDefRe = /(^|\n)@layer\s+([a-zA-Z\d\-_$. ,]+);/g;
|
|
1076
1111
|
const layerDefTrimRe = /((^|\n)@layer\s+|;)/g;
|
|
1077
|
-
async function optimizeCSS(
|
|
1112
|
+
async function optimizeCSS(css, fileName, options) {
|
|
1078
1113
|
const postcss = await getPostcss(options);
|
|
1079
|
-
function prepare(
|
|
1114
|
+
function prepare(source) {
|
|
1080
1115
|
return (() => {
|
|
1081
|
-
const matched =
|
|
1116
|
+
const matched = source.match(allLayerDefRe);
|
|
1082
1117
|
if (!matched) return "";
|
|
1083
1118
|
const layerNames = [];
|
|
1084
1119
|
matched.forEach((row) => {
|
|
1085
1120
|
row.replace(layerDefTrimRe, "").split(",").forEach((chunk) => layerNames.push(chunk.trim()));
|
|
1086
1121
|
});
|
|
1087
1122
|
return `@layer ${Array.from(new Set(layerNames)).join(", ")};\n`;
|
|
1088
|
-
})() +
|
|
1123
|
+
})() + source.replace(allLayerDefRe, "");
|
|
1089
1124
|
}
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
to: asset.fileName,
|
|
1125
|
+
return (await postcss.process(prepare(css), {
|
|
1126
|
+
from: fileName,
|
|
1127
|
+
to: fileName,
|
|
1094
1128
|
map: { inline: false }
|
|
1095
1129
|
})).css.replace(SOURCE_MAPPING_URL_COMMENT_RE, "");
|
|
1096
1130
|
}
|
|
1131
|
+
/**
|
|
1132
|
+
* Applies {@link PlugboyWorkspace.optimizeCSSOptions} to every stylesheet the
|
|
1133
|
+
* build writes.
|
|
1134
|
+
*
|
|
1135
|
+
* This runs in `writeBundle`, on the files on disk, rather than on the bundle
|
|
1136
|
+
* assets in `generateBundle` — because not every stylesheet exists as a bundle
|
|
1137
|
+
* asset by then. tsdown's own CSS pipeline emits from a *post* plugin, which
|
|
1138
|
+
* runs after every user plugin's `generateBundle`, so CSS that tsdown produces
|
|
1139
|
+
* (a plain `.css` / `.scss` import, or — since the vanilla-extract plugin routes
|
|
1140
|
+
* its `.css.ts` through tsdown — extracted CSS) used to skip these
|
|
1141
|
+
* optimizations entirely, while CSS a plugin emitted itself received them. By
|
|
1142
|
+
* `writeBundle` every producer has finished and the whole set is on disk.
|
|
1143
|
+
*
|
|
1144
|
+
* `preserve-css-imports` re-injects external `@import`s in its own
|
|
1145
|
+
* `writeBundle`; it is registered after this plugin, so it always sees the
|
|
1146
|
+
* optimized file.
|
|
1147
|
+
*/
|
|
1097
1148
|
function OptimizeCSSPlugin(workspace) {
|
|
1149
|
+
const processed = /* @__PURE__ */ new Set();
|
|
1098
1150
|
return {
|
|
1099
1151
|
name: "plugboy-optimize-css",
|
|
1100
|
-
|
|
1152
|
+
buildStart() {
|
|
1153
|
+
processed.clear();
|
|
1154
|
+
},
|
|
1155
|
+
async writeBundle(options, bundle) {
|
|
1101
1156
|
const { optimizeCSSOptions } = workspace;
|
|
1102
1157
|
if (!optimizeCSSOptions) return;
|
|
1158
|
+
const { dir } = options;
|
|
1159
|
+
if (!dir) return;
|
|
1160
|
+
const stylesheets = await listEmittedStylesheets(workspace, dir, bundle);
|
|
1161
|
+
await Promise.all(stylesheets.map(async (fileName) => {
|
|
1162
|
+
const filePath = path.join(dir, fileName);
|
|
1163
|
+
if (processed.has(filePath)) return;
|
|
1164
|
+
let css;
|
|
1165
|
+
try {
|
|
1166
|
+
css = await fs$1.readFile(filePath, "utf8");
|
|
1167
|
+
} catch {
|
|
1168
|
+
return;
|
|
1169
|
+
}
|
|
1170
|
+
processed.add(filePath);
|
|
1171
|
+
const optimized = await optimizeCSS(css, fileName, optimizeCSSOptions);
|
|
1172
|
+
if (optimized !== css) await fs$1.writeFile(filePath, optimized);
|
|
1173
|
+
}));
|
|
1174
|
+
}
|
|
1175
|
+
};
|
|
1176
|
+
}
|
|
1177
|
+
//#endregion
|
|
1178
|
+
//#region src/workspace/plugins/assemble-entry-css.ts
|
|
1179
|
+
function createAssembleEntryCssPlugin(workspace) {
|
|
1180
|
+
/** Chunk file name -> its identity and static imports, as of `generateBundle`. */
|
|
1181
|
+
const graph = /* @__PURE__ */ new Map();
|
|
1182
|
+
return definePlugin({
|
|
1183
|
+
name: "plugboy-assemble-entry-css",
|
|
1184
|
+
buildStart() {
|
|
1185
|
+
graph.clear();
|
|
1186
|
+
},
|
|
1187
|
+
generateBundle(_options, bundle) {
|
|
1103
1188
|
for (const chunk of Object.values(bundle)) {
|
|
1104
|
-
if (chunk.type !== "
|
|
1105
|
-
|
|
1189
|
+
if (chunk.type !== "chunk") continue;
|
|
1190
|
+
graph.set(chunk.fileName, {
|
|
1191
|
+
name: chunk.name,
|
|
1192
|
+
isEntry: chunk.isEntry,
|
|
1193
|
+
imports: [...chunk.imports]
|
|
1194
|
+
});
|
|
1106
1195
|
}
|
|
1196
|
+
},
|
|
1197
|
+
async writeBundle(options, bundle) {
|
|
1198
|
+
const { dir } = options;
|
|
1199
|
+
if (!dir) return;
|
|
1200
|
+
if (workspace.cssOptions?.inject) return;
|
|
1201
|
+
const targets = declaredStylesheets(workspace);
|
|
1202
|
+
if (!targets.size) return;
|
|
1203
|
+
const emitted = new Set(Object.values(bundle).filter((chunk) => chunk.type === "asset" && chunk.fileName.endsWith(".css")).map((chunk) => chunk.fileName));
|
|
1204
|
+
if (!emitted.size) return;
|
|
1205
|
+
/** The stylesheet a chunk owns, if the build emitted one. */
|
|
1206
|
+
const cssOf = (fileName) => {
|
|
1207
|
+
const css = toCssFileName(fileName);
|
|
1208
|
+
return css !== fileName && emitted.has(css) ? css : void 0;
|
|
1209
|
+
};
|
|
1210
|
+
/** Stylesheets an entry needs, dependencies first, each listed once. */
|
|
1211
|
+
const collect = (entryFileName) => {
|
|
1212
|
+
const visited = /* @__PURE__ */ new Set();
|
|
1213
|
+
const ordered = [];
|
|
1214
|
+
const walk = (fileName) => {
|
|
1215
|
+
if (visited.has(fileName)) return;
|
|
1216
|
+
visited.add(fileName);
|
|
1217
|
+
const node = graph.get(fileName);
|
|
1218
|
+
if (!node) return;
|
|
1219
|
+
for (const imported of node.imports) walk(imported);
|
|
1220
|
+
const css = cssOf(fileName);
|
|
1221
|
+
if (css && !ordered.includes(css)) ordered.push(css);
|
|
1222
|
+
};
|
|
1223
|
+
walk(entryFileName);
|
|
1224
|
+
return ordered;
|
|
1225
|
+
};
|
|
1226
|
+
const folded = /* @__PURE__ */ new Set();
|
|
1227
|
+
await Promise.all([...graph].map(async ([fileName, node]) => {
|
|
1228
|
+
if (!node.isEntry) return;
|
|
1229
|
+
const target = `${node.name}.css`;
|
|
1230
|
+
if (!targets.has(target)) return;
|
|
1231
|
+
const sources = collect(fileName);
|
|
1232
|
+
if (!sources.length) return;
|
|
1233
|
+
sources.forEach((source) => folded.add(source));
|
|
1234
|
+
if (sources.length === 1 && sources[0] === target) return;
|
|
1235
|
+
const css = (await Promise.all(sources.map((source) => fs$1.readFile(path.join(dir, source), "utf8").catch(() => "")))).filter(Boolean).join("\n");
|
|
1236
|
+
if (!css) return;
|
|
1237
|
+
await fs$1.writeFile(path.join(dir, target), css);
|
|
1238
|
+
folded.add(target);
|
|
1239
|
+
}));
|
|
1240
|
+
await Promise.all([...folded].filter((css) => !targets.has(css)).map((css) => fs$1.rm(path.join(dir, css), { force: true })));
|
|
1107
1241
|
}
|
|
1108
|
-
};
|
|
1242
|
+
});
|
|
1109
1243
|
}
|
|
1110
1244
|
//#endregion
|
|
1111
1245
|
//#region src/workspace/plugins/raw-loader.ts
|
|
@@ -1131,20 +1265,34 @@ const rawLoaderPlugin = {
|
|
|
1131
1265
|
//#endregion
|
|
1132
1266
|
//#region src/workspace/plugins/preserve-css-imports.ts
|
|
1133
1267
|
/**
|
|
1134
|
-
* Plugin to preserve
|
|
1268
|
+
* Plugin to preserve what tsdown's CSS pipeline would rewrite away at the top of
|
|
1269
|
+
* a stylesheet: external `@import` statements and the authored `@layer` order.
|
|
1135
1270
|
*
|
|
1136
|
-
* rolldown / tsdown's CSS pipeline (lightningcss)
|
|
1137
|
-
* `@import` it can. For bare package specifiers (e.g.
|
|
1271
|
+
* **External `@import`s.** rolldown / tsdown's CSS pipeline (lightningcss)
|
|
1272
|
+
* resolves and inlines every `@import` it can. For bare package specifiers (e.g.
|
|
1138
1273
|
* `@import url('material-symbols/rounded.css') layer(...)`) that is wrong for a
|
|
1139
1274
|
* library build: it bloats the output and rebases the imported package's own
|
|
1140
1275
|
* relative asset URLs (fonts) against our `dist`, breaking them. Such imports
|
|
1141
1276
|
* should stay external so the consumer's bundler resolves them.
|
|
1142
1277
|
*
|
|
1143
|
-
*
|
|
1144
|
-
*
|
|
1145
|
-
*
|
|
1146
|
-
*
|
|
1147
|
-
*
|
|
1278
|
+
* **Layer order.** lightningcss drops a name from an `@layer a, b, c;` statement
|
|
1279
|
+
* when a block for it follows in the same stylesheet, since the block establishes
|
|
1280
|
+
* the same order. That holds for a standalone document, but not for a library
|
|
1281
|
+
* stylesheet whose statement also orders layers belonging to *other* packages:
|
|
1282
|
+
* once the name is gone, its position is decided by wherever its block happens to
|
|
1283
|
+
* land relative to those, and the authored order is lost. `@fastkit/vui` declares
|
|
1284
|
+
* `@layer vui-normalize, vui-color-scheme, …, vui;`, and losing `vui-normalize`
|
|
1285
|
+
* from it promoted the reset layer above the packages it is supposed to lose to.
|
|
1286
|
+
*
|
|
1287
|
+
* Both are captured from a `transform` hook declared `order: 'pre'`, which runs
|
|
1288
|
+
* ahead of tsdown's CSS handling even though that is registered as a *pre plugin*
|
|
1289
|
+
* — hook order wins over plugin order. It is the only point that sees the CSS of
|
|
1290
|
+
* **every** stylesheet in the graph, including a virtual one another plugin
|
|
1291
|
+
* supplies from `load`: vanilla-extract generates its `@layer` statements into
|
|
1292
|
+
* such a module, so a `load`-based capture would miss exactly the case where the
|
|
1293
|
+
* generated statement is the only record of the intended order. The captured
|
|
1294
|
+
* values are re-emitted in `writeBundle`, after every CSS producer has written
|
|
1295
|
+
* its final file to disk.
|
|
1148
1296
|
*/
|
|
1149
1297
|
/**
|
|
1150
1298
|
* Matches a single `@import` statement, capturing the quote (group 1) and the
|
|
@@ -1162,47 +1310,133 @@ function isInternalImportSpecifier(spec) {
|
|
|
1162
1310
|
}
|
|
1163
1311
|
/** Matches a top-level `@layer <names>;` statement (declaration, not a block). */
|
|
1164
1312
|
const LAYER_STATEMENT_RE = /@layer\s+([^{};]+);[ \t]*\n?/g;
|
|
1165
|
-
|
|
1313
|
+
/** Stylesheet ids, with any query (`?source=…`, `?inline`) still attached. */
|
|
1314
|
+
const STYLE_ID_RE = /\.(?:css|scss|sass|less|styl|stylus)(?:$|\?)/;
|
|
1315
|
+
/** The layer names a stylesheet declares, in the order it declares them. */
|
|
1316
|
+
function collectLayerNames(css) {
|
|
1317
|
+
const names = [];
|
|
1318
|
+
for (const [, group] of css.matchAll(LAYER_STATEMENT_RE)) for (const name of group.split(",")) {
|
|
1319
|
+
const trimmed = name.trim();
|
|
1320
|
+
if (trimmed && !names.includes(trimmed)) names.push(trimmed);
|
|
1321
|
+
}
|
|
1322
|
+
return names;
|
|
1323
|
+
}
|
|
1324
|
+
/**
|
|
1325
|
+
* Merge several declaration orders into one that contradicts none of them.
|
|
1326
|
+
*
|
|
1327
|
+
* Concatenating them and dropping repeats does not work, because a name's first
|
|
1328
|
+
* appearance is rarely where its order is decided: vanilla-extract re-declares a
|
|
1329
|
+
* layer at the top of *every* stylesheet that puts a rule in it, so a single
|
|
1330
|
+
* `@layer that-one;` from some component is seen before the module that declares
|
|
1331
|
+
* how all the layers relate — and once the component's name is in the list, the
|
|
1332
|
+
* declaring module's order is silently dropped for it.
|
|
1333
|
+
*
|
|
1334
|
+
* Each sequence is therefore read as a set of "must come before" constraints and
|
|
1335
|
+
* the result is a topological sort of them, preferring the earliest-seen name when
|
|
1336
|
+
* several are free. Earlier sequences win: a constraint that would contradict one
|
|
1337
|
+
* already recorded is skipped, so a stylesheet's own surviving statement — whose
|
|
1338
|
+
* order tsdown may have rewritten — can add names without reordering anything.
|
|
1339
|
+
*/
|
|
1340
|
+
function mergeLayerOrder(sequences) {
|
|
1341
|
+
const nodes = [];
|
|
1342
|
+
const next = /* @__PURE__ */ new Map();
|
|
1343
|
+
const add = (name) => {
|
|
1344
|
+
if (next.has(name)) return;
|
|
1345
|
+
nodes.push(name);
|
|
1346
|
+
next.set(name, /* @__PURE__ */ new Set());
|
|
1347
|
+
};
|
|
1348
|
+
/** Whether `to` already has to come after `from`. */
|
|
1349
|
+
const precedes = (from, to) => {
|
|
1350
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1351
|
+
const stack = [from];
|
|
1352
|
+
while (stack.length) {
|
|
1353
|
+
const current = stack.pop();
|
|
1354
|
+
if (current === to) return true;
|
|
1355
|
+
if (seen.has(current)) continue;
|
|
1356
|
+
seen.add(current);
|
|
1357
|
+
stack.push(...next.get(current) ?? []);
|
|
1358
|
+
}
|
|
1359
|
+
return false;
|
|
1360
|
+
};
|
|
1361
|
+
for (const sequence of sequences) {
|
|
1362
|
+
sequence.forEach(add);
|
|
1363
|
+
for (let i = 0; i + 1 < sequence.length; i++) {
|
|
1364
|
+
const from = sequence[i];
|
|
1365
|
+
const to = sequence[i + 1];
|
|
1366
|
+
if (from === to || precedes(to, from)) continue;
|
|
1367
|
+
next.get(from).add(to);
|
|
1368
|
+
}
|
|
1369
|
+
}
|
|
1370
|
+
const incoming = new Map(nodes.map((name) => [name, 0]));
|
|
1371
|
+
for (const [, targets] of next) for (const target of targets) incoming.set(target, (incoming.get(target) ?? 0) + 1);
|
|
1372
|
+
const remaining = new Set(nodes);
|
|
1373
|
+
const merged = [];
|
|
1374
|
+
while (remaining.size) {
|
|
1375
|
+
const name = nodes.find((it) => remaining.has(it) && incoming.get(it) === 0) ?? nodes.find((it) => remaining.has(it));
|
|
1376
|
+
remaining.delete(name);
|
|
1377
|
+
merged.push(name);
|
|
1378
|
+
for (const target of next.get(name) ?? []) incoming.set(target, (incoming.get(target) ?? 1) - 1);
|
|
1379
|
+
}
|
|
1380
|
+
return merged;
|
|
1381
|
+
}
|
|
1382
|
+
function createPreserveCssImportsPlugin(workspace) {
|
|
1166
1383
|
const externalImports = [];
|
|
1384
|
+
const layersByModule = /* @__PURE__ */ new Map();
|
|
1385
|
+
const declaredLayers = [];
|
|
1167
1386
|
const processed = /* @__PURE__ */ new Set();
|
|
1168
1387
|
return definePlugin({
|
|
1169
1388
|
name: "preserve-css-imports",
|
|
1170
1389
|
buildStart() {
|
|
1171
1390
|
externalImports.length = 0;
|
|
1391
|
+
layersByModule.clear();
|
|
1392
|
+
declaredLayers.length = 0;
|
|
1172
1393
|
processed.clear();
|
|
1173
1394
|
},
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1395
|
+
transform: {
|
|
1396
|
+
order: "pre",
|
|
1397
|
+
filter: { id: STYLE_ID_RE },
|
|
1398
|
+
handler(code, id) {
|
|
1399
|
+
const file = id.split("?")[0];
|
|
1400
|
+
if (!STYLE_ID_RE.test(file)) return null;
|
|
1401
|
+
const names = collectLayerNames(code);
|
|
1402
|
+
if (names.length) layersByModule.set(id, names);
|
|
1403
|
+
if (!file.endsWith(".css") || !code.includes("@import")) return null;
|
|
1404
|
+
let changed = false;
|
|
1405
|
+
const stripped = code.replace(IMPORT_RE, (statement, _quote, spec) => {
|
|
1406
|
+
if (isInternalImportSpecifier(spec)) return statement;
|
|
1407
|
+
changed = true;
|
|
1408
|
+
const normalized = statement.trim();
|
|
1409
|
+
if (!externalImports.includes(normalized)) externalImports.push(normalized);
|
|
1410
|
+
return "";
|
|
1411
|
+
});
|
|
1412
|
+
if (!changed) return null;
|
|
1413
|
+
return {
|
|
1414
|
+
code: stripped,
|
|
1415
|
+
map: null
|
|
1416
|
+
};
|
|
1417
|
+
}
|
|
1418
|
+
},
|
|
1419
|
+
generateBundle(_options, bundle) {
|
|
1420
|
+
if (!layersByModule.size) return;
|
|
1421
|
+
const sequences = [];
|
|
1422
|
+
for (const chunk of Object.values(bundle)) {
|
|
1423
|
+
if (chunk.type !== "chunk") continue;
|
|
1424
|
+
for (const id of chunk.moduleIds) {
|
|
1425
|
+
const names = layersByModule.get(id);
|
|
1426
|
+
if (names) sequences.push(names);
|
|
1427
|
+
}
|
|
1182
1428
|
}
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
const stripped = code.replace(IMPORT_RE, (statement, _quote, spec) => {
|
|
1186
|
-
if (isInternalImportSpecifier(spec)) return statement;
|
|
1187
|
-
changed = true;
|
|
1188
|
-
const normalized = statement.trim();
|
|
1189
|
-
if (!externalImports.includes(normalized)) externalImports.push(normalized);
|
|
1190
|
-
return "";
|
|
1191
|
-
});
|
|
1192
|
-
if (!changed) return null;
|
|
1193
|
-
return {
|
|
1194
|
-
code: stripped,
|
|
1195
|
-
map: null
|
|
1196
|
-
};
|
|
1429
|
+
declaredLayers.length = 0;
|
|
1430
|
+
declaredLayers.push(...mergeLayerOrder(sequences));
|
|
1197
1431
|
},
|
|
1198
1432
|
async writeBundle(options, bundle) {
|
|
1199
|
-
if (!externalImports.length) return;
|
|
1433
|
+
if (!externalImports.length && !declaredLayers.length) return;
|
|
1200
1434
|
const { dir } = options;
|
|
1201
1435
|
if (!dir) return;
|
|
1202
|
-
const importBlock = `${externalImports.join("\n")}\n
|
|
1203
|
-
await
|
|
1204
|
-
|
|
1205
|
-
const filePath = path.join(dir,
|
|
1436
|
+
const importBlock = externalImports.length ? `${externalImports.join("\n")}\n` : "";
|
|
1437
|
+
const stylesheets = await listEmittedStylesheets(workspace, dir, bundle);
|
|
1438
|
+
await Promise.all(stylesheets.map(async (fileName) => {
|
|
1439
|
+
const filePath = path.join(dir, fileName);
|
|
1206
1440
|
if (processed.has(filePath)) return;
|
|
1207
1441
|
let css;
|
|
1208
1442
|
try {
|
|
@@ -1211,14 +1445,10 @@ function createPreserveCssImportsPlugin() {
|
|
|
1211
1445
|
return;
|
|
1212
1446
|
}
|
|
1213
1447
|
processed.add(filePath);
|
|
1214
|
-
const layerNames = [];
|
|
1215
|
-
for (const [, names] of css.matchAll(LAYER_STATEMENT_RE)) for (const name of names.split(",")) {
|
|
1216
|
-
const trimmed = name.trim();
|
|
1217
|
-
if (trimmed && !layerNames.includes(trimmed)) layerNames.push(trimmed);
|
|
1218
|
-
}
|
|
1448
|
+
const layerNames = mergeLayerOrder([declaredLayers, collectLayerNames(css)]);
|
|
1219
1449
|
const body = css.replace(LAYER_STATEMENT_RE, "");
|
|
1220
|
-
const
|
|
1221
|
-
await fs$1.writeFile(filePath,
|
|
1450
|
+
const next = `${layerNames.length ? `@layer ${layerNames.join(", ")};\n` : ""}${importBlock}${body}`;
|
|
1451
|
+
if (next !== css) await fs$1.writeFile(filePath, next);
|
|
1222
1452
|
}));
|
|
1223
1453
|
}
|
|
1224
1454
|
});
|
|
@@ -1389,10 +1619,11 @@ var PlugboyWorkspace = class {
|
|
|
1389
1619
|
createExternalImportsPlugin(this),
|
|
1390
1620
|
createSuppressDtsSourcemapWarningPlugin(),
|
|
1391
1621
|
...plugins,
|
|
1622
|
+
createAssembleEntryCssPlugin(this),
|
|
1392
1623
|
OptimizeCSSPlugin(this),
|
|
1393
1624
|
WorkspaceEnvPlugin(this),
|
|
1394
1625
|
rawLoaderPlugin,
|
|
1395
|
-
createPreserveCssImportsPlugin()
|
|
1626
|
+
createPreserveCssImportsPlugin(this)
|
|
1396
1627
|
];
|
|
1397
1628
|
this.hooks = hooks;
|
|
1398
1629
|
this.dts = dts;
|
|
@@ -1556,6 +1787,11 @@ async function getWorkspace(searchDir, allowMissing) {
|
|
|
1556
1787
|
...project.config.optimizeCSS,
|
|
1557
1788
|
...optimizeCSS
|
|
1558
1789
|
};
|
|
1790
|
+
const css = config.css || project?.config.css ? {
|
|
1791
|
+
...project?.config.css,
|
|
1792
|
+
...config.css
|
|
1793
|
+
} : void 0;
|
|
1794
|
+
config.target ??= project?.config.target;
|
|
1559
1795
|
const ctx = {
|
|
1560
1796
|
dir,
|
|
1561
1797
|
json,
|
|
@@ -1569,6 +1805,7 @@ async function getWorkspace(searchDir, allowMissing) {
|
|
|
1569
1805
|
plugins,
|
|
1570
1806
|
hooks,
|
|
1571
1807
|
dts,
|
|
1808
|
+
css,
|
|
1572
1809
|
optimizeCSS,
|
|
1573
1810
|
mergeExternals: (override) => {
|
|
1574
1811
|
config.deps ??= {};
|
|
@@ -1708,4 +1945,4 @@ export default defineWorkspaceConfig({
|
|
|
1708
1945
|
//#endregion
|
|
1709
1946
|
export { resolveOptimizeCSSOptions as $, resolveRawExposeEntriesSettings as A, resolveBundledConfigOutputFile as B, findProjectPlugin as C, loadProjectConfig as D, isProjectPackageJson as E, getFilename as F, mergeChunkAddons as G, stripDanglingDTSSourceMaps as H, isFileNotFoundException as I, isPromise as J, mergeExternals as K, pathExists as L, findConfig as M, findFile as N, resolveUserProjectConfig as O, getDirname as P, WORKSPACE_REQUIRED_FIELDS as Q, rmrf as R, extractProjectPlugins as S, defineProjectConfig as T, exitHook as U, DANGLING_DTS_SOURCE_MAP_RE as V, collectExternalStringPrefixes as W, PROJECT_REQUIRED_FIELDS as X, resolveListable as Y, TSDOWN_SYNC_OPTIONS as Z, loadWorkspaceConfig as _, syncWorkspacePackageFields as a, resolveUserWorkspaceConfig as b, Builder as c, getWorkspacePackageJson as d, mergeDTSSettingsList as et, Path as f, isWorkspacePackageJson as g, defineWorkspaceConfig as h, getWorkspace as i, createHooksDefaults as it, copyDirSync as j, exposeEntries as k, findWorkspacePackages as l, resolveUserHooks as m, PlugboyWorkspace as n, normalizeDTSPreserveTypeTarget as nt, PlugboyProject as o, buildHooks as p, mergeNoExternals as q, WORKSPACE_PACKAGE_SYNC_FIELDS as r, normalizeDTSSettings as rt, getProject as s, generateWorkspace as t, normalizeDTSPreserveTypeSettings as tt, getProjectPackageJson as u, resolveRawWorkspaceEntries as v, resolveUserPluginOption as w, definePlugin as x, resolveRawWorkspaceEntry as y, writeFileAtomic as z };
|
|
1710
1947
|
|
|
1711
|
-
//# sourceMappingURL=workspace-
|
|
1948
|
+
//# sourceMappingURL=workspace-B6BoRqWL.mjs.map
|