@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
@@ -1,288 +0,0 @@
1
- import { test, describe, before, after } from 'node:test';
2
- import assert from 'node:assert/strict';
3
- import fs from 'node:fs/promises';
4
- import path from 'node:path';
5
- import React from 'react';
6
- import { renderPageToHtml, build, Island, island } from '../dist/index.js';
7
-
8
- describe('react-html Engine Test Suite', () => {
9
- describe('Static HTML Rendering', () => {
10
- test('renders pure static component to HTML with zero script tags', () => {
11
- function StaticPage() {
12
- return React.createElement(
13
- 'div',
14
- { className: 'hero' },
15
- React.createElement('h1', null, 'Hello Pure World'),
16
- React.createElement('p', null, 'This is pure static HTML without JS.')
17
- );
18
- }
19
-
20
- const result = renderPageToHtml({
21
- pagePath: '/test/page.tsx',
22
- Component: StaticPage,
23
- metadata: { title: 'Static Test' }
24
- });
25
-
26
- assert.ok(result.html.includes('<!DOCTYPE html>'));
27
- assert.ok(result.html.includes('<title>Static Test</title>'));
28
- assert.ok(result.html.includes('<h1>Hello Pure World</h1>') || result.html.includes('Hello Pure World'));
29
- assert.ok(!result.html.includes('<script'));
30
- assert.equal(result.islands.length, 0);
31
- });
32
-
33
- test('preserves full html document when component returns html tag', () => {
34
- function FullDoc() {
35
- return React.createElement(
36
- 'html',
37
- { lang: 'fr' },
38
- React.createElement('head', null, React.createElement('title', null, 'French Page')),
39
- React.createElement('body', null, React.createElement('h1', null, 'Bonjour'))
40
- );
41
- }
42
-
43
- const result = renderPageToHtml({
44
- pagePath: '/test/french.tsx',
45
- Component: FullDoc
46
- });
47
-
48
- assert.ok(result.html.startsWith('<!DOCTYPE html>'));
49
- assert.ok(result.html.includes('<html lang="fr">'));
50
- assert.ok(result.html.includes('Bonjour'));
51
- assert.ok(!result.html.includes('<script'));
52
- });
53
- });
54
-
55
- describe('Reactive Island Architecture', () => {
56
- test('registers island and injects script tag for interactive component', () => {
57
- function MyCounter({ initial = 5 }) {
58
- return React.createElement('button', null, `Count: ${initial}`);
59
- }
60
-
61
- const InteractiveCounter = island(MyCounter, '/fake/path/Counter.tsx', 'MyCounter');
62
-
63
- function PageWithIsland() {
64
- return React.createElement(
65
- 'main',
66
- null,
67
- React.createElement('h1', null, 'Island Page'),
68
- React.createElement(InteractiveCounter, { initial: 10 })
69
- );
70
- }
71
-
72
- const result = renderPageToHtml({
73
- pagePath: '/test/island-page.tsx',
74
- Component: PageWithIsland
75
- });
76
-
77
- assert.equal(result.islands.length, 1);
78
- assert.equal(result.islands[0].name, 'MyCounter');
79
- assert.deepEqual(result.islands[0].props, { initial: 10 });
80
- assert.ok(result.html.includes('data-island="MyCounter"'));
81
- assert.ok(result.html.includes('data-props="{&quot;initial&quot;:10}"'));
82
- assert.ok(result.html.includes('<script type="module" src="/assets/islands/MyCounter.js">'));
83
- });
84
- });
85
-
86
- describe('End-to-End Build Pipeline', () => {
87
- const testFixtureDir = path.resolve(process.cwd(), '.test-fixture');
88
- const outDir = path.join(testFixtureDir, 'dist');
89
-
90
- before(async () => {
91
- await fs.mkdir(path.join(testFixtureDir, 'src/pages'), { recursive: true });
92
- await fs.mkdir(path.join(testFixtureDir, 'src/components'), { recursive: true });
93
-
94
- // Create a pure static page
95
- await fs.writeFile(
96
- path.join(testFixtureDir, 'src/pages/pure.tsx'),
97
- `
98
- import React from 'react';
99
- export const title = "Pure Static";
100
- export default function Pure() {
101
- return <div><h1>Zero JS</h1></div>;
102
- }
103
- `
104
- );
105
-
106
- // Create an island component
107
- await fs.writeFile(
108
- path.join(testFixtureDir, 'src/components/Toggle.island.tsx'),
109
- `
110
- import React, { useState } from 'react';
111
- import { island } from '${path.resolve(process.cwd(), 'dist/index.js')}';
112
- function ToggleComp({ label = 'Click' }) {
113
- const [on, setOn] = useState(false);
114
- return <button onClick={() => setOn(!on)}>{label}: {on ? 'ON' : 'OFF'}</button>;
115
- }
116
- export const Toggle = island(ToggleComp, import.meta.url, 'Toggle');
117
- export default Toggle;
118
- `
119
- );
120
-
121
- // Create a page using the island
122
- await fs.writeFile(
123
- path.join(testFixtureDir, 'src/pages/interactive.tsx'),
124
- `
125
- import React from 'react';
126
- import { Toggle } from '../components/Toggle.island.js';
127
- export default function Interactive() {
128
- return <div><h1>Interactive</h1><Toggle label="Power" /></div>;
129
- }
130
- `
131
- );
132
- });
133
-
134
- after(async () => {
135
- await fs.rm(testFixtureDir, { recursive: true, force: true });
136
- });
137
-
138
- test('builds static pages and bundles reactive islands correctly', async () => {
139
- const result = await build({
140
- root: testFixtureDir,
141
- outDir: 'dist',
142
- minify: true
143
- });
144
-
145
- assert.equal(result.pages.length, 2);
146
-
147
- // Check pure static HTML output: absolutely NO script tags
148
- const pureHtml = await fs.readFile(path.join(outDir, 'pure.html'), 'utf8');
149
- assert.ok(pureHtml.includes('Zero JS'));
150
- assert.ok(!pureHtml.includes('<script'));
151
-
152
- // Check interactive page HTML output: has island markup & script tag
153
- const interactiveHtml = await fs.readFile(path.join(outDir, 'interactive.html'), 'utf8');
154
- assert.ok(interactiveHtml.includes('Interactive'));
155
- assert.ok(interactiveHtml.includes('data-island="Toggle"'));
156
- assert.ok(interactiveHtml.includes('<script type="module" src="/assets/islands/Toggle.js">'));
157
-
158
- // Check island JS bundle was generated
159
- const islandJsExists = await fs.stat(path.join(outDir, 'assets/islands/Toggle.js')).then(() => true).catch(() => false);
160
- assert.ok(islandJsExists, 'Toggle.js island bundle should exist in assets/islands');
161
- });
162
- });
163
-
164
- describe('Terminal Documentation (TUI)', () => {
165
- test('contains comprehensive documentation sections', async () => {
166
- const { DOC_SECTIONS } = await import('../dist/cli/docs-content.js');
167
- assert.ok(DOC_SECTIONS.length >= 8, 'Expected at least 8 doc sections');
168
-
169
- const ids = DOC_SECTIONS.map(s => s.id);
170
- assert.ok(ids.includes('intro'));
171
- assert.ok(ids.includes('islands'));
172
- assert.ok(ids.includes('directives'));
173
- assert.ok(ids.includes('cli'));
174
- assert.ok(ids.includes('troubleshooting'));
175
- });
176
- });
177
-
178
- describe('Server Application Library (createEngine)', () => {
179
- const fixtureDir = path.resolve(process.cwd(), '.server-test-fixture');
180
- const pagesDir = path.join(fixtureDir, 'src/pages');
181
- const distDir = path.join(fixtureDir, 'dist');
182
-
183
- before(async () => {
184
- await fs.mkdir(pagesDir, { recursive: true });
185
- await fs.mkdir(distDir, { recursive: true });
186
-
187
- // Create pre-built production HTML in dist
188
- await fs.writeFile(
189
- path.join(distDir, 'index.html'),
190
- '<!DOCTYPE html><html><body><h1>PRE-BUILT PRODUCTION HTML</h1></body></html>'
191
- );
192
-
193
- // Create development source page in src/pages
194
- await fs.writeFile(
195
- path.join(pagesDir, 'index.tsx'),
196
- `
197
- import React from 'react';
198
- export default function Home() {
199
- return <h1>LIVE REBUILT DEV HTML</h1>;
200
- }
201
- `
202
- );
203
- });
204
-
205
- after(async () => {
206
- await fs.rm(fixtureDir, { recursive: true, force: true });
207
- });
208
-
209
- test('production mode: loads and returns pre-built static HTML from dist', async () => {
210
- const { createEngine } = await import('../dist/index.js');
211
- const engine = createEngine({
212
- root: fixtureDir,
213
- pagesDir,
214
- distDir,
215
- isProduction: true
216
- });
217
-
218
- const html = await engine.render('index');
219
- assert.ok(html.includes('PRE-BUILT PRODUCTION HTML'), 'Production should return pre-built dist HTML');
220
- assert.ok(!html.includes('LIVE REBUILT DEV HTML'));
221
- });
222
-
223
- test('development mode: dynamically rebuilds and returns fresh HTML string', async () => {
224
- const { createEngine } = await import('../dist/index.js');
225
- const engine = createEngine({
226
- root: fixtureDir,
227
- pagesDir,
228
- distDir,
229
- isProduction: false
230
- });
231
-
232
- const html = await engine.render('index');
233
- assert.ok(html.includes('LIVE REBUILT DEV HTML'), 'Development should rebuild from source TSX');
234
- assert.ok(!html.includes('PRE-BUILT PRODUCTION HTML'));
235
-
236
- // Modify the source file on the fly
237
- await fs.writeFile(
238
- path.join(pagesDir, 'index.tsx'),
239
- `
240
- import React from 'react';
241
- export default function Home() {
242
- return <h1>UPDATED LIVE IN DEV</h1>;
243
- }
244
- `
245
- );
246
-
247
- // Re-render: should reflect the immediate update without server restart!
248
- const updatedHtml = await engine.render('index');
249
- assert.ok(updatedHtml.includes('UPDATED LIVE IN DEV'), 'Dev mode should reflect immediate code edits');
250
- });
251
-
252
- test('middleware: serves request via connect/express-compatible middleware', async () => {
253
- const { createEngine } = await import('../dist/index.js');
254
- const engine = createEngine({
255
- root: fixtureDir,
256
- pagesDir,
257
- distDir,
258
- isProduction: true
259
- });
260
-
261
- let statusCode = 0;
262
- let headers = {};
263
- let body = '';
264
-
265
- const fakeReq = {
266
- url: '/',
267
- headers: { host: 'localhost:3000' }
268
- };
269
-
270
- const fakeRes = {
271
- writeHead(status, h) {
272
- statusCode = status;
273
- headers = h;
274
- },
275
- end(data) {
276
- body = data.toString();
277
- }
278
- };
279
-
280
- await engine.middleware(fakeReq, fakeRes);
281
-
282
- assert.equal(statusCode, 200);
283
- assert.equal(headers['Content-Type'], 'text/html; charset=utf-8');
284
- assert.ok(body.includes('PRE-BUILT PRODUCTION HTML'));
285
- });
286
- });
287
- });
288
-
package/tsconfig.json DELETED
@@ -1,21 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2022",
4
- "module": "NodeNext",
5
- "moduleResolution": "NodeNext",
6
- "lib": ["ES2022", "DOM", "DOM.Iterable"],
7
- "jsx": "react-jsx",
8
- "declaration": true,
9
- "declarationMap": true,
10
- "sourceMap": true,
11
- "outDir": "./dist",
12
- "rootDir": "./src",
13
- "strict": true,
14
- "esModuleInterop": true,
15
- "skipLibCheck": true,
16
- "forceConsistentCasingInFileNames": true
17
- },
18
- "include": ["src/**/*"],
19
- "exclude": ["node_modules", "dist", "example", "tests"]
20
- }
21
-