release: WRNexusJS 0.4.0
This commit is contained in:
@@ -58,35 +58,40 @@ export {
|
||||
|
||||
import type { Mode, StyleProcessContext, StylesConfig } from "./config.ts";
|
||||
import { bundleCss } from "./styles.ts";
|
||||
import { mkdir, writeFile } from "node:fs/promises";
|
||||
import { isAbsolute, join, relative } from "node:path";
|
||||
|
||||
/**
|
||||
* Produce the final CSS for an entry: run the config's custom processor if one
|
||||
* is provided (Tailwind/PostCSS/Sass), otherwise use the built-in Bun bundler.
|
||||
*
|
||||
* If a custom processor throws (e.g. Tailwind can't resolve `tailwindcss`
|
||||
* because deps aren't installed), we DON'T crash every request — we log a clear,
|
||||
* actionable message and fall back to best-effort CSS so the app keeps serving.
|
||||
* Development can fall back to best-effort CSS. Production throws by default so
|
||||
* a deployment cannot silently ship unprocessed Tailwind/PostCSS directives.
|
||||
*/
|
||||
export async function renderStyles(
|
||||
ctx: StyleProcessContext,
|
||||
styles?: StylesConfig,
|
||||
): Promise<string> {
|
||||
if (!ctx.entryPath) return "";
|
||||
if (!ctx.entryPath && !ctx.entries?.length) return "";
|
||||
const processContext =
|
||||
styles?.includePackageSources === false ? ctx : await packageAwareStyleContext(ctx);
|
||||
if (!processContext.entryPath) return "";
|
||||
if (styles?.process) {
|
||||
try {
|
||||
return String(await styles.process(ctx));
|
||||
return String(await styles.process(processContext));
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
console.error(
|
||||
`\n[wrnexus] Stylesheet processing failed — serving un-processed CSS.\n` +
|
||||
` ${msg.split("\n")[0]}\n` +
|
||||
` If you use Tailwind, run \`bun install\` inside the app so \`tailwindcss\`\n` +
|
||||
` is available (an app created inside another project may not have it).\n`,
|
||||
);
|
||||
return await fallbackCss(ctx);
|
||||
const details =
|
||||
`[wrnexus] Stylesheet processing failed.\n` +
|
||||
` ${msg.split("\n")[0]}\n` +
|
||||
" If you use Tailwind, run `bun install` in the application workspace so the CLI and plugins are available.";
|
||||
const failureMode = styles.failureMode ?? (ctx.mode === "production" ? "throw" : "fallback");
|
||||
if (failureMode === "throw") throw new Error(details, { cause: err });
|
||||
console.error(`\n${details}\n Serving best-effort unprocessed CSS in development.\n`);
|
||||
return await fallbackCss(processContext);
|
||||
}
|
||||
}
|
||||
return bundleCss(ctx.entryPath, ctx.mode);
|
||||
return bundleCss(processContext.entryPath!, processContext.mode);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -107,4 +112,44 @@ async function fallbackCss(ctx: StyleProcessContext): Promise<string> {
|
||||
}
|
||||
}
|
||||
|
||||
async function packageAwareStyleContext(ctx: StyleProcessContext): Promise<StyleProcessContext> {
|
||||
const sources = [...new Set((ctx.sources ?? []).filter(Boolean))];
|
||||
const entries = [...new Set((ctx.entries ?? []).filter(Boolean))];
|
||||
if (sources.length === 0 && entries.length === 0) return ctx;
|
||||
if (!ctx.entryPath && entries.length === 0) return ctx;
|
||||
const outputDir = join(ctx.appRoot, ".wrnexus", "styles");
|
||||
const wrapper = join(outputDir, "global.with-package-sources.css");
|
||||
await mkdir(outputDir, { recursive: true });
|
||||
const localPath = (value: string): string => {
|
||||
const path = isAbsolute(value) ? relative(outputDir, value) : value;
|
||||
const normalized = path.replace(/\\/g, "/");
|
||||
return normalized.startsWith(".") ? normalized : `./${normalized}`;
|
||||
};
|
||||
const quote = (value: string) => localPath(value).replace(/"/g, '\\"');
|
||||
const imports = [...(ctx.entryPath ? [ctx.entryPath] : []), ...entries]
|
||||
.map((value) => `@import "${quote(value)}";`)
|
||||
.join("\n");
|
||||
const directives = sources.map((value) => `@source "${quote(value)}";`).join("\n");
|
||||
await writeFile(
|
||||
wrapper,
|
||||
`${imports}\n\n/* WRNexus package scan sources */\n${directives}\n`,
|
||||
"utf8",
|
||||
);
|
||||
return {
|
||||
...ctx,
|
||||
originalEntryPath: ctx.entryPath,
|
||||
entryPath: wrapper,
|
||||
sources,
|
||||
entries,
|
||||
};
|
||||
}
|
||||
|
||||
export type { Mode as StylesMode };
|
||||
|
||||
export {
|
||||
auditWireTokens,
|
||||
normalizeStyleSources,
|
||||
tailwindSourceDirectives,
|
||||
contrast,
|
||||
} from "./audit.ts";
|
||||
export type { CssTokenAudit, StyleSource, ContrastResult } from "./audit.ts";
|
||||
|
||||
Reference in New Issue
Block a user