@punkestu/react-html 0.1.0 → 1.0.0

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.
Files changed (93) hide show
  1. package/README.md +72 -15
  2. package/dist/cli/docs-content.d.ts +8 -0
  3. package/dist/cli/docs-content.d.ts.map +1 -0
  4. package/dist/cli/docs-content.js +328 -0
  5. package/dist/cli/docs-content.js.map +1 -0
  6. package/dist/cli/index.d.ts +2 -0
  7. package/dist/cli/index.d.ts.map +1 -0
  8. package/dist/cli/index.js +135 -0
  9. package/dist/cli/index.js.map +1 -0
  10. package/dist/cli/tui-docs.d.ts +5 -0
  11. package/dist/cli/tui-docs.d.ts.map +1 -0
  12. package/dist/cli/tui-docs.js +191 -0
  13. package/dist/cli/tui-docs.js.map +1 -0
  14. package/dist/client/hydrate.d.ts +4 -0
  15. package/dist/client/hydrate.d.ts.map +1 -0
  16. package/dist/client/hydrate.js +80 -0
  17. package/dist/client/hydrate.js.map +1 -0
  18. package/dist/core/bundler.d.ts +9 -0
  19. package/dist/core/bundler.d.ts.map +1 -0
  20. package/dist/core/bundler.js +245 -0
  21. package/dist/core/bundler.js.map +1 -0
  22. package/dist/core/formatter.d.ts +6 -0
  23. package/dist/core/formatter.d.ts.map +1 -0
  24. package/dist/core/formatter.js +74 -0
  25. package/dist/core/formatter.js.map +1 -0
  26. package/dist/core/island-client.d.ts +9 -0
  27. package/dist/core/island-client.d.ts.map +1 -0
  28. package/dist/core/island-client.js +8 -0
  29. package/dist/core/island-client.js.map +1 -0
  30. package/dist/core/island-discovery.d.ts +19 -0
  31. package/dist/core/island-discovery.d.ts.map +1 -0
  32. package/dist/core/island-discovery.js +92 -0
  33. package/dist/core/island-discovery.js.map +1 -0
  34. package/dist/core/island-registry.d.ts +15 -0
  35. package/dist/core/island-registry.d.ts.map +1 -0
  36. package/dist/core/island-registry.js +17 -0
  37. package/dist/core/island-registry.js.map +1 -0
  38. package/dist/core/island.d.ts +32 -0
  39. package/dist/core/island.d.ts.map +1 -0
  40. package/dist/core/island.js +47 -0
  41. package/dist/core/island.js.map +1 -0
  42. package/dist/core/loader.d.ts +11 -0
  43. package/dist/core/loader.d.ts.map +1 -0
  44. package/dist/core/loader.js +87 -0
  45. package/dist/core/loader.js.map +1 -0
  46. package/dist/core/renderer.d.ts +20 -0
  47. package/dist/core/renderer.d.ts.map +1 -0
  48. package/dist/core/renderer.js +53 -0
  49. package/dist/core/renderer.js.map +1 -0
  50. package/dist/index.d.ts +27 -0
  51. package/dist/index.d.ts.map +1 -0
  52. package/dist/index.js +110 -0
  53. package/dist/index.js.map +1 -0
  54. package/dist/server/dev-server.d.ts +8 -0
  55. package/dist/server/dev-server.d.ts.map +1 -0
  56. package/dist/server/dev-server.js +112 -0
  57. package/dist/server/dev-server.js.map +1 -0
  58. package/dist/server/engine.d.ts +50 -0
  59. package/dist/server/engine.d.ts.map +1 -0
  60. package/dist/server/engine.js +225 -0
  61. package/dist/server/engine.js.map +1 -0
  62. package/{src/server/index.ts → dist/server/index.d.ts} +1 -1
  63. package/dist/server/index.d.ts.map +1 -0
  64. package/dist/server/index.js +3 -0
  65. package/dist/server/index.js.map +1 -0
  66. package/package.json +5 -1
  67. package/.react-html/cache/page-fefe905ae5d2.mjs +0 -9
  68. package/DOCS.md +0 -317
  69. package/example/public/styles.css +0 -184
  70. package/example/src/components/Card.tsx +0 -17
  71. package/example/src/components/Counter.island.tsx +0 -35
  72. package/example/src/components/Footer.tsx +0 -13
  73. package/example/src/components/Header.tsx +0 -20
  74. package/example/src/components/Layout.tsx +0 -39
  75. package/example/src/components/Tabs.island.tsx +0 -59
  76. package/example/src/pages/index.tsx +0 -49
  77. package/example/src/pages/pure.tsx +0 -56
  78. package/src/cli/docs-content.ts +0 -268
  79. package/src/cli/index.ts +0 -113
  80. package/src/cli/tui-docs.ts +0 -214
  81. package/src/client/hydrate.ts +0 -84
  82. package/src/core/bundler.ts +0 -122
  83. package/src/core/formatter.ts +0 -92
  84. package/src/core/island-client.ts +0 -23
  85. package/src/core/island-registry.ts +0 -35
  86. package/src/core/island.tsx +0 -110
  87. package/src/core/loader.ts +0 -89
  88. package/src/core/renderer.ts +0 -80
  89. package/src/index.ts +0 -138
  90. package/src/server/dev-server.ts +0 -125
  91. package/src/server/engine.ts +0 -270
  92. package/tests/engine.test.mjs +0 -288
  93. package/tsconfig.json +0 -21
