@punkestu/react-html 0.1.0 → 0.1.1
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/dist/cli/docs-content.d.ts +8 -0
- package/dist/cli/docs-content.d.ts.map +1 -0
- package/dist/cli/docs-content.js +261 -0
- package/dist/cli/docs-content.js.map +1 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +113 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/tui-docs.d.ts +5 -0
- package/dist/cli/tui-docs.d.ts.map +1 -0
- package/dist/cli/tui-docs.js +191 -0
- package/dist/cli/tui-docs.js.map +1 -0
- package/dist/client/hydrate.d.ts +4 -0
- package/dist/client/hydrate.d.ts.map +1 -0
- package/dist/client/hydrate.js +80 -0
- package/dist/client/hydrate.js.map +1 -0
- package/dist/core/bundler.d.ts +7 -0
- package/dist/core/bundler.d.ts.map +1 -0
- package/dist/core/bundler.js +103 -0
- package/dist/core/bundler.js.map +1 -0
- package/dist/core/formatter.d.ts +6 -0
- package/dist/core/formatter.d.ts.map +1 -0
- package/dist/core/formatter.js +74 -0
- package/dist/core/formatter.js.map +1 -0
- package/dist/core/island-client.d.ts +9 -0
- package/dist/core/island-client.d.ts.map +1 -0
- package/dist/core/island-client.js +8 -0
- package/dist/core/island-client.js.map +1 -0
- package/dist/core/island-registry.d.ts +15 -0
- package/dist/core/island-registry.d.ts.map +1 -0
- package/dist/core/island-registry.js +17 -0
- package/dist/core/island-registry.js.map +1 -0
- package/dist/core/island.d.ts +32 -0
- package/dist/core/island.d.ts.map +1 -0
- package/dist/core/island.js +47 -0
- package/dist/core/island.js.map +1 -0
- package/dist/core/loader.d.ts +11 -0
- package/dist/core/loader.d.ts.map +1 -0
- package/dist/core/loader.js +73 -0
- package/dist/core/loader.js.map +1 -0
- package/dist/core/renderer.d.ts +20 -0
- package/dist/core/renderer.d.ts.map +1 -0
- package/dist/core/renderer.js +53 -0
- package/dist/core/renderer.js.map +1 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +104 -0
- package/dist/index.js.map +1 -0
- package/dist/server/dev-server.d.ts +8 -0
- package/dist/server/dev-server.d.ts.map +1 -0
- package/dist/server/dev-server.js +112 -0
- package/dist/server/dev-server.js.map +1 -0
- package/dist/server/engine.d.ts +46 -0
- package/dist/server/engine.d.ts.map +1 -0
- package/dist/server/engine.js +222 -0
- package/dist/server/engine.js.map +1 -0
- package/{src/server/index.ts → dist/server/index.d.ts} +1 -1
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +3 -0
- package/dist/server/index.js.map +1 -0
- package/package.json +4 -1
- package/.react-html/cache/page-fefe905ae5d2.mjs +0 -9
- package/DOCS.md +0 -317
- package/example/public/styles.css +0 -184
- package/example/src/components/Card.tsx +0 -17
- package/example/src/components/Counter.island.tsx +0 -35
- package/example/src/components/Footer.tsx +0 -13
- package/example/src/components/Header.tsx +0 -20
- package/example/src/components/Layout.tsx +0 -39
- package/example/src/components/Tabs.island.tsx +0 -59
- package/example/src/pages/index.tsx +0 -49
- package/example/src/pages/pure.tsx +0 -56
- package/src/cli/docs-content.ts +0 -268
- package/src/cli/index.ts +0 -113
- package/src/cli/tui-docs.ts +0 -214
- package/src/client/hydrate.ts +0 -84
- package/src/core/bundler.ts +0 -122
- package/src/core/formatter.ts +0 -92
- package/src/core/island-client.ts +0 -23
- package/src/core/island-registry.ts +0 -35
- package/src/core/island.tsx +0 -110
- package/src/core/loader.ts +0 -89
- package/src/core/renderer.ts +0 -80
- package/src/index.ts +0 -138
- package/src/server/dev-server.ts +0 -125
- package/src/server/engine.ts +0 -270
- package/tests/engine.test.mjs +0 -288
- package/tsconfig.json +0 -21
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { hydrateRoot, createRoot } from 'react-dom/client';
|
|
3
|
+
export function hydrateIsland(islandName, Component) {
|
|
4
|
+
if (typeof window === 'undefined')
|
|
5
|
+
return;
|
|
6
|
+
const mountElements = document.querySelectorAll(`[data-island="${islandName}"]`);
|
|
7
|
+
mountElements.forEach((el) => {
|
|
8
|
+
// Prevent double hydration
|
|
9
|
+
if (el.hasAttribute('data-hydrated'))
|
|
10
|
+
return;
|
|
11
|
+
const rawProps = el.getAttribute('data-props');
|
|
12
|
+
let props = {};
|
|
13
|
+
if (rawProps) {
|
|
14
|
+
try {
|
|
15
|
+
props = JSON.parse(rawProps);
|
|
16
|
+
}
|
|
17
|
+
catch (err) {
|
|
18
|
+
console.error(`[react-html] Failed to parse props for island "${islandName}":`, err);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
const directive = (el.getAttribute('data-client') || 'load');
|
|
22
|
+
const doHydrate = () => {
|
|
23
|
+
if (el.hasAttribute('data-hydrated'))
|
|
24
|
+
return;
|
|
25
|
+
el.setAttribute('data-hydrated', 'true');
|
|
26
|
+
try {
|
|
27
|
+
hydrateRoot(el, React.createElement(Component, props), {
|
|
28
|
+
onRecoverableError(error) {
|
|
29
|
+
// Suppress non-breaking hydration difference warnings
|
|
30
|
+
console.debug(`[react-html] Island "${islandName}" hydration note:`, error);
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
catch (err) {
|
|
35
|
+
console.warn(`[react-html] Hydration error on island "${islandName}", recovering with client mount:`, err);
|
|
36
|
+
const root = createRoot(el);
|
|
37
|
+
root.render(React.createElement(Component, props));
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
switch (directive) {
|
|
41
|
+
case 'idle': {
|
|
42
|
+
if ('requestIdleCallback' in window) {
|
|
43
|
+
window.requestIdleCallback(doHydrate);
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
setTimeout(doHydrate, 200);
|
|
47
|
+
}
|
|
48
|
+
break;
|
|
49
|
+
}
|
|
50
|
+
case 'visible': {
|
|
51
|
+
if ('IntersectionObserver' in window) {
|
|
52
|
+
const observer = new IntersectionObserver((entries, obs) => {
|
|
53
|
+
entries.forEach((entry) => {
|
|
54
|
+
if (entry.isIntersecting) {
|
|
55
|
+
obs.disconnect();
|
|
56
|
+
doHydrate();
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
observer.observe(el);
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
doHydrate();
|
|
64
|
+
}
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
67
|
+
case 'load':
|
|
68
|
+
default: {
|
|
69
|
+
if (document.readyState === 'loading') {
|
|
70
|
+
window.addEventListener('DOMContentLoaded', doHydrate, { once: true });
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
doHydrate();
|
|
74
|
+
}
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=hydrate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hydrate.js","sourceRoot":"","sources":["../../src/client/hydrate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { IslandInstance } from './island-registry.js';
|
|
2
|
+
export interface BundlerOptions {
|
|
3
|
+
outDir: string;
|
|
4
|
+
minify?: boolean;
|
|
5
|
+
}
|
|
6
|
+
export declare function bundleIslands(islands: IslandInstance[], options: BundlerOptions): Promise<string[]>;
|
|
7
|
+
//# sourceMappingURL=bundler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bundler.d.ts","sourceRoot":"","sources":["../../src/core/bundler.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,wBAAsB,aAAa,CACjC,OAAO,EAAE,cAAc,EAAE,EACzB,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,MAAM,EAAE,CAAC,CA0GnB"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import * as esbuild from 'esbuild';
|
|
2
|
+
import fs from 'node:fs/promises';
|
|
3
|
+
import { existsSync } from 'node:fs';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { fileURLToPath } from 'node:url';
|
|
6
|
+
export async function bundleIslands(islands, options) {
|
|
7
|
+
const { outDir, minify = true } = options;
|
|
8
|
+
const islandsOutputDir = path.join(outDir, 'assets', 'islands');
|
|
9
|
+
await fs.mkdir(islandsOutputDir, { recursive: true });
|
|
10
|
+
const tempDir = path.resolve(process.cwd(), '.react-html/temp-islands');
|
|
11
|
+
await fs.mkdir(tempDir, { recursive: true });
|
|
12
|
+
const uniqueIslandsMap = new Map();
|
|
13
|
+
for (const island of islands) {
|
|
14
|
+
if (!uniqueIslandsMap.has(island.name)) {
|
|
15
|
+
uniqueIslandsMap.set(island.name, island);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
const bundledFiles = [];
|
|
19
|
+
// Locate hydrate module
|
|
20
|
+
const currentDir = import.meta.dirname || path.dirname(fileURLToPath(import.meta.url));
|
|
21
|
+
let hydratePath = path.resolve(currentDir, '../client/hydrate.js');
|
|
22
|
+
if (!existsSync(hydratePath)) {
|
|
23
|
+
hydratePath = path.resolve(currentDir, '../client/hydrate.ts');
|
|
24
|
+
}
|
|
25
|
+
let islandClientPath = path.resolve(currentDir, './island-client.js');
|
|
26
|
+
if (!existsSync(islandClientPath)) {
|
|
27
|
+
islandClientPath = path.resolve(currentDir, './island-client.ts');
|
|
28
|
+
}
|
|
29
|
+
for (const [name, island] of uniqueIslandsMap.entries()) {
|
|
30
|
+
let resolvedEntry = island.entryPath;
|
|
31
|
+
if (resolvedEntry.startsWith('file://')) {
|
|
32
|
+
resolvedEntry = fileURLToPath(resolvedEntry);
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
resolvedEntry = path.resolve(resolvedEntry);
|
|
36
|
+
}
|
|
37
|
+
try {
|
|
38
|
+
await fs.access(resolvedEntry);
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
console.warn(`[react-html] Warning: Island source file not found for "${name}" at "${resolvedEntry}". Skipping client bundle.`);
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
// Create a virtual client entrypoint for this island
|
|
45
|
+
const virtualEntryFile = path.join(tempDir, `${name}.entry.ts`);
|
|
46
|
+
const virtualEntryCode = `
|
|
47
|
+
import React from 'react';
|
|
48
|
+
import { hydrateIsland } from ${JSON.stringify(hydratePath)};
|
|
49
|
+
import * as Module from ${JSON.stringify(resolvedEntry)};
|
|
50
|
+
|
|
51
|
+
const raw = Module.default || Module[${JSON.stringify(name)}] || Module;
|
|
52
|
+
const Component = (raw && raw.__rawComponent) ? raw.__rawComponent : raw;
|
|
53
|
+
|
|
54
|
+
hydrateIsland(${JSON.stringify(name)}, Component);
|
|
55
|
+
`;
|
|
56
|
+
await fs.writeFile(virtualEntryFile, virtualEntryCode, 'utf8');
|
|
57
|
+
const outfile = path.join(islandsOutputDir, `${name}.js`);
|
|
58
|
+
await esbuild.build({
|
|
59
|
+
entryPoints: [virtualEntryFile],
|
|
60
|
+
outfile,
|
|
61
|
+
bundle: true,
|
|
62
|
+
format: 'esm',
|
|
63
|
+
platform: 'browser',
|
|
64
|
+
target: ['es2022'],
|
|
65
|
+
minify,
|
|
66
|
+
treeShaking: true,
|
|
67
|
+
define: {
|
|
68
|
+
'process.env.NODE_ENV': '"production"'
|
|
69
|
+
},
|
|
70
|
+
alias: {
|
|
71
|
+
'react-html': islandClientPath
|
|
72
|
+
},
|
|
73
|
+
plugins: [
|
|
74
|
+
{
|
|
75
|
+
name: 'redirect-react-html-imports',
|
|
76
|
+
setup(build) {
|
|
77
|
+
// Redirect any import of react-html or root index to island-client
|
|
78
|
+
build.onResolve({ filter: /(react-html|(\/|\\)(src|dist)(\/|\\)index(\.js|\.mjs|\.ts)?)$/ }, () => {
|
|
79
|
+
return { path: islandClientPath };
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
],
|
|
84
|
+
loader: {
|
|
85
|
+
'.tsx': 'tsx',
|
|
86
|
+
'.ts': 'ts',
|
|
87
|
+
'.jsx': 'jsx',
|
|
88
|
+
'.js': 'js',
|
|
89
|
+
'.css': 'empty'
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
bundledFiles.push(outfile);
|
|
93
|
+
}
|
|
94
|
+
// Cleanup virtual entry files
|
|
95
|
+
try {
|
|
96
|
+
await fs.rm(tempDir, { recursive: true, force: true });
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
// Ignore cleanup error
|
|
100
|
+
}
|
|
101
|
+
return bundledFiles;
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=bundler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bundler.js","sourceRoot":"","sources":["../../src/core/bundler.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formatter.d.ts","sourceRoot":"","sources":["../../src/core/formatter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAuF/C"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Robust HTML formatter to output clean, readable HTML
|
|
3
|
+
* Preserves exact inner markup inside reactive islands to ensure seamless React hydration.
|
|
4
|
+
*/
|
|
5
|
+
export function formatHtml(html) {
|
|
6
|
+
// Extract and preserve island contents verbatim
|
|
7
|
+
const preservedIslands = [];
|
|
8
|
+
let clean = html.replace(/<!--__ISLAND_START__-->([\s\S]*?)<!--__ISLAND_END__-->/g, (_, inner) => {
|
|
9
|
+
const idx = preservedIslands.length;
|
|
10
|
+
preservedIslands.push(inner);
|
|
11
|
+
return `%%REACT_HTML_ISLAND_${idx}%%`;
|
|
12
|
+
});
|
|
13
|
+
// Strip React comment artifacts outside islands if any
|
|
14
|
+
clean = clean.replace(/<!-- -->/g, '');
|
|
15
|
+
const tokens = clean.split(/(<[^>]+>)/g).filter((t) => t.trim().length > 0);
|
|
16
|
+
let formatted = '';
|
|
17
|
+
let indent = 0;
|
|
18
|
+
const indentStr = ' ';
|
|
19
|
+
// Void tags that don't need closing or indentation changes
|
|
20
|
+
const voidTags = new Set([
|
|
21
|
+
'area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input',
|
|
22
|
+
'link', 'meta', 'param', 'source', 'track', 'wbr', '!doctype'
|
|
23
|
+
]);
|
|
24
|
+
// Tags where content is typically kept on the same line if brief
|
|
25
|
+
const inlineTags = new Set([
|
|
26
|
+
'title', 'span', 'strong', 'em', 'b', 'i', 'code', 'small', 'sub', 'sup'
|
|
27
|
+
]);
|
|
28
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
29
|
+
const token = tokens[i].trim();
|
|
30
|
+
if (token.startsWith('<!DOCTYPE') || token.startsWith('<!doctype')) {
|
|
31
|
+
formatted += token + '\n';
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
if (token.startsWith('</')) {
|
|
35
|
+
// Closing tag
|
|
36
|
+
const match = token.match(/<\/([a-zA-Z0-9\-]+)/);
|
|
37
|
+
const tagName = match ? match[1].toLowerCase() : '';
|
|
38
|
+
indent = Math.max(0, indent - 1);
|
|
39
|
+
formatted += indentStr.repeat(indent) + token + '\n';
|
|
40
|
+
}
|
|
41
|
+
else if (token.startsWith('<') && !token.startsWith('<!--')) {
|
|
42
|
+
// Opening or self-closing tag
|
|
43
|
+
const match = token.match(/<([a-zA-Z0-9\-]+)/);
|
|
44
|
+
const tagName = match ? match[1].toLowerCase() : '';
|
|
45
|
+
const isSelfClosing = token.endsWith('/>') || voidTags.has(tagName);
|
|
46
|
+
// Check if next token is text and next-next token is closing tag
|
|
47
|
+
if (inlineTags.has(tagName) &&
|
|
48
|
+
i + 2 < tokens.length &&
|
|
49
|
+
!tokens[i + 1].trim().startsWith('<') &&
|
|
50
|
+
tokens[i + 2].trim().toLowerCase() === `</${tagName}>`) {
|
|
51
|
+
const text = tokens[i + 1].trim();
|
|
52
|
+
const closeTag = tokens[i + 2].trim();
|
|
53
|
+
formatted += indentStr.repeat(indent) + `${token}${text}${closeTag}\n`;
|
|
54
|
+
i += 2;
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
formatted += indentStr.repeat(indent) + token + '\n';
|
|
58
|
+
if (!isSelfClosing) {
|
|
59
|
+
indent++;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
// Standalone text content
|
|
64
|
+
formatted += indentStr.repeat(indent) + token + '\n';
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
// Restore preserved island markup untouched
|
|
68
|
+
let finalHtml = formatted.replace(/%%REACT_HTML_ISLAND_(\d+)%%/g, (_, idxStr) => {
|
|
69
|
+
const idx = parseInt(idxStr, 10);
|
|
70
|
+
return preservedIslands[idx] ?? '';
|
|
71
|
+
});
|
|
72
|
+
return finalHtml.trim() + '\n';
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=formatter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formatter.js","sourceRoot":"","sources":["../../src/core/formatter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import React, { ComponentType, ReactNode } from 'react';
|
|
2
|
+
export declare function Island<P extends Record<string, unknown>>({ component: Component, props, children }: {
|
|
3
|
+
component: ComponentType<P>;
|
|
4
|
+
props?: P;
|
|
5
|
+
children?: ReactNode;
|
|
6
|
+
[key: string]: unknown;
|
|
7
|
+
}): React.ReactElement;
|
|
8
|
+
export declare function island<P extends Record<string, unknown>>(Component: ComponentType<P>, _sourcePath?: string, _customName?: string): ComponentType<P>;
|
|
9
|
+
//# sourceMappingURL=island-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"island-client.d.ts","sourceRoot":"","sources":["../../src/core/island-client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAExD,wBAAgB,MAAM,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EACxD,SAAS,EAAE,SAAS,EACpB,KAAe,EACf,QAAQ,EACT,EAAE;IACD,SAAS,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC;IAC5B,KAAK,CAAC,EAAE,CAAC,CAAC;IACV,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB,GAAG,KAAK,CAAC,YAAY,CAErB;AAED,wBAAgB,MAAM,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACtD,SAAS,EAAE,aAAa,CAAC,CAAC,CAAC,EAC3B,WAAW,CAAC,EAAE,MAAM,EACpB,WAAW,CAAC,EAAE,MAAM,GACnB,aAAa,CAAC,CAAC,CAAC,CAElB"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export function Island({ component: Component, props = {}, children }) {
|
|
3
|
+
return React.createElement(Component, props, children);
|
|
4
|
+
}
|
|
5
|
+
export function island(Component, _sourcePath, _customName) {
|
|
6
|
+
return Component;
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=island-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"island-client.js","sourceRoot":"","sources":["../../src/core/island-client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAmC,MAAM,OAAO,CAAC;AAExD,MAAM,UAAU,MAAM,CAAoC,EACxD,SAAS,EAAE,SAAS,EACpB,KAAK,GAAG,EAAO,EACf,QAAQ,EAMT;IACC,OAAO,KAAK,CAAC,aAAa,CAAC,SAAS,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC;AACzD,CAAC;AAED,MAAM,UAAU,MAAM,CACpB,SAA2B,EAC3B,WAAoB,EACpB,WAAoB;IAEpB,OAAO,SAAS,CAAC;AACnB,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface IslandInstance {
|
|
2
|
+
id: string;
|
|
3
|
+
name: string;
|
|
4
|
+
entryPath: string;
|
|
5
|
+
props: Record<string, unknown>;
|
|
6
|
+
clientDirective?: 'load' | 'idle' | 'visible';
|
|
7
|
+
}
|
|
8
|
+
export interface RenderContext {
|
|
9
|
+
pagePath: string;
|
|
10
|
+
islands: IslandInstance[];
|
|
11
|
+
}
|
|
12
|
+
export declare function runWithRenderContext<T>(context: RenderContext, fn: () => T): T;
|
|
13
|
+
export declare function getCurrentRenderContext(): RenderContext | undefined;
|
|
14
|
+
export declare function registerIslandInContext(island: IslandInstance): void;
|
|
15
|
+
//# sourceMappingURL=island-registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"island-registry.d.ts","sourceRoot":"","sources":["../../src/core/island-registry.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,eAAe,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;CAC/C;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,cAAc,EAAE,CAAC;CAC3B;AAQD,wBAAgB,oBAAoB,CAAC,CAAC,EAAE,OAAO,EAAE,aAAa,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAE9E;AAED,wBAAgB,uBAAuB,IAAI,aAAa,GAAG,SAAS,CAEnE;AAED,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI,CAKpE"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
2
|
+
const GLOBAL_STORAGE_KEY = Symbol.for('__react_html_render_context__');
|
|
3
|
+
const storage = globalThis[GLOBAL_STORAGE_KEY] ||
|
|
4
|
+
(globalThis[GLOBAL_STORAGE_KEY] = new AsyncLocalStorage());
|
|
5
|
+
export function runWithRenderContext(context, fn) {
|
|
6
|
+
return storage.run(context, fn);
|
|
7
|
+
}
|
|
8
|
+
export function getCurrentRenderContext() {
|
|
9
|
+
return storage.getStore();
|
|
10
|
+
}
|
|
11
|
+
export function registerIslandInContext(island) {
|
|
12
|
+
const ctx = storage.getStore();
|
|
13
|
+
if (ctx) {
|
|
14
|
+
ctx.islands.push(island);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=island-registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"island-registry.js","sourceRoot":"","sources":["../../src/core/island-registry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAerD,MAAM,kBAAkB,GAAG,MAAM,CAAC,GAAG,CAAC,+BAA+B,CAAC,CAAC;AAEvE,MAAM,OAAO,GACV,UAAkB,CAAC,kBAAkB,CAAC;IACvC,CAAE,UAAkB,CAAC,kBAAkB,CAAC,GAAG,IAAI,iBAAiB,EAAiB,CAAC,CAAC;AAErF,MAAM,UAAU,oBAAoB,CAAI,OAAsB,EAAE,EAAW;IACzE,OAAO,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;AAClC,CAAC;AAED,MAAM,UAAU,uBAAuB;IACrC,OAAO,OAAO,CAAC,QAAQ,EAAE,CAAC;AAC5B,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,MAAsB;IAC5D,MAAM,GAAG,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IAC/B,IAAI,GAAG,EAAE,CAAC;QACR,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC3B,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import React, { ComponentType, ReactNode } from 'react';
|
|
2
|
+
export interface IslandProps<P = Record<string, unknown>> {
|
|
3
|
+
/** Explicit island name (optional) */
|
|
4
|
+
name?: string;
|
|
5
|
+
/** Path to the island component file (relative or absolute) */
|
|
6
|
+
src?: string;
|
|
7
|
+
/** The React component to render */
|
|
8
|
+
component: ComponentType<P>;
|
|
9
|
+
/** Props passed to the component */
|
|
10
|
+
props?: P;
|
|
11
|
+
/** Client hydration directive (default: 'load') */
|
|
12
|
+
client?: 'load' | 'idle' | 'visible';
|
|
13
|
+
/** Optional wrapper tag, default: 'div' */
|
|
14
|
+
as?: string;
|
|
15
|
+
className?: string;
|
|
16
|
+
style?: React.CSSProperties;
|
|
17
|
+
children?: ReactNode;
|
|
18
|
+
}
|
|
19
|
+
export declare function Island<P extends Record<string, unknown>>({ name, src, component: Component, props, client, as: Tag, className, style, children }: IslandProps<P>): React.ReactElement;
|
|
20
|
+
/**
|
|
21
|
+
* Helper to wrap any React component into a ready-to-use Island component
|
|
22
|
+
* Example:
|
|
23
|
+
* export const Counter = island(CounterComponent, import.meta.url, 'Counter');
|
|
24
|
+
* // In page: <Counter initialCount={5} />
|
|
25
|
+
*/
|
|
26
|
+
export declare function island<P extends Record<string, unknown>>(Component: ComponentType<P>, sourcePath: string, customName?: string): ComponentType<P & {
|
|
27
|
+
client?: 'load' | 'idle' | 'visible';
|
|
28
|
+
as?: string;
|
|
29
|
+
className?: string;
|
|
30
|
+
style?: React.CSSProperties;
|
|
31
|
+
}>;
|
|
32
|
+
//# sourceMappingURL=island.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"island.d.ts","sourceRoot":"","sources":["../../src/core/island.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAMxD,MAAM,WAAW,WAAW,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACtD,sCAAsC;IACtC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,+DAA+D;IAC/D,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,oCAAoC;IACpC,SAAS,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC;IAC5B,oCAAoC;IACpC,KAAK,CAAC,EAAE,CAAC,CAAC;IACV,mDAAmD;IACnD,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;IACrC,2CAA2C;IAC3C,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED,wBAAgB,MAAM,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EACxD,IAAI,EACJ,GAAG,EACH,SAAS,EAAE,SAAS,EACpB,KAAe,EACf,MAAe,EACf,EAAE,EAAE,GAAW,EACf,SAAS,EACT,KAAK,EACL,QAAQ,EACT,EAAE,WAAW,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,YAAY,CAqCrC;AAED;;;;;GAKG;AACH,wBAAgB,MAAM,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACtD,SAAS,EAAE,aAAa,CAAC,CAAC,CAAC,EAC3B,UAAU,EAAE,MAAM,EAClB,UAAU,CAAC,EAAE,MAAM,GAClB,aAAa,CAAC,CAAC,GAAG;IAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;IAAC,EAAE,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAA;CAAE,CAAC,CA0B3H"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { renderToString } from 'react-dom/server';
|
|
4
|
+
import { registerIslandInContext } from './island-registry.js';
|
|
5
|
+
let islandCounter = 0;
|
|
6
|
+
export function Island({ name, src, component: Component, props = {}, client = 'load', as: Tag = 'div', className, style, children }) {
|
|
7
|
+
const componentName = name ||
|
|
8
|
+
Component.__islandName ||
|
|
9
|
+
Component.displayName ||
|
|
10
|
+
Component.name ||
|
|
11
|
+
'AnonymousIsland';
|
|
12
|
+
const islandId = `island-${++islandCounter}`;
|
|
13
|
+
// If src is specified or attached to component
|
|
14
|
+
const entryPath = src || Component.__islandPath || '';
|
|
15
|
+
registerIslandInContext({
|
|
16
|
+
id: islandId,
|
|
17
|
+
name: componentName,
|
|
18
|
+
entryPath,
|
|
19
|
+
props,
|
|
20
|
+
clientDirective: client
|
|
21
|
+
});
|
|
22
|
+
const Wrapper = Tag;
|
|
23
|
+
// Use renderToString for the island's inner tree to produce hydration-compatible SSR markup
|
|
24
|
+
const innerHtml = renderToString(React.createElement(Component, props, children));
|
|
25
|
+
return (_jsx(Wrapper, { "data-island": componentName, "data-island-id": islandId, "data-props": JSON.stringify(props), "data-client": client, className: className, style: style, dangerouslySetInnerHTML: { __html: `<!--__ISLAND_START__-->${innerHtml}<!--__ISLAND_END__-->` } }));
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Helper to wrap any React component into a ready-to-use Island component
|
|
29
|
+
* Example:
|
|
30
|
+
* export const Counter = island(CounterComponent, import.meta.url, 'Counter');
|
|
31
|
+
* // In page: <Counter initialCount={5} />
|
|
32
|
+
*/
|
|
33
|
+
export function island(Component, sourcePath, customName) {
|
|
34
|
+
const resolvedName = customName || Component.displayName || Component.name || 'AnonymousIsland';
|
|
35
|
+
Component.__islandPath = sourcePath;
|
|
36
|
+
Component.__islandName = resolvedName;
|
|
37
|
+
const IslandWrapper = (props) => {
|
|
38
|
+
const { client, as, className, style, ...componentProps } = props;
|
|
39
|
+
return (_jsx(Island, { name: resolvedName, src: sourcePath, component: Component, props: componentProps, client: client, as: as, className: className, style: style }));
|
|
40
|
+
};
|
|
41
|
+
IslandWrapper.displayName = `Island(${resolvedName})`;
|
|
42
|
+
IslandWrapper.__islandPath = sourcePath;
|
|
43
|
+
IslandWrapper.__islandName = resolvedName;
|
|
44
|
+
IslandWrapper.__rawComponent = Component;
|
|
45
|
+
return IslandWrapper;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=island.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"island.js","sourceRoot":"","sources":["../../src/core/island.tsx"],"names":[],"mappings":";AAAA,OAAO,KAAmC,MAAM,OAAO,CAAC;AACxD,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAE/D,IAAI,aAAa,GAAG,CAAC,CAAC;AAoBtB,MAAM,UAAU,MAAM,CAAoC,EACxD,IAAI,EACJ,GAAG,EACH,SAAS,EAAE,SAAS,EACpB,KAAK,GAAG,EAAO,EACf,MAAM,GAAG,MAAM,EACf,EAAE,EAAE,GAAG,GAAG,KAAK,EACf,SAAS,EACT,KAAK,EACL,QAAQ,EACO;IACf,MAAM,aAAa,GACjB,IAAI;QACH,SAAiB,CAAC,YAAY;QAC/B,SAAS,CAAC,WAAW;QACrB,SAAS,CAAC,IAAI;QACd,iBAAiB,CAAC;IAEpB,MAAM,QAAQ,GAAG,UAAU,EAAE,aAAa,EAAE,CAAC;IAE7C,+CAA+C;IAC/C,MAAM,SAAS,GAAG,GAAG,IAAK,SAAiB,CAAC,YAAY,IAAI,EAAE,CAAC;IAE/D,uBAAuB,CAAC;QACtB,EAAE,EAAE,QAAQ;QACZ,IAAI,EAAE,aAAa;QACnB,SAAS;QACT,KAAK;QACL,eAAe,EAAE,MAAM;KACxB,CAAC,CAAC;IAEH,MAAM,OAAO,GAAG,GAAU,CAAC;IAE3B,4FAA4F;IAC5F,MAAM,SAAS,GAAG,cAAc,CAAC,KAAK,CAAC,aAAa,CAAC,SAAS,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC;IAElF,OAAO,CACL,KAAC,OAAO,mBACO,aAAa,oBACV,QAAQ,gBACZ,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,iBACpB,MAAM,EACnB,SAAS,EAAE,SAAS,EACpB,KAAK,EAAE,KAAK,EACZ,uBAAuB,EAAE,EAAE,MAAM,EAAE,0BAA0B,SAAS,uBAAuB,EAAE,GAC/F,CACH,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,MAAM,CACpB,SAA2B,EAC3B,UAAkB,EAClB,UAAmB;IAEnB,MAAM,YAAY,GAAG,UAAU,IAAI,SAAS,CAAC,WAAW,IAAI,SAAS,CAAC,IAAI,IAAI,iBAAiB,CAAC;IAC/F,SAAiB,CAAC,YAAY,GAAG,UAAU,CAAC;IAC5C,SAAiB,CAAC,YAAY,GAAG,YAAY,CAAC;IAE/C,MAAM,aAAa,GAAG,CAAC,KAAiH,EAAE,EAAE;QAC1I,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,cAAc,EAAE,GAAG,KAAK,CAAC;QAClE,OAAO,CACL,KAAC,MAAM,IACL,IAAI,EAAE,YAAY,EAClB,GAAG,EAAE,UAAU,EACf,SAAS,EAAE,SAAS,EACpB,KAAK,EAAE,cAAmB,EAC1B,MAAM,EAAE,MAAM,EACd,EAAE,EAAE,EAAE,EACN,SAAS,EAAE,SAAS,EACpB,KAAK,EAAE,KAAK,GACZ,CACH,CAAC;IACJ,CAAC,CAAC;IAEF,aAAa,CAAC,WAAW,GAAG,UAAU,YAAY,GAAG,CAAC;IACrD,aAAqB,CAAC,YAAY,GAAG,UAAU,CAAC;IAChD,aAAqB,CAAC,YAAY,GAAG,YAAY,CAAC;IAClD,aAAqB,CAAC,cAAc,GAAG,SAAS,CAAC;IAClD,OAAO,aAAa,CAAC;AACvB,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface LoadedPage {
|
|
2
|
+
Component: React.ComponentType<any>;
|
|
3
|
+
metadata?: {
|
|
4
|
+
title?: string;
|
|
5
|
+
description?: string;
|
|
6
|
+
[key: string]: unknown;
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
export declare function loadPageModule(pageFilePath: string): Promise<LoadedPage>;
|
|
10
|
+
export declare function clearCache(): Promise<void>;
|
|
11
|
+
//# sourceMappingURL=loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/core/loader.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,KAAK,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;IACpC,QAAQ,CAAC,EAAE;QACT,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;KACxB,CAAC;CACH;AAyBD,wBAAsB,cAAc,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CA0C9E;AAED,wBAAsB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAMhD"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import * as esbuild from 'esbuild';
|
|
2
|
+
import fs from 'node:fs/promises';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import crypto from 'node:crypto';
|
|
5
|
+
import { pathToFileURL } from 'node:url';
|
|
6
|
+
const CACHE_DIR = path.resolve(process.cwd(), '.react-html/cache');
|
|
7
|
+
// Plugin to replace import.meta.url with the real source file URL
|
|
8
|
+
const importMetaUrlPlugin = {
|
|
9
|
+
name: 'preserve-import-meta-url',
|
|
10
|
+
setup(build) {
|
|
11
|
+
build.onLoad({ filter: /\.(tsx|ts|jsx|js)$/ }, async (args) => {
|
|
12
|
+
if (args.path.includes('node_modules'))
|
|
13
|
+
return null;
|
|
14
|
+
let text = await fs.readFile(args.path, 'utf8');
|
|
15
|
+
if (text.includes('import.meta.url')) {
|
|
16
|
+
const fileUrl = pathToFileURL(args.path).href;
|
|
17
|
+
text = text.replaceAll('import.meta.url', JSON.stringify(fileUrl));
|
|
18
|
+
const ext = path.extname(args.path).slice(1);
|
|
19
|
+
return {
|
|
20
|
+
contents: text,
|
|
21
|
+
loader: (ext === 'js' || ext === 'jsx' || ext === 'ts' || ext === 'tsx') ? ext : 'tsx'
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
return null;
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
export async function loadPageModule(pageFilePath) {
|
|
29
|
+
await fs.mkdir(CACHE_DIR, { recursive: true });
|
|
30
|
+
const resolvedPath = path.resolve(pageFilePath);
|
|
31
|
+
const hash = crypto.createHash('sha256').update(resolvedPath).digest('hex').slice(0, 12);
|
|
32
|
+
const cacheFilePath = path.join(CACHE_DIR, `page-${hash}.mjs`);
|
|
33
|
+
// Build the page bundle for Node.js execution
|
|
34
|
+
await esbuild.build({
|
|
35
|
+
entryPoints: [resolvedPath],
|
|
36
|
+
outfile: cacheFilePath,
|
|
37
|
+
bundle: true,
|
|
38
|
+
format: 'esm',
|
|
39
|
+
platform: 'node',
|
|
40
|
+
target: 'node22',
|
|
41
|
+
packages: 'external',
|
|
42
|
+
sourcemap: 'inline',
|
|
43
|
+
plugins: [importMetaUrlPlugin],
|
|
44
|
+
loader: {
|
|
45
|
+
'.tsx': 'tsx',
|
|
46
|
+
'.ts': 'ts',
|
|
47
|
+
'.jsx': 'jsx',
|
|
48
|
+
'.js': 'js',
|
|
49
|
+
'.css': 'empty'
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
// Dynamic import with timestamp cache buster
|
|
53
|
+
const fileUrl = `${pathToFileURL(cacheFilePath).href}?t=${Date.now()}`;
|
|
54
|
+
const importedModule = await import(fileUrl);
|
|
55
|
+
const Component = importedModule.default;
|
|
56
|
+
if (!Component) {
|
|
57
|
+
throw new Error(`Page "${pageFilePath}" does not have a default export. Please provide "export default function Page()".`);
|
|
58
|
+
}
|
|
59
|
+
const { default: _, ...metadata } = importedModule;
|
|
60
|
+
return {
|
|
61
|
+
Component,
|
|
62
|
+
metadata
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
export async function clearCache() {
|
|
66
|
+
try {
|
|
67
|
+
await fs.rm(CACHE_DIR, { recursive: true, force: true });
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
// Ignore cache cleanup errors
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/core/loader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { IslandInstance } from './island-registry.js';
|
|
3
|
+
export interface RenderResult {
|
|
4
|
+
html: string;
|
|
5
|
+
islands: IslandInstance[];
|
|
6
|
+
}
|
|
7
|
+
export interface RenderOptions {
|
|
8
|
+
pagePath: string;
|
|
9
|
+
Component: React.ComponentType<any>;
|
|
10
|
+
props?: Record<string, unknown>;
|
|
11
|
+
metadata?: {
|
|
12
|
+
title?: string;
|
|
13
|
+
description?: string;
|
|
14
|
+
lang?: string;
|
|
15
|
+
[key: string]: unknown;
|
|
16
|
+
};
|
|
17
|
+
basePath?: string;
|
|
18
|
+
}
|
|
19
|
+
export declare function renderPageToHtml(options: RenderOptions): RenderResult;
|
|
20
|
+
//# sourceMappingURL=renderer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../src/core/renderer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAwB,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAG5E,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,cAAc,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,KAAK,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;IACpC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,QAAQ,CAAC,EAAE;QACT,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;KACxB,CAAC;IACF,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,aAAa,GAAG,YAAY,CAuDrE"}
|