@purestack/ts-render 1.1.7 → 1.1.9
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 +1 -1
- package/dist/ts-render.d.mts +4 -4
- package/dist/ts-render.d.mts.map +1 -1
- package/dist/ts-render.mjs +4 -4
- package/dist/ts-render.mjs.map +1 -1
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# @purestack/ts-render
|
|
2
2
|
|
|
3
3
|
Server-side rendering for PureStack's Regor components. `renderApp` takes HTML,
|
|
4
|
-
a component set, and a `
|
|
4
|
+
a component set, and a `PageContext`, and resolves to the rendered HTML with
|
|
5
5
|
any required component scripts attached.
|
|
6
6
|
|
|
7
7
|
Each render gets a document of its own. With an async DOM scope installed, as
|
package/dist/ts-render.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
/*! @purestack/ts-render v1.1.
|
|
1
|
+
/*! @purestack/ts-render v1.1.9 | (c) 2026 Ahmed Yasin Koculu | MIT License */
|
|
2
2
|
|
|
3
3
|
import { Component } from "regor";
|
|
4
|
-
import {
|
|
4
|
+
import { PageContext } from "@purestack/ts-common";
|
|
5
5
|
//#region packages/ts-render/src/componentRegistry.d.ts
|
|
6
6
|
export declare const componentRegistry: {
|
|
7
7
|
register(name: string, component: Component<never>): void;
|
|
@@ -12,7 +12,7 @@ export declare const componentRegistry: {
|
|
|
12
12
|
};
|
|
13
13
|
//#endregion
|
|
14
14
|
//#region packages/ts-render/src/renderApp.d.ts
|
|
15
|
-
interface RenderAppOptions<TContext extends
|
|
15
|
+
interface RenderAppOptions<TContext extends PageContext> {
|
|
16
16
|
/** Components for this render, on top of the registered ones. */
|
|
17
17
|
components: unknown;
|
|
18
18
|
context: TContext;
|
|
@@ -26,7 +26,7 @@ interface RenderAppOptions<TContext extends TsSsgContext> {
|
|
|
26
26
|
* Renders Regor markup to HTML in a document of its own, so renders can
|
|
27
27
|
* overlap, and `onRendered` can await, without seeing each other's pages.
|
|
28
28
|
*/
|
|
29
|
-
export declare const renderApp: <TContext extends
|
|
29
|
+
export declare const renderApp: <TContext extends PageContext>(html: string, options: RenderAppOptions<TContext>) => Promise<string>;
|
|
30
30
|
//#endregion
|
|
31
31
|
export type { RenderAppOptions };
|
|
32
32
|
//# sourceMappingURL=ts-render.d.mts.map
|
package/dist/ts-render.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ts-render.d.mts","names":[],"sources":["../src/componentRegistry.ts","../src/renderApp.ts"],"mappings":";;;qBAKa;EACX,SAAQ,cAAa,WAAa;EAGlC,aAAa,gBAAW,aAAkB;EAQ1C,UAAU,eAAe;EAGzB,iBAAgB;EAGhB;;;;UChBe,iBAAiB,iBAAiB;;EAEjD;EACA,SAAS;;;;;EAKT,cAAc,UAAU,oBAAoB;;;;;;qBAOjC,YAAa,iBAAiB,
|
|
1
|
+
{"version":3,"file":"ts-render.d.mts","names":[],"sources":["../src/componentRegistry.ts","../src/renderApp.ts"],"mappings":";;;qBAKa;EACX,SAAQ,cAAa,WAAa;EAGlC,aAAa,gBAAW,aAAkB;EAQ1C,UAAU,eAAe;EAGzB,iBAAgB;EAGhB;;;;UChBe,iBAAiB,iBAAiB;;EAEjD;EACA,SAAS;;;;;EAKT,cAAc,UAAU,oBAAoB;;;;;;qBAOjC,YAAa,iBAAiB,aAAW,cACxC,SACH,iBAAiB,cACzB"}
|
package/dist/ts-render.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! @purestack/ts-render v1.1.
|
|
1
|
+
/*! @purestack/ts-render v1.1.9 | (c) 2026 Ahmed Yasin Koculu | MIT License */
|
|
2
2
|
|
|
3
3
|
import { isPlainObject } from "@purestack/ts-util";
|
|
4
4
|
import { runInDom } from "@purestack/ts-minidom";
|
|
@@ -56,7 +56,7 @@ const renderApp = (html, options) => {
|
|
|
56
56
|
return runInDom(htmlToParse, async (document) => {
|
|
57
57
|
const runtimeEmbeds = /* @__PURE__ */ new Map();
|
|
58
58
|
const baseContext = options.context;
|
|
59
|
-
const
|
|
59
|
+
const pageContext = {
|
|
60
60
|
...baseContext,
|
|
61
61
|
recordRuntimeEmbed: (name, position) => {
|
|
62
62
|
const normalized = name.trim().toLowerCase();
|
|
@@ -69,9 +69,9 @@ const renderApp = (html, options) => {
|
|
|
69
69
|
...componentRegistry.getAll(),
|
|
70
70
|
...isPlainObject(options.components) ? options.components : {}
|
|
71
71
|
},
|
|
72
|
-
|
|
72
|
+
pageContext
|
|
73
73
|
}, { element: document.body });
|
|
74
|
-
appendEmbeddedScriptsToDom(runtimeEmbeds,
|
|
74
|
+
appendEmbeddedScriptsToDom(runtimeEmbeds, pageContext);
|
|
75
75
|
await options.onRendered?.(document);
|
|
76
76
|
if (isDocument) return `<!DOCTYPE html>${document.documentElement?.outerHTML ?? ""}`;
|
|
77
77
|
return document.body?.innerHTML ?? "";
|
package/dist/ts-render.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ts-render.mjs","names":[],"sources":["../src/componentRegistry.ts","../src/renderApp.ts"],"sourcesContent":["import { isPlainObject } from '@purestack/ts-util'\nimport type { Component } from 'regor'\n\nconst registry = new Map<string, Component<never>>()\n\nexport const componentRegistry = {\n register(name: string, component: Component<never>) {\n registry.set(name, component)\n },\n registerMany<TComponents>(...components: (TComponents | object)[]) {\n for (const compSet of components) {\n if (!isPlainObject(compSet)) continue\n for (const [name, component] of Object.entries(compSet)) {\n registry.set(name, component as Component<never>)\n }\n }\n },\n getAll(): Record<string, Component> {\n return Object.fromEntries(registry.entries())\n },\n hasComponentName(name: string) {\n return hasComponentName(name, registry)\n },\n clear() {\n registry.clear()\n },\n}\n\nfunction hasComponentName(\n input: string,\n source: Map<string, Component<never>>,\n) {\n const normalizedInput = normalizeComponentName(input)\n if (!normalizedInput) return false\n for (const key of source.keys()) {\n const normalizedKey = normalizeComponentName(key)\n if (!normalizedKey) continue\n if (normalizedKey === normalizedInput) return true\n }\n return false\n}\n\nfunction normalizeComponentName(value: string) {\n const trimmed = value.trim()\n if (!trimmed) return ''\n return trimmed.toLowerCase().replace(/[^a-z0-9]/g, '')\n}\n","import type {
|
|
1
|
+
{"version":3,"file":"ts-render.mjs","names":[],"sources":["../src/componentRegistry.ts","../src/renderApp.ts"],"sourcesContent":["import { isPlainObject } from '@purestack/ts-util'\nimport type { Component } from 'regor'\n\nconst registry = new Map<string, Component<never>>()\n\nexport const componentRegistry = {\n register(name: string, component: Component<never>) {\n registry.set(name, component)\n },\n registerMany<TComponents>(...components: (TComponents | object)[]) {\n for (const compSet of components) {\n if (!isPlainObject(compSet)) continue\n for (const [name, component] of Object.entries(compSet)) {\n registry.set(name, component as Component<never>)\n }\n }\n },\n getAll(): Record<string, Component> {\n return Object.fromEntries(registry.entries())\n },\n hasComponentName(name: string) {\n return hasComponentName(name, registry)\n },\n clear() {\n registry.clear()\n },\n}\n\nfunction hasComponentName(\n input: string,\n source: Map<string, Component<never>>,\n) {\n const normalizedInput = normalizeComponentName(input)\n if (!normalizedInput) return false\n for (const key of source.keys()) {\n const normalizedKey = normalizeComponentName(key)\n if (!normalizedKey) continue\n if (normalizedKey === normalizedInput) return true\n }\n return false\n}\n\nfunction normalizeComponentName(value: string) {\n const trimmed = value.trim()\n if (!trimmed) return ''\n return trimmed.toLowerCase().replace(/[^a-z0-9]/g, '')\n}\n","import type { PageContext } from '@purestack/ts-common'\nimport { runInDom } from '@purestack/ts-minidom'\nimport { buildModalScript, buildTabsScript } from '@purestack/ts-page-scripts'\nimport { isPlainObject } from '@purestack/ts-util'\nimport { createApp } from 'regor'\nimport { componentRegistry } from './componentRegistry'\n\nexport interface RenderAppOptions<TContext extends PageContext> {\n /** Components for this render, on top of the registered ones. */\n components: unknown\n context: TContext\n /**\n * Runs on the rendered document, before it becomes HTML. It may be async:\n * the document stays this render's own until it finishes.\n */\n onRendered?: (document: Document) => void | Promise<void>\n}\n\n/**\n * Renders Regor markup to HTML in a document of its own, so renders can\n * overlap, and `onRendered` can await, without seeing each other's pages.\n */\nexport const renderApp = <TContext extends PageContext>(\n html: string,\n options: RenderAppOptions<TContext>,\n): Promise<string> => {\n const normalizedHtml = html.trimStart()\n const isDocument =\n normalizedHtml.startsWith('<!DOCTYPE html>') ||\n normalizedHtml.startsWith('<!doctype html>') ||\n normalizedHtml.startsWith('<html')\n const htmlToParse = isDocument\n ? normalizedHtml\n : `<!DOCTYPE html><html><body>${html}</body></html>`\n return runInDom(htmlToParse, async (document) => {\n const runtimeEmbeds = new Map<string, 'body' | 'head'>()\n const baseContext = options.context\n const pageContext = {\n ...baseContext,\n recordRuntimeEmbed: (name: string, position: 'body' | 'head') => {\n const normalized = name.trim().toLowerCase()\n if (normalized.length > 0) {\n runtimeEmbeds.set(normalized, position)\n }\n baseContext.recordRuntimeEmbed(name, position)\n },\n }\n createApp(\n {\n components: {\n ...componentRegistry.getAll(),\n ...(isPlainObject(options.components) ? options.components : {}),\n },\n pageContext,\n },\n {\n element: document.body,\n },\n )\n appendEmbeddedScriptsToDom(runtimeEmbeds, pageContext)\n await options.onRendered?.(document)\n if (isDocument) {\n return `<!DOCTYPE html>${document.documentElement?.outerHTML ?? ''}`\n }\n return document.body?.innerHTML ?? ''\n })\n}\n\nfunction appendEmbeddedScriptsToDom(\n runtimeEmbeds: Map<string, 'body' | 'head'>,\n context: PageContext,\n) {\n appendRuntimeScript(\n resolveTabsEmbedPosition(runtimeEmbeds, context),\n buildTabsScript,\n )\n appendRuntimeScript(\n resolveModalEmbedPosition(runtimeEmbeds, context),\n buildModalScript,\n )\n}\n\nfunction appendRuntimeScript(\n position: 'body' | 'head' | undefined,\n scriptBuilder: () => string,\n) {\n if (!position) return\n const targetParent = ensureScriptParent(position)\n if (!targetParent) return\n const script = document.createElement('script')\n script.textContent = scriptBuilder()\n targetParent.appendChild(script)\n}\n\nfunction ensureScriptParent(position: 'body' | 'head') {\n if (position === 'body') {\n return document.body\n }\n return document.head\n}\n\nfunction resolveTabsEmbedPosition(\n runtimeEmbeds: Map<string, 'body' | 'head'>,\n context: PageContext,\n) {\n const runtimePosition = runtimeEmbeds.get('tabs')\n if (runtimePosition) return runtimePosition\n return context?.pageInfo?.frontmatter?.embed?.tabs\n}\n\nfunction resolveModalEmbedPosition(\n runtimeEmbeds: Map<string, 'body' | 'head'>,\n context: PageContext,\n) {\n const runtimePosition = runtimeEmbeds.get('modal')\n if (runtimePosition) return runtimePosition\n return context?.pageInfo?.frontmatter?.embed?.modal\n}\n"],"mappings":";;;;;;AAGA,MAAM,2BAAW,IAAI,IAA8B;AAEnD,MAAa,oBAAoB;CAC/B,SAAS,MAAc,WAA6B;EAClD,SAAS,IAAI,MAAM,SAAS;CAC9B;CACA,aAA0B,GAAG,YAAsC;EACjE,KAAK,MAAM,WAAW,YAAY;GAChC,IAAI,CAAC,cAAc,OAAO,GAAG;GAC7B,KAAK,MAAM,CAAC,MAAM,cAAc,OAAO,QAAQ,OAAO,GACpD,SAAS,IAAI,MAAM,SAA6B;EAEpD;CACF;CACA,SAAoC;EAClC,OAAO,OAAO,YAAY,SAAS,QAAQ,CAAC;CAC9C;CACA,iBAAiB,MAAc;EAC7B,OAAO,iBAAiB,MAAM,QAAQ;CACxC;CACA,QAAQ;EACN,SAAS,MAAM;CACjB;AACF;AAEA,SAAS,iBACP,OACA,QACA;CACA,MAAM,kBAAkB,uBAAuB,KAAK;CACpD,IAAI,CAAC,iBAAiB,OAAO;CAC7B,KAAK,MAAM,OAAO,OAAO,KAAK,GAAG;EAC/B,MAAM,gBAAgB,uBAAuB,GAAG;EAChD,IAAI,CAAC,eAAe;EACpB,IAAI,kBAAkB,iBAAiB,OAAO;CAChD;CACA,OAAO;AACT;AAEA,SAAS,uBAAuB,OAAe;CAC7C,MAAM,UAAU,MAAM,KAAK;CAC3B,IAAI,CAAC,SAAS,OAAO;CACrB,OAAO,QAAQ,YAAY,CAAC,CAAC,QAAQ,cAAc,EAAE;AACvD;;;;;;;;ACxBA,MAAa,aACX,MACA,YACoB;CACpB,MAAM,iBAAiB,KAAK,UAAU;CACtC,MAAM,aACJ,eAAe,WAAW,iBAAiB,KAC3C,eAAe,WAAW,iBAAiB,KAC3C,eAAe,WAAW,OAAO;CACnC,MAAM,cAAc,aAChB,iBACA,8BAA8B,KAAK;CACvC,OAAO,SAAS,aAAa,OAAO,aAAa;EAC/C,MAAM,gCAAgB,IAAI,IAA6B;EACvD,MAAM,cAAc,QAAQ;EAC5B,MAAM,cAAc;GAClB,GAAG;GACH,qBAAqB,MAAc,aAA8B;IAC/D,MAAM,aAAa,KAAK,KAAK,CAAC,CAAC,YAAY;IAC3C,IAAI,WAAW,SAAS,GACtB,cAAc,IAAI,YAAY,QAAQ;IAExC,YAAY,mBAAmB,MAAM,QAAQ;GAC/C;EACF;EACA,UACE;GACE,YAAY;IACV,GAAG,kBAAkB,OAAO;IAC5B,GAAI,cAAc,QAAQ,UAAU,IAAI,QAAQ,aAAa,CAAC;GAChE;GACA;EACF,GACA,EACE,SAAS,SAAS,KACpB,CACF;EACA,2BAA2B,eAAe,WAAW;EACrD,MAAM,QAAQ,aAAa,QAAQ;EACnC,IAAI,YACF,OAAO,kBAAkB,SAAS,iBAAiB,aAAa;EAElE,OAAO,SAAS,MAAM,aAAa;CACrC,CAAC;AACH;AAEA,SAAS,2BACP,eACA,SACA;CACA,oBACE,yBAAyB,eAAe,OAAO,GAC/C,eACF;CACA,oBACE,0BAA0B,eAAe,OAAO,GAChD,gBACF;AACF;AAEA,SAAS,oBACP,UACA,eACA;CACA,IAAI,CAAC,UAAU;CACf,MAAM,eAAe,mBAAmB,QAAQ;CAChD,IAAI,CAAC,cAAc;CACnB,MAAM,SAAS,SAAS,cAAc,QAAQ;CAC9C,OAAO,cAAc,cAAc;CACnC,aAAa,YAAY,MAAM;AACjC;AAEA,SAAS,mBAAmB,UAA2B;CACrD,IAAI,aAAa,QACf,OAAO,SAAS;CAElB,OAAO,SAAS;AAClB;AAEA,SAAS,yBACP,eACA,SACA;CACA,MAAM,kBAAkB,cAAc,IAAI,MAAM;CAChD,IAAI,iBAAiB,OAAO;CAC5B,OAAO,SAAS,UAAU,aAAa,OAAO;AAChD;AAEA,SAAS,0BACP,eACA,SACA;CACA,MAAM,kBAAkB,cAAc,IAAI,OAAO;CACjD,IAAI,iBAAiB,OAAO;CAC5B,OAAO,SAAS,UAAU,aAAa,OAAO;AAChD"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@purestack/ts-render",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.9",
|
|
4
4
|
"packageManager": "yarn@4.9.2",
|
|
5
5
|
"module": "./dist/ts-render.mjs",
|
|
6
6
|
"types": "./dist/ts-render.d.mts",
|
|
@@ -39,10 +39,10 @@
|
|
|
39
39
|
"test": "vitest"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@purestack/ts-common": "^1.1.
|
|
43
|
-
"@purestack/ts-minidom": "^1.1.
|
|
44
|
-
"@purestack/ts-page-scripts": "^1.1.
|
|
45
|
-
"@purestack/ts-util": "^1.1.
|
|
46
|
-
"regor": "^1.7.
|
|
42
|
+
"@purestack/ts-common": "^1.1.9",
|
|
43
|
+
"@purestack/ts-minidom": "^1.1.9",
|
|
44
|
+
"@purestack/ts-page-scripts": "^1.1.9",
|
|
45
|
+
"@purestack/ts-util": "^1.1.9",
|
|
46
|
+
"regor": "^1.7.4"
|
|
47
47
|
}
|
|
48
48
|
}
|