finish CSS delivery and generated type remediation
This commit is contained in:
@@ -566,14 +566,17 @@ export async function runBuild(appRoot: string): Promise<void> {
|
||||
},
|
||||
config.styles,
|
||||
);
|
||||
const combinedSource = `${frameworkStyles}\n${css}`;
|
||||
// Theme tokens are request-selected and loaded separately. Keep only the
|
||||
// shared UI primitives with application CSS so the full theme/accent
|
||||
// matrix cannot leak back into the blocking stylesheet.
|
||||
const combinedSource = `${uiStyles}\n${css}`;
|
||||
const combinedInput = join(distDir, ".wrnexus-combined.css");
|
||||
writeFileSync(combinedInput, combinedSource, "utf8");
|
||||
const combinedCss = await bundleCss(combinedInput, "production");
|
||||
rmSync(combinedInput, { force: true });
|
||||
assetHash.update(combinedCss);
|
||||
// One blocking CSS request in production: tokens → UI → application CSS.
|
||||
// The standalone framework.css remains available for apps without global CSS.
|
||||
// One shared blocking request for UI + application CSS. The small active
|
||||
// theme stylesheet is selected from the request cookie and loaded first.
|
||||
writeFileSync(join(distDir, "styles.css"), combinedCss, "utf8");
|
||||
hasStyles = true;
|
||||
if (Buffer.byteLength(combinedCss, "utf8") <= INLINE_CSS_LIMIT_BYTES) {
|
||||
@@ -655,8 +658,8 @@ applyAuthzManifestEarly([${authzSetupEntries}]);
|
||||
const componentsLit = router.components
|
||||
.map((c) => {
|
||||
const v = `c${counter++}`;
|
||||
imports.push(`import * as ${v} from ${JSON.stringify(importPathFor(c.file))};`);
|
||||
return `{ name: ${JSON.stringify(c.name)}, mod: ${v} }`;
|
||||
imports.push(`import { render as ${v} } from ${JSON.stringify(importPathFor(c.file))};`);
|
||||
return `{ name: ${JSON.stringify(c.name)}, mod: { render: ${v} } }`;
|
||||
})
|
||||
.join(", ");
|
||||
console.log(`✓ Components: ${router.components.length}`);
|
||||
@@ -665,8 +668,8 @@ applyAuthzManifestEarly([${authzSetupEntries}]);
|
||||
const layoutsLit = router.layouts
|
||||
.map((l) => {
|
||||
const v = `c${counter++}`;
|
||||
imports.push(`import * as ${v} from ${JSON.stringify(importPathFor(l.file))};`);
|
||||
return `{ name: ${JSON.stringify(l.name)}, mod: ${v} }`;
|
||||
imports.push(`import { render as ${v} } from ${JSON.stringify(importPathFor(l.file))};`);
|
||||
return `{ name: ${JSON.stringify(l.name)}, mod: { render: ${v} } }`;
|
||||
})
|
||||
.join(", ");
|
||||
if (router.layouts.length) console.log(`✓ Layouts: ${router.layouts.length}`);
|
||||
@@ -748,7 +751,7 @@ await createProductionServer(
|
||||
realtime: ${config.realtime ? JSON.stringify(config.realtime) : "undefined"},
|
||||
publicDir: join(import.meta.dir, "public"),
|
||||
${hasStyles ? `stylesPath: join(import.meta.dir, "styles.css"),` : ""}
|
||||
${hasStyles ? `stylesIncludeFramework: true,` : ""}
|
||||
${hasStyles ? `stylesIncludeUi: true,` : ""}
|
||||
${inlineStyles ? `inlineStyles: ${JSON.stringify(inlineStyles)},` : ""}
|
||||
assetVersion: ${JSON.stringify(assetVersion)},
|
||||
clientRuntimes: ${JSON.stringify(emittedPluginAssets.runtimes)},
|
||||
|
||||
@@ -75,7 +75,7 @@ function writePluginArtifacts(root: string, contributions?: PluginContributions)
|
||||
});
|
||||
writeFileSync(
|
||||
join(typeDir, "wrnexus.plugins.generated.d.ts"),
|
||||
`// AUTO-GENERATED plugin type aggregation - do not edit.\n${references.join("\n")}\n`,
|
||||
`// AUTO-GENERATED plugin type aggregation - do not edit.\n${references.length > 0 ? `${references.join("\n")}\n` : ""}`,
|
||||
"utf8",
|
||||
);
|
||||
const docsDir = join(root, ".wrnexus", "documentation");
|
||||
@@ -182,7 +182,6 @@ export function generateApplicationTypes(
|
||||
.map((name) => join(root, name))
|
||||
.find(existsSync);
|
||||
const code = `// AUTO-GENERATED by \`wrnexus generate types\` - do not edit.
|
||||
/* eslint-disable @typescript-eslint/no-empty-object-type */
|
||||
declare namespace WRNexusGenerated {
|
||||
type ApiContract<T> = T extends import("@wrnexus/core").DefinedEndpoint<infer I, infer O>
|
||||
? { input: I; output: O }
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
import { afterAll, expect, test } from "bun:test";
|
||||
import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
||||
import { join } from "node:path";
|
||||
import { runBuild } from "../src/build.ts";
|
||||
|
||||
const scratchRoot = join(import.meta.dir, ".tmp-css-delivery");
|
||||
mkdirSync(scratchRoot, { recursive: true });
|
||||
afterAll(() => rmSync(scratchRoot, { recursive: true, force: true }));
|
||||
|
||||
test("production ships active themes separately and retains one component style copy", async () => {
|
||||
const root = mkdtempSync(join(scratchRoot, "app-"));
|
||||
mkdirSync(join(root, "app", "pages"), { recursive: true });
|
||||
mkdirSync(join(root, "app", "components"), { recursive: true });
|
||||
mkdirSync(join(root, "app", "styles"), { recursive: true });
|
||||
writeFileSync(join(root, "package.json"), JSON.stringify({ name: "css-delivery-fixture" }));
|
||||
writeFileSync(
|
||||
join(root, "wrnexus.config.ts"),
|
||||
`export default { theme: { default: "dark", palette: "violet" }, styles: { entry: "app/styles/global.css" } };\n`,
|
||||
);
|
||||
writeFileSync(join(root, "app", "styles", "global.css"), ".app-shell{display:block}\n");
|
||||
writeFileSync(
|
||||
join(root, "app", "components", "Probe.wrn"),
|
||||
`component Probe { style { .unique-server-style-marker{color:red} } view { <p class="unique-server-style-marker">Probe</p> } }\n`,
|
||||
);
|
||||
writeFileSync(
|
||||
join(root, "app", "pages", "index.wrn"),
|
||||
`import Probe from "../components/Probe.wrn"\npage Home { view { <main class="app-shell"><Probe /></main> } }\n`,
|
||||
);
|
||||
|
||||
await runBuild(root);
|
||||
const styles = readFileSync(join(root, "dist", "styles.css"), "utf8");
|
||||
const activeTheme = readFileSync(join(root, "dist", "theme", "dark", "violet.css"), "utf8");
|
||||
const server = readFileSync(join(root, "dist", "server.js"), "utf8");
|
||||
expect(styles).toContain(".app-shell");
|
||||
expect(styles).not.toContain("[data-theme=");
|
||||
expect(activeTheme.length).toBeLessThan(10_000);
|
||||
expect(server.match(/unique-server-style-marker/g)).toHaveLength(2);
|
||||
});
|
||||
Reference in New Issue
Block a user