@@ -0,0 +1,191 @@
1
+ import readline from 'node:readline';
2
+ import { DOC_SECTIONS } from './docs-content.js';
3
+ // ANSI escape sequences
4
+ const CLEAR = '\x1b[2J\x1b[H';
5
+ const HIDE_CURSOR = '\x1b[?25l';
6
+ const SHOW_CURSOR = '\x1b[?25h';
7
+ const BOLD = '\x1b[1m';
8
+ const DIM = '\x1b[2m';
9
+ const RESET = '\x1b[0m';
10
+ const CYAN = '\x1b[36m';
11
+ const GREEN = '\x1b[32m';
12
+ const YELLOW = '\x1b[33m';
13
+ const BLUE = '\x1b[34m';
14
+ const MAGENTA = '\x1b[35m';
15
+ const INVERT = '\x1b[7m';
16
+ function formatLine(line) {
17
+ if (line.startsWith('# ')) {
18
+ return `${BOLD}${CYAN}${line}${RESET}`;
19
+ }
20
+ if (line.startsWith('* ')) {
21
+ return `${BOLD}${GREEN}${line}${RESET}`;
22
+ }
23
+ if (line.startsWith('//') || line.startsWith(' $ ')) {
24
+ return `${YELLOW}${line}${RESET}`;
25
+ }
26
+ if (line.includes('├──') || line.includes('└──') || line.includes('│')) {
27
+ return `${DIM}${line}${RESET}`;
28
+ }
29
+ return line;
30
+ }
31
+ export function printSectionDirect(section) {
32
+ console.log(`\n${BOLD}${CYAN}=== ${section.title} ===${RESET}\n`);
33
+ for (const line of section.content) {
34
+ console.log(formatLine(line));
35
+ }
36
+ console.log('');
37
+ }
38
+ export function printAllDocs() {
39
+ console.log(`\n${BOLD}${CYAN}====================================================${RESET}`);
40
+ console.log(`${BOLD}${CYAN} ⚛️ REACT-HTML COMPLETE MANUAL ${RESET}`);
41
+ console.log(`${BOLD}${CYAN}====================================================${RESET}\n`);
42
+ for (const sec of DOC_SECTIONS) {
43
+ printSectionDirect(sec);
44
+ console.log(`${DIM}${'─'.repeat(60)}${RESET}\n`);
45
+ }
46
+ }
47
+ export async function launchDocsTui(initialArg) {
48
+ // If specific section or --all requested non-interactively
49
+ if (initialArg === '--all' || initialArg === '-a') {
50
+ printAllDocs();
51
+ return;
52
+ }
53
+ if (initialArg) {
54
+ const match = DOC_SECTIONS.find((s, idx) => s.id.toLowerCase() === initialArg.toLowerCase() ||
55
+ String(idx + 1) === initialArg ||
56
+ s.title.toLowerCase().includes(initialArg.toLowerCase()));
57
+ if (match) {
58
+ printSectionDirect(match);
59
+ return;
60
+ }
61
+ }
62
+ // Non-TTY fallback
63
+ if (!process.stdin.isTTY || !process.stdout.isTTY) {
64
+ printAllDocs();
65
+ return;
66
+ }
67
+ let selectedIndex = 0;
68
+ let viewMode = 'menu';
69
+ let scrollOffset = 0;
70
+ readline.emitKeypressEvents(process.stdin);
71
+ process.stdin.setRawMode(true);
72
+ process.stdout.write(HIDE_CURSOR);
73
+ function cleanup() {
74
+ process.stdout.write(SHOW_CURSOR);
75
+ if (process.stdin.isTTY) {
76
+ process.stdin.setRawMode(false);
77
+ }
78
+ process.stdin.pause();
79
+ console.clear();
80
+ }
81
+ function renderMenu() {
82
+ const termWidth = Math.max(process.stdout.columns || 80, 60);
83
+ const border = '═'.repeat(Math.min(termWidth - 2, 70));
84
+ let out = CLEAR;
85
+ out += `${CYAN}╔${border}╗${RESET}\n`;
86
+ out += `${CYAN}║${BOLD} ⚛️ REACT-HTML TERMINAL DOCUMENTATION (TUI) ${RESET}${CYAN}║${RESET}\n`;
87
+ out += `${CYAN}║${DIM} Modular pure HTML with selective reactive islands compilation ${RESET}${CYAN}║${RESET}\n`;
88
+ out += `${CYAN}╚${border}╝${RESET}\n\n`;
89
+ out += `${BOLD}Select a topic using arrow keys and press [Enter]:${RESET}\n\n`;
90
+ DOC_SECTIONS.forEach((sec, idx) => {
91
+ const isSelected = idx === selectedIndex;
92
+ if (isSelected) {
93
+ out += ` ${BOLD}${CYAN}▶ ${INVERT} ${sec.title} ${RESET}\n`;
94
+ out += ` ${DIM}${sec.summary}${RESET}\n\n`;
95
+ }
96
+ else {
97
+ out += ` ${BOLD}${sec.title}${RESET}\n`;
98
+ out += ` ${DIM}${sec.summary}${RESET}\n\n`;
99
+ }
100
+ });
101
+ out += `\n${DIM}${'─'.repeat(Math.min(termWidth - 2, 70))}${RESET}\n`;
102
+ out += `${BOLD}[↑/↓ or j/k]${RESET} Navigate ${BOLD}[Enter]${RESET} Read ${BOLD}[q / Ctrl+C]${RESET} Exit\n`;
103
+ process.stdout.write(out);
104
+ }
105
+ function renderReader() {
106
+ const sec = DOC_SECTIONS[selectedIndex];
107
+ const termHeight = Math.max(process.stdout.rows || 24, 15);
108
+ const termWidth = Math.max(process.stdout.columns || 80, 60);
109
+ const contentRows = termHeight - 8;
110
+ const visibleLines = sec.content.slice(scrollOffset, scrollOffset + contentRows);
111
+ let out = CLEAR;
112
+ out += `${CYAN}${BOLD}⚛️ react-html :: ${sec.title}${RESET}\n`;
113
+ out += `${DIM}${'═'.repeat(Math.min(termWidth - 2, 70))}${RESET}\n\n`;
114
+ for (const line of visibleLines) {
115
+ out += formatLine(line) + '\n';
116
+ }
117
+ // Fill blank lines if content is short
118
+ for (let i = visibleLines.length; i < contentRows; i++) {
119
+ out += '\n';
120
+ }
121
+ const maxScroll = Math.max(0, sec.content.length - contentRows);
122
+ const scrollInfo = maxScroll > 0 ? ` [Line ${scrollOffset + 1}/${sec.content.length}]` : '';
123
+ out += `\n${DIM}${'─'.repeat(Math.min(termWidth - 2, 70))}${RESET}\n`;
124
+ out += `${BOLD}[↑/↓ or j/k]${RESET} Scroll${scrollInfo} ${BOLD}[b / Esc]${RESET} Back to Menu ${BOLD}[q]${RESET} Quit\n`;
125
+ process.stdout.write(out);
126
+ }
127
+ function draw() {
128
+ if (viewMode === 'menu') {
129
+ renderMenu();
130
+ }
131
+ else {
132
+ renderReader();
133
+ }
134
+ }
135
+ draw();
136
+ return new Promise((resolve) => {
137
+ process.stdin.on('keypress', (str, key) => {
138
+ if ((key.ctrl && key.name === 'c') || key.name === 'q') {
139
+ cleanup();
140
+ resolve();
141
+ return;
142
+ }
143
+ if (viewMode === 'menu') {
144
+ if (key.name === 'up' || key.name === 'k') {
145
+ selectedIndex = (selectedIndex - 1 + DOC_SECTIONS.length) % DOC_SECTIONS.length;
146
+ draw();
147
+ }
148
+ else if (key.name === 'down' || key.name === 'j') {
149
+ selectedIndex = (selectedIndex + 1) % DOC_SECTIONS.length;
150
+ draw();
151
+ }
152
+ else if (key.name === 'return' || key.name === 'space') {
153
+ viewMode = 'reader';
154
+ scrollOffset = 0;
155
+ draw();
156
+ }
157
+ }
158
+ else if (viewMode === 'reader') {
159
+ const sec = DOC_SECTIONS[selectedIndex];
160
+ const termHeight = Math.max(process.stdout.rows || 24, 15);
161
+ const contentRows = termHeight - 8;
162
+ const maxScroll = Math.max(0, sec.content.length - contentRows);
163
+ if (key.name === 'escape' || key.name === 'b' || key.name === 'backspace') {
164
+ viewMode = 'menu';
165
+ draw();
166
+ }
167
+ else if (key.name === 'up' || key.name === 'k') {
168
+ if (scrollOffset > 0) {
169
+ scrollOffset--;
170
+ draw();
171
+ }
172
+ }
173
+ else if (key.name === 'down' || key.name === 'j') {
174
+ if (scrollOffset < maxScroll) {
175
+ scrollOffset++;
176
+ draw();
177
+ }
178
+ }
179
+ else if (key.name === 'pageup') {
180
+ scrollOffset = Math.max(0, scrollOffset - 5);
181
+ draw();
182
+ }
183
+ else if (key.name === 'pagedown') {
184
+ scrollOffset = Math.min(maxScroll, scrollOffset + 5);
185
+ draw();
186
+ }
187
+ }
188
+ });
189
+ });
190
+ }
191
+ //# sourceMappingURL=tui-docs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tui-docs.js","sourceRoot":"","sources":["../../src/cli/tui-docs.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import { ComponentType } from 'react';
2
+ export type ClientDirective = 'load' | 'idle' | 'visible';
3
+ export declare function hydrateIsland(islandName: string, Component: ComponentType<any>): void;
4
+ //# sourceMappingURL=hydrate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hydrate.d.ts","sourceRoot":"","sources":["../../src/client/hydrate.ts"],"names":[],"mappings":"AAAA,OAAc,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAG7C,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;AAE1D,wBAAgB,aAAa,CAC3B,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,aAAa,CAAC,GAAG,CAAC,GAC5B,IAAI,CA2EN"}
@@ -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,9 @@
1
+ import { IslandInstance } from './island-registry.js';
2
+ export type ClientRuntime = 'react' | 'preact';
3
+ export interface BundlerOptions {
4
+ outDir: string;
5
+ minify?: boolean;
6
+ clientRuntime?: ClientRuntime;
7
+ }
8
+ export declare function bundleIslands(islands: IslandInstance[], options: BundlerOptions): Promise<string[]>;
9
+ //# 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,MAAM,aAAa,GAAG,OAAO,GAAG,QAAQ,CAAC;AAE/C,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,aAAa,CAAC,EAAE,aAAa,CAAC;CAC/B;AAED,wBAAsB,aAAa,CACjC,OAAO,EAAE,cAAc,EAAE,EACzB,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,MAAM,EAAE,CAAC,CAgQnB"}
@@ -0,0 +1,245 @@
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, clientRuntime = 'react' } = 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
+ if (uniqueIslandsMap.size === 0) {
19
+ return [];
20
+ }
21
+ // Locate hydrate module
22
+ const currentDir = import.meta.dirname || path.dirname(fileURLToPath(import.meta.url));
23
+ let hydratePath = path.resolve(currentDir, '../client/hydrate.js');
24
+ if (!existsSync(hydratePath)) {
25
+ hydratePath = path.resolve(currentDir, '../client/hydrate.ts');
26
+ }
27
+ let islandClientPath = path.resolve(currentDir, './island-client.js');
28
+ if (!existsSync(islandClientPath)) {
29
+ islandClientPath = path.resolve(currentDir, './island-client.ts');
30
+ }
31
+ const vanillaEntries = {};
32
+ const reactEntries = {};
33
+ for (const [name, island] of uniqueIslandsMap.entries()) {
34
+ let resolvedEntry = island.entryPath;
35
+ if (resolvedEntry.startsWith('file://')) {
36
+ resolvedEntry = fileURLToPath(resolvedEntry);
37
+ }
38
+ else {
39
+ resolvedEntry = path.resolve(resolvedEntry);
40
+ }
41
+ let fileContent = '';
42
+ try {
43
+ fileContent = await fs.readFile(resolvedEntry, 'utf8');
44
+ }
45
+ catch {
46
+ console.warn(`[react-html] Warning: Island source file not found for "${name}" at "${resolvedEntry}". Skipping client bundle.`);
47
+ continue;
48
+ }
49
+ // Check if the island exports a vanilla DOM client function
50
+ const isVanilla = /\bexport\s+(function|const|let|var)\s+client\b/.test(fileContent);
51
+ const virtualEntryFile = path.join(tempDir, `${name}.entry.ts`);
52
+ if (isVanilla) {
53
+ // Pure Vanilla DOM Island entrypoint
54
+ const virtualEntryCode = `
55
+ import { client } from ${JSON.stringify(resolvedEntry)};
56
+
57
+ function init() {
58
+ document.querySelectorAll(${JSON.stringify(`[data-island="${name}"]`)}).forEach((el) => {
59
+ if (el.hasAttribute('data-hydrated')) return;
60
+
61
+ const rawProps = el.getAttribute('data-props');
62
+ let props = {};
63
+ if (rawProps) {
64
+ try { props = JSON.parse(rawProps); } catch (e) {}
65
+ }
66
+
67
+ const directive = el.getAttribute('data-client') || 'load';
68
+ const doMount = () => {
69
+ if (el.hasAttribute('data-hydrated')) return;
70
+ el.setAttribute('data-hydrated', 'true');
71
+ client(el as HTMLElement, props);
72
+ };
73
+
74
+ switch (directive) {
75
+ case 'idle': {
76
+ if ('requestIdleCallback' in window) {
77
+ (window as any).requestIdleCallback(doMount);
78
+ } else {
79
+ setTimeout(doMount, 200);
80
+ }
81
+ break;
82
+ }
83
+ case 'visible': {
84
+ if ('IntersectionObserver' in window) {
85
+ const obs = new IntersectionObserver((entries, observer) => {
86
+ entries.forEach((entry) => {
87
+ if (entry.isIntersecting) {
88
+ observer.disconnect();
89
+ doMount();
90
+ }
91
+ });
92
+ });
93
+ obs.observe(el);
94
+ } else {
95
+ doMount();
96
+ }
97
+ break;
98
+ }
99
+ case 'load':
100
+ default: {
101
+ if (document.readyState === 'loading') {
102
+ window.addEventListener('DOMContentLoaded', doMount, { once: true });
103
+ } else {
104
+ doMount();
105
+ }
106
+ break;
107
+ }
108
+ }
109
+ });
110
+ }
111
+
112
+ if (document.readyState === 'loading') {
113
+ window.addEventListener('DOMContentLoaded', init, { once: true });
114
+ } else {
115
+ init();
116
+ }
117
+ `;
118
+ await fs.writeFile(virtualEntryFile, virtualEntryCode, 'utf8');
119
+ vanillaEntries[name] = virtualEntryFile;
120
+ }
121
+ else {
122
+ // React / Preact Island entrypoint
123
+ const virtualEntryCode = `
124
+ import React from 'react';
125
+ import { hydrateIsland } from ${JSON.stringify(hydratePath)};
126
+ import * as Module from ${JSON.stringify(resolvedEntry)};
127
+
128
+ const mod: Record<string, any> = { ...Module };
129
+ const raw = mod.default ?? mod[${JSON.stringify(name)}] ?? mod;
130
+ const Component = (raw && raw.__rawComponent) ? raw.__rawComponent : raw;
131
+
132
+ hydrateIsland(${JSON.stringify(name)}, Component);
133
+ `;
134
+ await fs.writeFile(virtualEntryFile, virtualEntryCode, 'utf8');
135
+ reactEntries[name] = virtualEntryFile;
136
+ }
137
+ }
138
+ const bundledFiles = [];
139
+ // 1. Bundle Vanilla Islands: completely stub React so ZERO bytes of React/VDOM are included!
140
+ if (Object.keys(vanillaEntries).length > 0) {
141
+ const vanillaResult = await esbuild.build({
142
+ entryPoints: vanillaEntries,
143
+ outdir: islandsOutputDir,
144
+ bundle: true,
145
+ format: 'esm',
146
+ platform: 'browser',
147
+ target: ['es2022'],
148
+ minify,
149
+ treeShaking: true,
150
+ legalComments: 'none',
151
+ plugins: [
152
+ {
153
+ name: 'stub-react-for-vanilla',
154
+ setup(build) {
155
+ // Stub react, react/jsx-runtime and react-html
156
+ build.onResolve({ filter: /^(react|react\/.*|react-html|@punkestu\/react-html)$/ }, (args) => {
157
+ return { path: args.path, namespace: 'vanilla-empty-stub' };
158
+ });
159
+ build.onLoad({ filter: /.*/, namespace: 'vanilla-empty-stub' }, () => {
160
+ return {
161
+ contents: 'export default {}; export const jsx = () => {}; export const jsxs = () => {}; export const Fragment = ""; export function island(c){return c;}',
162
+ loader: 'js'
163
+ };
164
+ });
165
+ }
166
+ }
167
+ ],
168
+ loader: {
169
+ '.tsx': 'tsx',
170
+ '.ts': 'ts',
171
+ '.jsx': 'jsx',
172
+ '.js': 'js',
173
+ '.css': 'empty'
174
+ },
175
+ metafile: true
176
+ });
177
+ if (vanillaResult.metafile) {
178
+ for (const outPath of Object.keys(vanillaResult.metafile.outputs)) {
179
+ bundledFiles.push(path.resolve(process.cwd(), outPath));
180
+ }
181
+ }
182
+ }
183
+ // 2. Bundle React / Preact Islands with ESM code splitting
184
+ if (Object.keys(reactEntries).length > 0) {
185
+ const alias = {
186
+ 'react-html': islandClientPath,
187
+ ...(clientRuntime === 'preact'
188
+ ? {
189
+ react: 'preact/compat',
190
+ 'react-dom/client': 'preact/compat/client',
191
+ 'react-dom': 'preact/compat'
192
+ }
193
+ : {})
194
+ };
195
+ const reactResult = await esbuild.build({
196
+ entryPoints: reactEntries,
197
+ outdir: islandsOutputDir,
198
+ bundle: true,
199
+ format: 'esm',
200
+ platform: 'browser',
201
+ target: ['es2022'],
202
+ splitting: true,
203
+ chunkNames: 'chunks/[name]-[hash]',
204
+ minify,
205
+ treeShaking: true,
206
+ legalComments: 'none',
207
+ define: {
208
+ 'process.env.NODE_ENV': '"production"'
209
+ },
210
+ alias,
211
+ plugins: [
212
+ {
213
+ name: 'redirect-react-html-imports',
214
+ setup(build) {
215
+ build.onResolve({ filter: /(react-html|@punkestu\/react-html|(\/|\\)(src|dist)(\/|\\)index(\.js|\.mjs|\.ts)?)$/ }, () => {
216
+ return { path: islandClientPath };
217
+ });
218
+ }
219
+ }
220
+ ],
221
+ loader: {
222
+ '.tsx': 'tsx',
223
+ '.ts': 'ts',
224
+ '.jsx': 'jsx',
225
+ '.js': 'js',
226
+ '.css': 'empty'
227
+ },
228
+ metafile: true
229
+ });
230
+ if (reactResult.metafile) {
231
+ for (const outPath of Object.keys(reactResult.metafile.outputs)) {
232
+ bundledFiles.push(path.resolve(process.cwd(), outPath));
233
+ }
234
+ }
235
+ }
236
+ // Cleanup virtual entry files
237
+ try {
238
+ await fs.rm(tempDir, { recursive: true, force: true });
239
+ }
240
+ catch {
241
+ // Ignore cleanup error
242
+ }
243
+ return bundledFiles;
244
+ }
245
+ //# 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,6 @@
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 declare function formatHtml(html: string): string;
6
+ //# sourceMappingURL=formatter.d.ts.map
@@ -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