feat: release design system engine, studio and component contracts
This commit is contained in:
1 parent
ff1065fb27
commit
3943b946d6
693 files changed
+175546
-3894
No files matched your search
@@ -7,7 +7,14 @@
|
||||
* the browser, which keeps "server-only code" genuinely server-only.
|
||||
*/
|
||||
|
||||
import { escapeHtml, renderControlTemplates, type PageMeta, type SeoConfig } from "@wrnexus/core";
|
||||
import {
|
||||
escapeHtml,
|
||||
encodeControlTemplate,
|
||||
getRequestContext,
|
||||
renderControlTemplates,
|
||||
type PageMeta,
|
||||
type SeoConfig,
|
||||
} from "@wrnexus/core";
|
||||
|
||||
export interface ScriptAsset {
|
||||
src: string;
|
||||
@@ -64,6 +71,8 @@ export function streamPartialDocument(
|
||||
}
|
||||
|
||||
export interface RenderOptions {
|
||||
/** Trusted compiler output. Applied after all extracted component styles. */
|
||||
componentRecipeCss?: string;
|
||||
/** Page metadata for the document head. */
|
||||
meta: PageMeta;
|
||||
/** Global SEO defaults from `wrnexus.config.ts`. */
|
||||
@@ -106,9 +115,62 @@ export function renderDocument(opts: RenderOptions): string {
|
||||
const title = escapeHtml(seo.title);
|
||||
const scripts = normalizeScripts(opts.scripts ?? []);
|
||||
|
||||
const sourceDocument = opts.documentTemplate?.trim();
|
||||
const extracted = extractWrnexusStyles(sourceDocument ?? opts.body, opts.styleNonce);
|
||||
const renderedBody = sourceDocument ? opts.body : extracted.html;
|
||||
// Repeated component instances use identical behavior descriptors. Share one
|
||||
// request-owned JSON value instead of repeating base64 in every branch/row.
|
||||
const request = getRequestContext()?.req;
|
||||
// Existing tabs keep the inline transport until their runtime advertises
|
||||
// registry support. Full documents load the versioned matching runtime.
|
||||
const shareRegistry =
|
||||
request?.headers.get("x-wrnexus-nav") !== "1" ||
|
||||
["registry-v1", "registry-v2"].includes(request?.headers.get("x-wrnexus-behaviors") || "");
|
||||
const shareScopes =
|
||||
request?.headers.get("x-wrnexus-nav") !== "1" ||
|
||||
request?.headers.get("x-wrnexus-behaviors") === "registry-v2";
|
||||
const behaviors = new Map<string, string>();
|
||||
const shareBehaviors = (markup: string) => {
|
||||
if (!shareRegistry) return markup;
|
||||
const shared = markup.replace(
|
||||
/data-wrn-(behavior|scope|loop-locals)="([A-Za-z0-9+/=]+)"/g,
|
||||
(attribute, kind: string, encoded: string) => {
|
||||
if (kind !== "behavior" && !shareScopes) return attribute;
|
||||
const metadataKey = (kind === "behavior" ? "behavior:" : "scope:") + encoded;
|
||||
let reference = behaviors.get(metadataKey);
|
||||
if (!reference) {
|
||||
try {
|
||||
const value = JSON.parse(Buffer.from(encoded, "base64").toString("utf8"));
|
||||
if (!value || typeof value !== "object" || Array.isArray(value)) return attribute;
|
||||
reference = encodeControlTemplate(
|
||||
kind === "behavior" ? value : { __wrnMetadata: true, value },
|
||||
);
|
||||
behaviors.set(metadataKey, reference);
|
||||
} catch {
|
||||
return attribute;
|
||||
}
|
||||
}
|
||||
return `data-wrn-${kind}="${reference}"`;
|
||||
},
|
||||
);
|
||||
// The encoded scope is authoritative; retain only its root marker instead
|
||||
// of repeating the same state in the fallback declaration as well.
|
||||
return !shareScopes
|
||||
? shared
|
||||
: shared.replace(/<[^>]+\bdata-wrn-scope="@[^"]+"[^>]*>/g, (tag) =>
|
||||
tag.replace(/\bdata-scope="[^"]*"/g, 'data-scope=""'),
|
||||
);
|
||||
};
|
||||
const hydrationBody = shareBehaviors(opts.body);
|
||||
const sourceDocument = opts.documentTemplate?.trim()
|
||||
? shareBehaviors(opts.documentTemplate.trim())
|
||||
: undefined;
|
||||
let controlStyles = "";
|
||||
const controls = renderControlTemplates((markup) => {
|
||||
const prepared = extractWrnexusStyles(shareBehaviors(markup), opts.styleNonce);
|
||||
controlStyles += prepared.styles;
|
||||
return prepared.html;
|
||||
});
|
||||
const extracted = extractWrnexusStyles(sourceDocument ?? hydrationBody, opts.styleNonce);
|
||||
extracted.styles = extractWrnexusStyles(controlStyles + extracted.styles, opts.styleNonce).styles;
|
||||
const renderedBody = sourceDocument ? hydrationBody : extracted.html;
|
||||
const renderedDocument = sourceDocument ? extracted.html : undefined;
|
||||
|
||||
const seoTags = renderSeoTags(seo);
|
||||
@@ -119,8 +181,11 @@ export function renderDocument(opts: RenderOptions): string {
|
||||
const scriptTags = scripts.map((script) => `\n ${renderScriptTag(script)}`).join("");
|
||||
|
||||
const globalHead = opts.extraHead ? `\n ${opts.extraHead}` : "";
|
||||
const localStyles = extracted.styles ? `\n ${extracted.styles}` : "";
|
||||
const extraBody = renderControlTemplates() + (opts.extraBody ? `\n ${opts.extraBody}` : "");
|
||||
const recipeStyles = opts.componentRecipeCss
|
||||
? `\n <style data-wrn-design-recipes${opts.styleNonce ? ` nonce="${escapeHtml(opts.styleNonce)}"` : ""}>${opts.componentRecipeCss.replace(/</g, "\\3c ")}</style>`
|
||||
: "";
|
||||
const localStyles = (extracted.styles ? `\n ${extracted.styles}` : "") + recipeStyles;
|
||||
const extraBody = controls + (opts.extraBody ? `\n ${opts.extraBody}` : "");
|
||||
|
||||
const htmlAttrs = /(?:^|\s)lang\s*=/.test(opts.htmlAttrs ?? "")
|
||||
? (opts.htmlAttrs ?? "")
|
||||
@@ -446,7 +511,10 @@ export function renderDocumentStream(opts: StreamRenderOptions): ReadableStream<
|
||||
controller.enqueue(encoder.encode(prefix ?? ""));
|
||||
for await (const chunk of bodyChunks(opts.body)) controller.enqueue(encoder.encode(chunk));
|
||||
// Async body rendering can register templates after the shell is built.
|
||||
const tail = (suffix ?? "").replace(/<script type="application\/json" data-wrn-controls[^>]*>[\s\S]*?<\/script>/g, "");
|
||||
const tail = (suffix ?? "").replace(
|
||||
/<script type="application\/json" data-wrn-controls[^>]*>[\s\S]*?<\/script>/g,
|
||||
"",
|
||||
);
|
||||
controller.enqueue(encoder.encode(renderControlTemplates() + tail));
|
||||
controller.close();
|
||||
} catch (error) {
|
||||
|
||||
Reference in new issue
Block a user