frontend-hamroun 1.2.88 → 1.2.90
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/hooks.d.ts +1 -1
- package/dist/hooks.d.ts.map +1 -1
- package/dist/hooks.js +23 -2
- package/dist/index.cjs +142 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +142 -5
- package/dist/index.js.map +1 -1
- package/dist/renderComponent.d.ts.map +1 -1
- package/dist/renderComponent.js +16 -8
- package/dist/server-renderer.js +10 -3
- package/package.json +1 -1
package/dist/hooks.d.ts
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
export declare function setRenderCallback(callback: any, element: any, container: any): void;
|
2
|
-
export declare function prepareRender(component?: any): number;
|
2
|
+
export declare function prepareRender(component?: any, isServerSideRender?: boolean): number;
|
3
3
|
export declare function finishRender(): void;
|
4
4
|
export declare function useState<T>(initial: T): [T, (newValue: T | ((prev: T) => T)) => void];
|
5
5
|
export declare function useEffect(callback: () => void | (() => void), deps?: any[]): void;
|
package/dist/hooks.d.ts.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"
|
1
|
+
{"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"AAmBA,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG,GAAG,IAAI,CAInF;AAED,wBAAgB,aAAa,CAAC,SAAS,GAAE,GAAU,EAAE,kBAAkB,GAAE,OAAe,GAAG,MAAM,CAYhG;AAED,wBAAgB,YAAY,IAAI,IAAI,CAInC;AAED,wBAAgB,QAAQ,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,IAAI,CAAC,CAyCrF;AAED,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,EAAE,IAAI,CAAC,EAAE,GAAG,EAAE,GAAG,IAAI,CAgCjF;AAED,wBAAgB,OAAO,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,IAAI,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,CAqB5D;AAED,wBAAgB,MAAM,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,GAAG;IAAE,OAAO,EAAE,CAAC,CAAA;CAAE,CAqBpD;AA2BD,wBAAgB,gBAAgB,IAAI,CAAC,KAAK,GAAG,IAAI,EAAE,MAAM,IAAI,CAAC,CAG7D;AAGD,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC"}
|
package/dist/hooks.js
CHANGED
@@ -2,6 +2,7 @@ import { batchUpdates, isBatching } from './batch.js';
|
|
2
2
|
// Current render ID counter
|
3
3
|
let currentRender = 0;
|
4
4
|
let renderContext = null;
|
5
|
+
let isSSR = false;
|
5
6
|
// State storage
|
6
7
|
const states = new Map();
|
7
8
|
const stateIndices = new Map();
|
@@ -17,15 +18,21 @@ export function setRenderCallback(callback, element, container) {
|
|
17
18
|
globalContainer = container;
|
18
19
|
currentElement = element;
|
19
20
|
}
|
20
|
-
export function prepareRender(component = null) {
|
21
|
+
export function prepareRender(component = null, isServerSideRender = false) {
|
21
22
|
currentRender++;
|
22
23
|
renderContext = component;
|
24
|
+
isSSR = isServerSideRender;
|
23
25
|
stateIndices.set(currentRender, 0);
|
26
|
+
// Initialize state array for this render if it doesn't exist
|
27
|
+
if (!states.has(currentRender)) {
|
28
|
+
states.set(currentRender, []);
|
29
|
+
}
|
24
30
|
return currentRender;
|
25
31
|
}
|
26
32
|
export function finishRender() {
|
27
33
|
renderContext = null;
|
28
|
-
currentRender
|
34
|
+
// Don't reset currentRender to 0 immediately to preserve state
|
35
|
+
// currentRender = 0;
|
29
36
|
}
|
30
37
|
export function useState(initial) {
|
31
38
|
if (!currentRender) {
|
@@ -41,6 +48,10 @@ export function useState(initial) {
|
|
41
48
|
}
|
42
49
|
const state = componentStates[index];
|
43
50
|
const setState = (newValue) => {
|
51
|
+
// For SSR, don't actually update state
|
52
|
+
if (isSSR) {
|
53
|
+
return;
|
54
|
+
}
|
44
55
|
const nextValue = typeof newValue === 'function'
|
45
56
|
? newValue(componentStates[index])
|
46
57
|
: newValue;
|
@@ -60,6 +71,12 @@ export function useState(initial) {
|
|
60
71
|
export function useEffect(callback, deps) {
|
61
72
|
if (!currentRender)
|
62
73
|
throw new Error("useEffect must be called within a render");
|
74
|
+
// Skip effects during SSR
|
75
|
+
if (isSSR) {
|
76
|
+
const effectIndex = stateIndices.get(currentRender) || 0;
|
77
|
+
stateIndices.set(currentRender, effectIndex + 1);
|
78
|
+
return;
|
79
|
+
}
|
63
80
|
const effectIndex = stateIndices.get(currentRender) || 0;
|
64
81
|
if (!effects.has(currentRender)) {
|
65
82
|
effects.set(currentRender, []);
|
@@ -116,6 +133,10 @@ export function useRef(initial) {
|
|
116
133
|
}
|
117
134
|
async function rerender(rendererId) {
|
118
135
|
try {
|
136
|
+
// Skip rerender during SSR
|
137
|
+
if (isSSR) {
|
138
|
+
return;
|
139
|
+
}
|
119
140
|
// Clean up effects
|
120
141
|
const componentEffects = effects.get(rendererId);
|
121
142
|
if (componentEffects) {
|
package/dist/index.cjs
CHANGED
@@ -142,6 +142,7 @@ function useContext(context) {
|
|
142
142
|
|
143
143
|
// Current render ID counter
|
144
144
|
let currentRender = 0;
|
145
|
+
let isSSR = false;
|
145
146
|
// State storage
|
146
147
|
const states = new Map();
|
147
148
|
const stateIndices = new Map();
|
@@ -157,13 +158,19 @@ function setRenderCallback(callback, element, container) {
|
|
157
158
|
globalContainer = container;
|
158
159
|
currentElement = element;
|
159
160
|
}
|
160
|
-
function prepareRender(component = null) {
|
161
|
+
function prepareRender(component = null, isServerSideRender = false) {
|
161
162
|
currentRender++;
|
163
|
+
isSSR = isServerSideRender;
|
162
164
|
stateIndices.set(currentRender, 0);
|
165
|
+
// Initialize state array for this render if it doesn't exist
|
166
|
+
if (!states.has(currentRender)) {
|
167
|
+
states.set(currentRender, []);
|
168
|
+
}
|
163
169
|
return currentRender;
|
164
170
|
}
|
165
171
|
function finishRender() {
|
166
|
-
currentRender
|
172
|
+
// Don't reset currentRender to 0 immediately to preserve state
|
173
|
+
// currentRender = 0;
|
167
174
|
}
|
168
175
|
function useState(initial) {
|
169
176
|
if (!currentRender) {
|
@@ -179,6 +186,10 @@ function useState(initial) {
|
|
179
186
|
}
|
180
187
|
const state = componentStates[index];
|
181
188
|
const setState = (newValue) => {
|
189
|
+
// For SSR, don't actually update state
|
190
|
+
if (isSSR) {
|
191
|
+
return;
|
192
|
+
}
|
182
193
|
const nextValue = typeof newValue === 'function'
|
183
194
|
? newValue(componentStates[index])
|
184
195
|
: newValue;
|
@@ -198,6 +209,12 @@ function useState(initial) {
|
|
198
209
|
function useEffect(callback, deps) {
|
199
210
|
if (!currentRender)
|
200
211
|
throw new Error("useEffect must be called within a render");
|
212
|
+
// Skip effects during SSR
|
213
|
+
if (isSSR) {
|
214
|
+
const effectIndex = stateIndices.get(currentRender) || 0;
|
215
|
+
stateIndices.set(currentRender, effectIndex + 1);
|
216
|
+
return;
|
217
|
+
}
|
201
218
|
const effectIndex = stateIndices.get(currentRender) || 0;
|
202
219
|
if (!effects.has(currentRender)) {
|
203
220
|
effects.set(currentRender, []);
|
@@ -254,6 +271,10 @@ function useRef(initial) {
|
|
254
271
|
}
|
255
272
|
async function rerender(rendererId) {
|
256
273
|
try {
|
274
|
+
// Skip rerender during SSR
|
275
|
+
if (isSSR) {
|
276
|
+
return;
|
277
|
+
}
|
257
278
|
// Clean up effects
|
258
279
|
const componentEffects = effects.get(rendererId);
|
259
280
|
if (componentEffects) {
|
@@ -304,8 +325,6 @@ async function render(element, container) {
|
|
304
325
|
}
|
305
326
|
catch (error) {
|
306
327
|
console.error('Error during render:', error);
|
307
|
-
// Clean up render context on error
|
308
|
-
finishRender();
|
309
328
|
throw error;
|
310
329
|
}
|
311
330
|
}
|
@@ -325,6 +344,123 @@ async function hydrate(element, container) {
|
|
325
344
|
}
|
326
345
|
}
|
327
346
|
|
347
|
+
async function renderToString(element) {
|
348
|
+
prepareRender(element); // Pass the element to establish render context
|
349
|
+
try {
|
350
|
+
const html = await renderNodeToString(element);
|
351
|
+
return html;
|
352
|
+
}
|
353
|
+
finally {
|
354
|
+
}
|
355
|
+
}
|
356
|
+
async function renderNodeToString(node) {
|
357
|
+
// Handle null, undefined, boolean
|
358
|
+
if (node == null || typeof node === 'boolean') {
|
359
|
+
return '';
|
360
|
+
}
|
361
|
+
// Handle primitives
|
362
|
+
if (typeof node === 'string' || typeof node === 'number') {
|
363
|
+
return escapeHtml(String(node));
|
364
|
+
}
|
365
|
+
// Handle arrays
|
366
|
+
if (Array.isArray(node)) {
|
367
|
+
const results = await Promise.all(node.map(child => renderNodeToString(child)));
|
368
|
+
return results.join('');
|
369
|
+
}
|
370
|
+
// Handle objects with type and props (React-like elements)
|
371
|
+
if (node && typeof node === 'object' && 'type' in node) {
|
372
|
+
const { type, props = {} } = node;
|
373
|
+
// Handle function components
|
374
|
+
if (typeof type === 'function') {
|
375
|
+
try {
|
376
|
+
// Set up a new render context for this component
|
377
|
+
const componentRenderId = prepareRender(type);
|
378
|
+
try {
|
379
|
+
const result = await type(props);
|
380
|
+
return await renderNodeToString(result);
|
381
|
+
}
|
382
|
+
finally {
|
383
|
+
finishRender();
|
384
|
+
}
|
385
|
+
}
|
386
|
+
catch (error) {
|
387
|
+
console.error('Error rendering component:', error);
|
388
|
+
return `<!-- Error rendering component: ${error.message} -->`;
|
389
|
+
}
|
390
|
+
}
|
391
|
+
// Handle DOM elements
|
392
|
+
if (typeof type === 'string') {
|
393
|
+
return await renderDOMElement(type, props);
|
394
|
+
}
|
395
|
+
}
|
396
|
+
// Fallback for other objects
|
397
|
+
if (typeof node === 'object') {
|
398
|
+
return escapeHtml(JSON.stringify(node));
|
399
|
+
}
|
400
|
+
return escapeHtml(String(node));
|
401
|
+
}
|
402
|
+
async function renderDOMElement(tagName, props) {
|
403
|
+
const { children, ...attrs } = props;
|
404
|
+
// Self-closing tags
|
405
|
+
const voidElements = new Set([
|
406
|
+
'area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input',
|
407
|
+
'link', 'meta', 'param', 'source', 'track', 'wbr'
|
408
|
+
]);
|
409
|
+
// Build attributes string
|
410
|
+
const attributeString = Object.entries(attrs)
|
411
|
+
.filter(([key, value]) => {
|
412
|
+
// Filter out React-specific props and event handlers
|
413
|
+
if (key.startsWith('on') || key === 'key' || key === 'ref')
|
414
|
+
return false;
|
415
|
+
if (value == null || value === false)
|
416
|
+
return false;
|
417
|
+
return true;
|
418
|
+
})
|
419
|
+
.map(([key, value]) => {
|
420
|
+
// Handle className -> class
|
421
|
+
if (key === 'className')
|
422
|
+
key = 'class';
|
423
|
+
// Handle boolean attributes
|
424
|
+
if (value === true)
|
425
|
+
return key;
|
426
|
+
// Handle style objects
|
427
|
+
if (key === 'style' && typeof value === 'object' && value !== null) {
|
428
|
+
const styleString = Object.entries(value)
|
429
|
+
.map(([prop, val]) => `${kebabCase(prop)}:${val}`)
|
430
|
+
.join(';');
|
431
|
+
return `style="${escapeHtml(styleString)}"`;
|
432
|
+
}
|
433
|
+
return `${key}="${escapeHtml(String(value))}"`;
|
434
|
+
})
|
435
|
+
.join(' ');
|
436
|
+
const openTag = `<${tagName}${attributeString ? ' ' + attributeString : ''}>`;
|
437
|
+
// Self-closing elements
|
438
|
+
if (voidElements.has(tagName)) {
|
439
|
+
return openTag.slice(0, -1) + '/>';
|
440
|
+
}
|
441
|
+
// Elements with children
|
442
|
+
const closeTag = `</${tagName}>`;
|
443
|
+
if (children != null) {
|
444
|
+
const childrenString = await renderNodeToString(children);
|
445
|
+
return openTag + childrenString + closeTag;
|
446
|
+
}
|
447
|
+
return openTag + closeTag;
|
448
|
+
}
|
449
|
+
function escapeHtml(text) {
|
450
|
+
const htmlEscapes = {
|
451
|
+
'&': '&',
|
452
|
+
'<': '<',
|
453
|
+
'>': '>',
|
454
|
+
'"': '"',
|
455
|
+
"'": ''',
|
456
|
+
'/': '/'
|
457
|
+
};
|
458
|
+
return text.replace(/[&<>"'/]/g, (match) => htmlEscapes[match]);
|
459
|
+
}
|
460
|
+
function kebabCase(str) {
|
461
|
+
return str.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`);
|
462
|
+
}
|
463
|
+
|
328
464
|
function arePropsEqual(oldProps, newProps) {
|
329
465
|
const oldKeys = Object.keys(oldProps).filter(k => k !== 'children');
|
330
466
|
const newKeys = Object.keys(newProps).filter(k => k !== 'children');
|
@@ -1026,6 +1162,7 @@ const frontendHamroun = {
|
|
1026
1162
|
// Rendering
|
1027
1163
|
render,
|
1028
1164
|
hydrate,
|
1165
|
+
renderToString,
|
1029
1166
|
// Hooks
|
1030
1167
|
useState,
|
1031
1168
|
useEffect,
|
@@ -1100,6 +1237,7 @@ exports.onComponentMounted = onComponentMounted;
|
|
1100
1237
|
exports.onComponentUnmounted = onComponentUnmounted;
|
1101
1238
|
exports.onComponentUpdated = onComponentUpdated;
|
1102
1239
|
exports.render = render;
|
1240
|
+
exports.renderToString = renderToString;
|
1103
1241
|
exports.shouldComponentUpdate = shouldComponentUpdate;
|
1104
1242
|
exports.thunk = thunk;
|
1105
1243
|
exports.useContext = useContext;
|
package/dist/index.cjs.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"index.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
1
|
+
{"version":3,"file":"index.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
package/dist/index.d.ts
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
export { jsx, jsxs, jsxDEV, Fragment, createElement } from './jsx-runtime.js';
|
2
2
|
export { render, hydrate } from './renderer.js';
|
3
|
+
export { renderToString } from './server-renderer.js';
|
3
4
|
export { useState, useEffect, useMemo, useRef, useContext, useErrorBoundary } from './hooks.js';
|
4
5
|
export { createContext } from './context.js';
|
5
6
|
export { batchUpdates } from './batch.js';
|
@@ -12,6 +13,7 @@ export { createStore, StoreProvider, useSelector, useDispatch, useStore, logger,
|
|
12
13
|
export { LifecycleEvents, emitAppInit, emitAppMounted, emitAppUpdated, emitAppError, emitAppDestroyed, emitComponentCreated, emitComponentMounted, emitComponentUpdated, emitComponentError, emitComponentUnmounted, onAppInit, onAppMounted, onAppUpdated, onAppError, onAppDestroyed, onComponentCreated, onComponentMounted, onComponentUpdated, onComponentError, onComponentUnmounted } from './lifecycle-events.js';
|
13
14
|
import { jsx, createElement } from './jsx-runtime.js';
|
14
15
|
import { render, hydrate } from './renderer.js';
|
16
|
+
import { renderToString } from './server-renderer.js';
|
15
17
|
import { useState, useEffect, useMemo, useRef, useContext, useErrorBoundary } from './hooks.js';
|
16
18
|
import { createContext } from './context.js';
|
17
19
|
import { batchUpdates } from './batch.js';
|
@@ -37,6 +39,7 @@ declare const frontendHamroun: {
|
|
37
39
|
createElement: typeof createElement;
|
38
40
|
render: typeof render;
|
39
41
|
hydrate: typeof hydrate;
|
42
|
+
renderToString: typeof renderToString;
|
40
43
|
useState: typeof useState;
|
41
44
|
useEffect: typeof useEffect;
|
42
45
|
useMemo: typeof useMemo;
|
package/dist/index.d.ts.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
@@ -138,6 +138,7 @@ function useContext(context) {
|
|
138
138
|
|
139
139
|
// Current render ID counter
|
140
140
|
let currentRender = 0;
|
141
|
+
let isSSR = false;
|
141
142
|
// State storage
|
142
143
|
const states = new Map();
|
143
144
|
const stateIndices = new Map();
|
@@ -153,13 +154,19 @@ function setRenderCallback(callback, element, container) {
|
|
153
154
|
globalContainer = container;
|
154
155
|
currentElement = element;
|
155
156
|
}
|
156
|
-
function prepareRender(component = null) {
|
157
|
+
function prepareRender(component = null, isServerSideRender = false) {
|
157
158
|
currentRender++;
|
159
|
+
isSSR = isServerSideRender;
|
158
160
|
stateIndices.set(currentRender, 0);
|
161
|
+
// Initialize state array for this render if it doesn't exist
|
162
|
+
if (!states.has(currentRender)) {
|
163
|
+
states.set(currentRender, []);
|
164
|
+
}
|
159
165
|
return currentRender;
|
160
166
|
}
|
161
167
|
function finishRender() {
|
162
|
-
currentRender
|
168
|
+
// Don't reset currentRender to 0 immediately to preserve state
|
169
|
+
// currentRender = 0;
|
163
170
|
}
|
164
171
|
function useState(initial) {
|
165
172
|
if (!currentRender) {
|
@@ -175,6 +182,10 @@ function useState(initial) {
|
|
175
182
|
}
|
176
183
|
const state = componentStates[index];
|
177
184
|
const setState = (newValue) => {
|
185
|
+
// For SSR, don't actually update state
|
186
|
+
if (isSSR) {
|
187
|
+
return;
|
188
|
+
}
|
178
189
|
const nextValue = typeof newValue === 'function'
|
179
190
|
? newValue(componentStates[index])
|
180
191
|
: newValue;
|
@@ -194,6 +205,12 @@ function useState(initial) {
|
|
194
205
|
function useEffect(callback, deps) {
|
195
206
|
if (!currentRender)
|
196
207
|
throw new Error("useEffect must be called within a render");
|
208
|
+
// Skip effects during SSR
|
209
|
+
if (isSSR) {
|
210
|
+
const effectIndex = stateIndices.get(currentRender) || 0;
|
211
|
+
stateIndices.set(currentRender, effectIndex + 1);
|
212
|
+
return;
|
213
|
+
}
|
197
214
|
const effectIndex = stateIndices.get(currentRender) || 0;
|
198
215
|
if (!effects.has(currentRender)) {
|
199
216
|
effects.set(currentRender, []);
|
@@ -250,6 +267,10 @@ function useRef(initial) {
|
|
250
267
|
}
|
251
268
|
async function rerender(rendererId) {
|
252
269
|
try {
|
270
|
+
// Skip rerender during SSR
|
271
|
+
if (isSSR) {
|
272
|
+
return;
|
273
|
+
}
|
253
274
|
// Clean up effects
|
254
275
|
const componentEffects = effects.get(rendererId);
|
255
276
|
if (componentEffects) {
|
@@ -300,8 +321,6 @@ async function render(element, container) {
|
|
300
321
|
}
|
301
322
|
catch (error) {
|
302
323
|
console.error('Error during render:', error);
|
303
|
-
// Clean up render context on error
|
304
|
-
finishRender();
|
305
324
|
throw error;
|
306
325
|
}
|
307
326
|
}
|
@@ -321,6 +340,123 @@ async function hydrate(element, container) {
|
|
321
340
|
}
|
322
341
|
}
|
323
342
|
|
343
|
+
async function renderToString(element) {
|
344
|
+
prepareRender(element); // Pass the element to establish render context
|
345
|
+
try {
|
346
|
+
const html = await renderNodeToString(element);
|
347
|
+
return html;
|
348
|
+
}
|
349
|
+
finally {
|
350
|
+
}
|
351
|
+
}
|
352
|
+
async function renderNodeToString(node) {
|
353
|
+
// Handle null, undefined, boolean
|
354
|
+
if (node == null || typeof node === 'boolean') {
|
355
|
+
return '';
|
356
|
+
}
|
357
|
+
// Handle primitives
|
358
|
+
if (typeof node === 'string' || typeof node === 'number') {
|
359
|
+
return escapeHtml(String(node));
|
360
|
+
}
|
361
|
+
// Handle arrays
|
362
|
+
if (Array.isArray(node)) {
|
363
|
+
const results = await Promise.all(node.map(child => renderNodeToString(child)));
|
364
|
+
return results.join('');
|
365
|
+
}
|
366
|
+
// Handle objects with type and props (React-like elements)
|
367
|
+
if (node && typeof node === 'object' && 'type' in node) {
|
368
|
+
const { type, props = {} } = node;
|
369
|
+
// Handle function components
|
370
|
+
if (typeof type === 'function') {
|
371
|
+
try {
|
372
|
+
// Set up a new render context for this component
|
373
|
+
const componentRenderId = prepareRender(type);
|
374
|
+
try {
|
375
|
+
const result = await type(props);
|
376
|
+
return await renderNodeToString(result);
|
377
|
+
}
|
378
|
+
finally {
|
379
|
+
finishRender();
|
380
|
+
}
|
381
|
+
}
|
382
|
+
catch (error) {
|
383
|
+
console.error('Error rendering component:', error);
|
384
|
+
return `<!-- Error rendering component: ${error.message} -->`;
|
385
|
+
}
|
386
|
+
}
|
387
|
+
// Handle DOM elements
|
388
|
+
if (typeof type === 'string') {
|
389
|
+
return await renderDOMElement(type, props);
|
390
|
+
}
|
391
|
+
}
|
392
|
+
// Fallback for other objects
|
393
|
+
if (typeof node === 'object') {
|
394
|
+
return escapeHtml(JSON.stringify(node));
|
395
|
+
}
|
396
|
+
return escapeHtml(String(node));
|
397
|
+
}
|
398
|
+
async function renderDOMElement(tagName, props) {
|
399
|
+
const { children, ...attrs } = props;
|
400
|
+
// Self-closing tags
|
401
|
+
const voidElements = new Set([
|
402
|
+
'area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input',
|
403
|
+
'link', 'meta', 'param', 'source', 'track', 'wbr'
|
404
|
+
]);
|
405
|
+
// Build attributes string
|
406
|
+
const attributeString = Object.entries(attrs)
|
407
|
+
.filter(([key, value]) => {
|
408
|
+
// Filter out React-specific props and event handlers
|
409
|
+
if (key.startsWith('on') || key === 'key' || key === 'ref')
|
410
|
+
return false;
|
411
|
+
if (value == null || value === false)
|
412
|
+
return false;
|
413
|
+
return true;
|
414
|
+
})
|
415
|
+
.map(([key, value]) => {
|
416
|
+
// Handle className -> class
|
417
|
+
if (key === 'className')
|
418
|
+
key = 'class';
|
419
|
+
// Handle boolean attributes
|
420
|
+
if (value === true)
|
421
|
+
return key;
|
422
|
+
// Handle style objects
|
423
|
+
if (key === 'style' && typeof value === 'object' && value !== null) {
|
424
|
+
const styleString = Object.entries(value)
|
425
|
+
.map(([prop, val]) => `${kebabCase(prop)}:${val}`)
|
426
|
+
.join(';');
|
427
|
+
return `style="${escapeHtml(styleString)}"`;
|
428
|
+
}
|
429
|
+
return `${key}="${escapeHtml(String(value))}"`;
|
430
|
+
})
|
431
|
+
.join(' ');
|
432
|
+
const openTag = `<${tagName}${attributeString ? ' ' + attributeString : ''}>`;
|
433
|
+
// Self-closing elements
|
434
|
+
if (voidElements.has(tagName)) {
|
435
|
+
return openTag.slice(0, -1) + '/>';
|
436
|
+
}
|
437
|
+
// Elements with children
|
438
|
+
const closeTag = `</${tagName}>`;
|
439
|
+
if (children != null) {
|
440
|
+
const childrenString = await renderNodeToString(children);
|
441
|
+
return openTag + childrenString + closeTag;
|
442
|
+
}
|
443
|
+
return openTag + closeTag;
|
444
|
+
}
|
445
|
+
function escapeHtml(text) {
|
446
|
+
const htmlEscapes = {
|
447
|
+
'&': '&',
|
448
|
+
'<': '<',
|
449
|
+
'>': '>',
|
450
|
+
'"': '"',
|
451
|
+
"'": ''',
|
452
|
+
'/': '/'
|
453
|
+
};
|
454
|
+
return text.replace(/[&<>"'/]/g, (match) => htmlEscapes[match]);
|
455
|
+
}
|
456
|
+
function kebabCase(str) {
|
457
|
+
return str.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`);
|
458
|
+
}
|
459
|
+
|
324
460
|
function arePropsEqual(oldProps, newProps) {
|
325
461
|
const oldKeys = Object.keys(oldProps).filter(k => k !== 'children');
|
326
462
|
const newKeys = Object.keys(newProps).filter(k => k !== 'children');
|
@@ -1022,6 +1158,7 @@ const frontendHamroun = {
|
|
1022
1158
|
// Rendering
|
1023
1159
|
render,
|
1024
1160
|
hydrate,
|
1161
|
+
renderToString,
|
1025
1162
|
// Hooks
|
1026
1163
|
useState,
|
1027
1164
|
useEffect,
|
@@ -1054,5 +1191,5 @@ const frontendHamroun = {
|
|
1054
1191
|
eventBus: globalEventBus
|
1055
1192
|
};
|
1056
1193
|
|
1057
|
-
export { Component, Fragment, LifecycleEvents, Link, Redirect, Route, RouterProvider, StoreProvider, Switch, batchUpdates, createContext, createElement, createEventBus, createStore, frontendHamroun as default, diff, emitAppDestroyed, emitAppError, emitAppInit, emitAppMounted, emitAppUpdated, emitComponentCreated, emitComponentError, emitComponentMounted, emitComponentUnmounted, emitComponentUpdated, globalEventBus as eventBus, hydrate, jsx, jsx as jsxDEV, jsx as jsxs, logger, onAppDestroyed, onAppError, onAppInit, onAppMounted, onAppUpdated, onComponentCreated, onComponentError, onComponentMounted, onComponentUnmounted, onComponentUpdated, render, shouldComponentUpdate, thunk, useContext, useDispatch, useEffect, useErrorBoundary, useEvent, useForm, useLocation, useMemo, useNavigate, useParams, useRef, useSelector, useState, useStore };
|
1194
|
+
export { Component, Fragment, LifecycleEvents, Link, Redirect, Route, RouterProvider, StoreProvider, Switch, batchUpdates, createContext, createElement, createEventBus, createStore, frontendHamroun as default, diff, emitAppDestroyed, emitAppError, emitAppInit, emitAppMounted, emitAppUpdated, emitComponentCreated, emitComponentError, emitComponentMounted, emitComponentUnmounted, emitComponentUpdated, globalEventBus as eventBus, hydrate, jsx, jsx as jsxDEV, jsx as jsxs, logger, onAppDestroyed, onAppError, onAppInit, onAppMounted, onAppUpdated, onComponentCreated, onComponentError, onComponentMounted, onComponentUnmounted, onComponentUpdated, render, renderToString, shouldComponentUpdate, thunk, useContext, useDispatch, useEffect, useErrorBoundary, useEvent, useForm, useLocation, useMemo, useNavigate, useParams, useRef, useSelector, useState, useStore };
|
1058
1195
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
1
|
+
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"renderComponent.d.ts","sourceRoot":"","sources":["../src/renderComponent.ts"],"names":[],"mappings":"
|
1
|
+
{"version":3,"file":"renderComponent.d.ts","sourceRoot":"","sources":["../src/renderComponent.ts"],"names":[],"mappings":"AAMA;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,KAAK,CAAC;CACf;AAED;;GAEG;AACH,wBAAsB,eAAe,CAAC,SAAS,EAAE,GAAG,EAAE,KAAK,GAAE,GAAQ,GAAG,OAAO,CAAC,YAAY,CAAC,CA4B5F;AAED,eAAe,eAAe,CAAC"}
|
package/dist/renderComponent.js
CHANGED
@@ -2,19 +2,27 @@
|
|
2
2
|
* Utility for rendering components to strings and hydrating them
|
3
3
|
*/
|
4
4
|
import { renderToString } from './server-renderer.js';
|
5
|
+
import { prepareRender, finishRender } from './hooks.js';
|
5
6
|
/**
|
6
7
|
* Renders a component to an HTML string with error handling
|
7
8
|
*/
|
8
9
|
export async function renderComponent(Component, props = {}) {
|
9
10
|
try {
|
10
|
-
//
|
11
|
-
const
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
11
|
+
// Prepare render context for SSR
|
12
|
+
const renderId = prepareRender(Component, true);
|
13
|
+
try {
|
14
|
+
// Call the component function with props
|
15
|
+
const element = Component(props);
|
16
|
+
// Convert the element to an HTML string
|
17
|
+
const html = await renderToString(element);
|
18
|
+
return {
|
19
|
+
html,
|
20
|
+
success: true
|
21
|
+
};
|
22
|
+
}
|
23
|
+
finally {
|
24
|
+
finishRender();
|
25
|
+
}
|
18
26
|
}
|
19
27
|
catch (error) {
|
20
28
|
console.error('Error rendering component:', error);
|
package/dist/server-renderer.js
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
import { prepareRender, finishRender } from './hooks.js';
|
2
2
|
export async function renderToString(element) {
|
3
|
-
const renderId = prepareRender(
|
3
|
+
const renderId = prepareRender(element); // Pass the element to establish render context
|
4
4
|
try {
|
5
5
|
const html = await renderNodeToString(element);
|
6
6
|
return html;
|
@@ -29,8 +29,15 @@ async function renderNodeToString(node) {
|
|
29
29
|
// Handle function components
|
30
30
|
if (typeof type === 'function') {
|
31
31
|
try {
|
32
|
-
|
33
|
-
|
32
|
+
// Set up a new render context for this component
|
33
|
+
const componentRenderId = prepareRender(type);
|
34
|
+
try {
|
35
|
+
const result = await type(props);
|
36
|
+
return await renderNodeToString(result);
|
37
|
+
}
|
38
|
+
finally {
|
39
|
+
finishRender();
|
40
|
+
}
|
34
41
|
}
|
35
42
|
catch (error) {
|
36
43
|
console.error('Error rendering component:', error);
|