@akanjs/devkit 3.0.0-alpha.11 → 3.0.0-alpha.12
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.
|
@@ -48,6 +48,8 @@ export class CssCompiler {
|
|
|
48
48
|
#resolvedSpecifierCache = new Map<string, Promise<string | null>>();
|
|
49
49
|
/** Every stylesheet this compile reached, entry points and `@import` targets alike. */
|
|
50
50
|
#discoveredCssPaths = new Set<string>();
|
|
51
|
+
/** `@import` targets of the compile in progress, by path, so the output can be checked against them. */
|
|
52
|
+
#importedStylesheets = new Map<string, string>();
|
|
51
53
|
|
|
52
54
|
#fileExists(absPath: string): Promise<boolean> {
|
|
53
55
|
let cached = this.#fileExistsCache.get(absPath);
|
|
@@ -233,6 +235,7 @@ export class CssCompiler {
|
|
|
233
235
|
async compileCss(cssPaths: string[], sourcePaths: string[]): Promise<string> {
|
|
234
236
|
if (cssPaths.length === 0) return "";
|
|
235
237
|
|
|
238
|
+
this.#importedStylesheets.clear();
|
|
236
239
|
const compileStarted = Date.now();
|
|
237
240
|
const compilers = await Promise.all(
|
|
238
241
|
cssPaths.map(async (cssPath) => {
|
|
@@ -265,13 +268,33 @@ export class CssCompiler {
|
|
|
265
268
|
this.#logger.verbose(
|
|
266
269
|
`css compiled paths=${cssPaths.length} candidates=${candidates.length} in ${Date.now() - compileStarted}ms`,
|
|
267
270
|
);
|
|
268
|
-
|
|
271
|
+
const css = parts.join("\n");
|
|
272
|
+
this.#warnDroppedImports(css);
|
|
273
|
+
return css;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* An `@import` can resolve, be read, and still contribute nothing — the one failure the existence check
|
|
278
|
+
* cannot see, and the one that reads as an unstyled component rather than as an error. Custom properties
|
|
279
|
+
* declared outside `@theme` are the tell: those pass through verbatim, so a stylesheet whose every
|
|
280
|
+
* declaration is missing from the build did not make it in.
|
|
281
|
+
*/
|
|
282
|
+
#warnDroppedImports(css: string) {
|
|
283
|
+
for (const [cssPath, content] of this.#importedStylesheets) {
|
|
284
|
+
const names = declaredCustomProperties(content);
|
|
285
|
+
if (names.length === 0 || names.some((name) => css.includes(`${name}:`))) continue;
|
|
286
|
+
this.#logger.warn(
|
|
287
|
+
`css @import ${cssPath} was loaded but none of its ${names.length} declaration(s) reached the compiled CSS`,
|
|
288
|
+
);
|
|
289
|
+
}
|
|
269
290
|
}
|
|
270
291
|
|
|
271
292
|
async #loadStylesheet(id: string, fromBase: string) {
|
|
272
293
|
const p = await this.#resolveCssImport(id, fromBase);
|
|
273
294
|
this.#discoveredCssPaths.add(p);
|
|
274
295
|
const content = await Bun.file(p).text();
|
|
296
|
+
this.#importedStylesheets.set(p, content);
|
|
297
|
+
this.#logger.verbose(`css import "${id}" from ${fromBase} -> ${p} (${content.length} bytes)`);
|
|
275
298
|
return { path: p, base: path.dirname(p), content };
|
|
276
299
|
}
|
|
277
300
|
|
|
@@ -388,6 +411,17 @@ export function isIgnoredNodeModuleSource(filePath: string): boolean {
|
|
|
388
411
|
return NODE_MODULES_RE.test(filePath) && !AKANJS_NODE_MODULE_RE.test(filePath);
|
|
389
412
|
}
|
|
390
413
|
|
|
414
|
+
/**
|
|
415
|
+
* `@theme` blocks are stripped first: those variables are emitted only when a utility uses one, so their
|
|
416
|
+
* absence from a build says nothing about whether the stylesheet arrived.
|
|
417
|
+
*/
|
|
418
|
+
export function declaredCustomProperties(css: string): string[] {
|
|
419
|
+
const withoutThemeBlocks = css.replace(/@theme[^{]*\{[^}]*\}/g, "");
|
|
420
|
+
return [...new Set([...withoutThemeBlocks.matchAll(/(?:^|[\s;{])(--[\w-]+)\s*:/g)].map(([, name]) => name))].filter(
|
|
421
|
+
(name): name is string => !!name,
|
|
422
|
+
);
|
|
423
|
+
}
|
|
424
|
+
|
|
391
425
|
function getPageKeyBasePath(pageKey: string, basePaths: string[]): string | null {
|
|
392
426
|
const normalized = pageKey.split(path.sep).join("/").replace(/^\.\//, "");
|
|
393
427
|
const segments = normalized.split("/");
|
|
@@ -5,7 +5,7 @@ import path from "node:path";
|
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
6
|
import type { RoutesManifest } from "akanjs/server";
|
|
7
7
|
import { CsrArtifactBuilder } from "./csrArtifactBuilder";
|
|
8
|
-
import { CssCompiler, isIgnoredNodeModuleSource } from "./cssCompiler";
|
|
8
|
+
import { CssCompiler, declaredCustomProperties, isIgnoredNodeModuleSource } from "./cssCompiler";
|
|
9
9
|
import { CssImportResolver } from "./cssImportResolver";
|
|
10
10
|
import { DevChangePlanner } from "./devChangePlanner";
|
|
11
11
|
import { DevGeneratedIndexSync } from "./devGeneratedIndexSync";
|
|
@@ -443,6 +443,17 @@ describe("CssCompiler", () => {
|
|
|
443
443
|
expect(css).toContain(".text-fuchsia-500");
|
|
444
444
|
});
|
|
445
445
|
|
|
446
|
+
test("reads declarations that prove a stylesheet arrived, ignoring theme variables that may not", () => {
|
|
447
|
+
expect(declaredCustomProperties(":root { --kakao: #fee500; --naver: #1ec800; }")).toEqual(["--kakao", "--naver"]);
|
|
448
|
+
expect(declaredCustomProperties("@theme inline {\n --color-brand: var(--brand);\n}\n")).toEqual([]);
|
|
449
|
+
expect(declaredCustomProperties("@theme { --color-x: initial; }\n:root { --brand: #111; }")).toEqual(["--brand"]);
|
|
450
|
+
expect(declaredCustomProperties(".a { color: var(--kakao); }")).toEqual([]);
|
|
451
|
+
expect(declaredCustomProperties(":root{--a:#111}\n@media (min-width:1px){:root{--a:#222;--b:#333}}")).toEqual([
|
|
452
|
+
"--a",
|
|
453
|
+
"--b",
|
|
454
|
+
]);
|
|
455
|
+
});
|
|
456
|
+
|
|
446
457
|
test("fails loudly on a stylesheet import that resolves to nothing", async () => {
|
|
447
458
|
const root = await makeTempRoot();
|
|
448
459
|
const cssPath = path.join(root, "apps/demo/page/styles.css");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@akanjs/devkit",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.12",
|
|
4
4
|
"sourceType": "module",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"publishConfig": {
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"@langchain/openai": "^1.4.6",
|
|
46
46
|
"@tailwindcss/node": "^4.3.0",
|
|
47
47
|
"@trapezedev/project": "^7.1.4",
|
|
48
|
-
"akanjs": "3.0.0-alpha.
|
|
48
|
+
"akanjs": "3.0.0-alpha.12",
|
|
49
49
|
"chalk": "^5.6.2",
|
|
50
50
|
"commander": "^14.0.3",
|
|
51
51
|
"dayjs": "^1.11.20",
|