frontend-hamroun 1.1.47 → 1.1.49
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +255 -2
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +19 -18
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/templates/ssr-template/src/App.tsx +31 -21
- package/templates/ssr-template/src/client.tsx +19 -1
- package/templates/ssr-template/src/server.ts +29 -30
package/README.md
CHANGED
@@ -95,12 +95,222 @@ function ThemedButton() {
|
|
95
95
|
}
|
96
96
|
```
|
97
97
|
|
98
|
-
|
98
|
+
## Server-Side Rendering
|
99
99
|
|
100
|
+
### Quick Start
|
100
101
|
```tsx
|
102
|
+
// server.ts
|
101
103
|
import { renderToString } from 'frontend-hamroun';
|
102
104
|
|
103
|
-
const html = await renderToString(<App
|
105
|
+
const html = await renderToString(<App />, {
|
106
|
+
title: 'My SSR App',
|
107
|
+
description: 'A server-rendered application',
|
108
|
+
scripts: ['/client.js'],
|
109
|
+
initialState: {
|
110
|
+
user: { id: 1, name: 'John' }
|
111
|
+
}
|
112
|
+
});
|
113
|
+
```
|
114
|
+
|
115
|
+
### Complete SSR Setup
|
116
|
+
|
117
|
+
1. Server Setup:
|
118
|
+
```typescript
|
119
|
+
// server.ts
|
120
|
+
import express from 'express';
|
121
|
+
import { renderToString } from 'frontend-hamroun';
|
122
|
+
|
123
|
+
const app = express();
|
124
|
+
|
125
|
+
app.get('*', async (req, res) => {
|
126
|
+
try {
|
127
|
+
const html = await renderToString(<App />, {
|
128
|
+
title: 'My App',
|
129
|
+
description: 'Server-rendered app',
|
130
|
+
scripts: ['/client.js'],
|
131
|
+
styles: ['/styles.css'],
|
132
|
+
meta: {
|
133
|
+
'og:title': 'My App',
|
134
|
+
'theme-color': '#ffffff'
|
135
|
+
},
|
136
|
+
initialState: {
|
137
|
+
url: req.url,
|
138
|
+
user: req.user
|
139
|
+
},
|
140
|
+
bodyAttrs: { class: 'app-root' },
|
141
|
+
htmlAttrs: { lang: 'en' }
|
142
|
+
});
|
143
|
+
|
144
|
+
res.send(html);
|
145
|
+
} catch (error) {
|
146
|
+
res.status(500).send('Server Error');
|
147
|
+
}
|
148
|
+
});
|
149
|
+
```
|
150
|
+
|
151
|
+
2. Client Hydration:
|
152
|
+
```typescript
|
153
|
+
// client.tsx
|
154
|
+
import { hydrate } from 'frontend-hamroun';
|
155
|
+
|
156
|
+
// Type-safe state access
|
157
|
+
declare global {
|
158
|
+
interface Window {
|
159
|
+
__INITIAL_STATE__: {
|
160
|
+
url: string;
|
161
|
+
user?: { id: number; name: string };
|
162
|
+
}
|
163
|
+
}
|
164
|
+
}
|
165
|
+
|
166
|
+
const { url, user } = window.__INITIAL_STATE__;
|
167
|
+
|
168
|
+
hydrate(<App url={url} user={user} />, document.getElementById('root')!);
|
169
|
+
```
|
170
|
+
|
171
|
+
3. Template Customization:
|
172
|
+
```typescript
|
173
|
+
// Custom template options
|
174
|
+
interface TemplateOptions {
|
175
|
+
title: string;
|
176
|
+
description?: string;
|
177
|
+
scripts?: string[];
|
178
|
+
styles?: string[];
|
179
|
+
meta?: Record<string, string>;
|
180
|
+
initialState?: any;
|
181
|
+
bodyAttrs?: Record<string, string>;
|
182
|
+
htmlAttrs?: Record<string, string>;
|
183
|
+
}
|
184
|
+
```
|
185
|
+
|
186
|
+
### SSR Features
|
187
|
+
|
188
|
+
- ✨ Full HTML document generation
|
189
|
+
- 🔄 Automatic state hydration
|
190
|
+
- 🎨 Customizable templates
|
191
|
+
- 📱 Meta tags for SEO
|
192
|
+
- 🛡️ XSS protection
|
193
|
+
- 🚀 Streaming support
|
194
|
+
- 📦 Asset optimization
|
195
|
+
- 🔍 Error handling
|
196
|
+
|
197
|
+
### Best Practices
|
198
|
+
|
199
|
+
1. State Management:
|
200
|
+
```typescript
|
201
|
+
// Shared types between server and client
|
202
|
+
interface AppState {
|
203
|
+
url: string;
|
204
|
+
user?: UserData;
|
205
|
+
settings: AppSettings;
|
206
|
+
}
|
207
|
+
|
208
|
+
// Server
|
209
|
+
const state: AppState = {
|
210
|
+
url: req.url,
|
211
|
+
user: await getUser(req),
|
212
|
+
settings: await getSettings()
|
213
|
+
};
|
214
|
+
|
215
|
+
// Client
|
216
|
+
const { url, user, settings } = window.__INITIAL_STATE__ as AppState;
|
217
|
+
```
|
218
|
+
|
219
|
+
2. Error Handling:
|
220
|
+
```typescript
|
221
|
+
// Server-side error boundary
|
222
|
+
try {
|
223
|
+
const html = await renderToString(<App />, options);
|
224
|
+
res.send(html);
|
225
|
+
} catch (error) {
|
226
|
+
const errorHtml = await renderToString(
|
227
|
+
<ErrorPage error={error} />,
|
228
|
+
{ title: 'Error' }
|
229
|
+
);
|
230
|
+
res.status(500).send(errorHtml);
|
231
|
+
}
|
232
|
+
```
|
233
|
+
|
234
|
+
3. Performance Optimization:
|
235
|
+
```typescript
|
236
|
+
// Caching
|
237
|
+
const cached = await cache.get(cacheKey);
|
238
|
+
if (cached) return cached;
|
239
|
+
|
240
|
+
const html = await renderToString(<App />, {
|
241
|
+
...options,
|
242
|
+
scripts: [
|
243
|
+
{ src: '/client.js', async: true, defer: true }
|
244
|
+
]
|
245
|
+
});
|
246
|
+
|
247
|
+
await cache.set(cacheKey, html, '1h');
|
248
|
+
```
|
249
|
+
|
250
|
+
### Basic SSR Setup
|
251
|
+
|
252
|
+
```typescript
|
253
|
+
// Server-side rendering with customization
|
254
|
+
const html = await renderToString(<App />, {
|
255
|
+
title: 'My App',
|
256
|
+
description: 'Server-rendered application',
|
257
|
+
scripts: ['/assets/client.js'],
|
258
|
+
styles: ['/assets/styles.css'],
|
259
|
+
meta: {
|
260
|
+
'theme-color': '#ffffff',
|
261
|
+
'og:title': 'My App',
|
262
|
+
'og:description': 'My awesome app'
|
263
|
+
},
|
264
|
+
initialState: {
|
265
|
+
user: { name: 'John' }
|
266
|
+
},
|
267
|
+
bodyAttrs: { class: 'dark-mode' },
|
268
|
+
htmlAttrs: { lang: 'en', dir: 'ltr' }
|
269
|
+
});
|
270
|
+
```
|
271
|
+
|
272
|
+
### Express Server Integration
|
273
|
+
|
274
|
+
```typescript
|
275
|
+
import express from 'express';
|
276
|
+
import { renderToString } from 'frontend-hamroun';
|
277
|
+
|
278
|
+
const app = express();
|
279
|
+
|
280
|
+
app.get('*', async (req, res) => {
|
281
|
+
const initialState = {
|
282
|
+
url: req.url,
|
283
|
+
user: req.user // From your auth middleware
|
284
|
+
};
|
285
|
+
|
286
|
+
const html = await renderToString(<App />, {
|
287
|
+
title: 'My App',
|
288
|
+
scripts: ['/client.js'],
|
289
|
+
initialState
|
290
|
+
});
|
291
|
+
|
292
|
+
res.send(html);
|
293
|
+
});
|
294
|
+
```
|
295
|
+
|
296
|
+
### Client-Side Hydration
|
297
|
+
|
298
|
+
```typescript
|
299
|
+
import { hydrate } from 'frontend-hamroun';
|
300
|
+
|
301
|
+
// Access the server-provided state
|
302
|
+
declare global {
|
303
|
+
interface Window {
|
304
|
+
__INITIAL_STATE__: any;
|
305
|
+
}
|
306
|
+
}
|
307
|
+
|
308
|
+
const initialState = window.__INITIAL_STATE__;
|
309
|
+
|
310
|
+
hydrate(
|
311
|
+
<App initialState={initialState} />,
|
312
|
+
document.getElementById('root')!
|
313
|
+
);
|
104
314
|
```
|
105
315
|
|
106
316
|
## CLI Tools
|
@@ -140,6 +350,49 @@ npx create-frontend-app my-app
|
|
140
350
|
- Error boundaries
|
141
351
|
- Performance monitoring
|
142
352
|
|
353
|
+
## Advanced Features
|
354
|
+
|
355
|
+
### Template Customization
|
356
|
+
```typescript
|
357
|
+
interface TemplateOptions {
|
358
|
+
title: string;
|
359
|
+
description?: string;
|
360
|
+
scripts?: string[];
|
361
|
+
styles?: string[];
|
362
|
+
meta?: Record<string, string>;
|
363
|
+
initialState?: any;
|
364
|
+
bodyAttrs?: Record<string, string>;
|
365
|
+
htmlAttrs?: Record<string, string>;
|
366
|
+
}
|
367
|
+
|
368
|
+
// Usage with custom template
|
369
|
+
const html = await renderToString(<App />, {
|
370
|
+
title: 'Custom Template',
|
371
|
+
styles: ['/styles.css'],
|
372
|
+
bodyAttrs: { 'data-theme': 'dark' }
|
373
|
+
});
|
374
|
+
```
|
375
|
+
|
376
|
+
### Error Handling
|
377
|
+
```typescript
|
378
|
+
// Error boundary component
|
379
|
+
function ErrorBoundary({ children }) {
|
380
|
+
const [error, resetError] = useErrorBoundary();
|
381
|
+
|
382
|
+
if (error) {
|
383
|
+
return (
|
384
|
+
<div role="alert">
|
385
|
+
<h2>Something went wrong</h2>
|
386
|
+
<pre>{error.message}</pre>
|
387
|
+
<button onClick={resetError}>Try again</button>
|
388
|
+
</div>
|
389
|
+
);
|
390
|
+
}
|
391
|
+
|
392
|
+
return children;
|
393
|
+
}
|
394
|
+
```
|
395
|
+
|
143
396
|
## Contributing
|
144
397
|
|
145
398
|
1. Fork the repository
|
package/dist/index.d.ts
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
export { useState, useEffect, useMemo, useRef, useErrorBoundary } from './hooks';
|
2
|
+
export { createElement } from './jsx-runtime';
|
2
3
|
export { createContext, useContext } from './context';
|
3
4
|
export { batchUpdates } from './batch';
|
4
5
|
export { jsx, jsxs, Fragment } from './jsx-runtime';
|
package/dist/index.js
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});let e=!1;const t=[];function n(n){if(e)t.push(n);else{e=!0;try{for(n();t.length>0;){const e=t.shift();null==e||e()}}finally{e=!1}}}let r=0;const o=new Map,s=new Map,i=new Map,a=new Map,c=new Map;let l=null,p=null,u=null;const d="undefined"==typeof window,f=new Map;function h(t){if(!r)throw new Error("useState must be called within a render");if(d){f.has(r)||f.set(r,new Map);const e=f.get(r),n=s.get(r)||0;e.has(n)||e.set(n,t);const o=e.get(n),i=e=>{};return s.set(r,n+1),[o,i]}o.has(r)||o.set(r,[]);const i=o.get(r),a=s.get(r);a>=i.length&&i.push(t);const c=i[a];return s.set(r,a+1),[c,t=>{const o="function"==typeof t?t(i[a]):t;i[a]!==o&&(i[a]=o,e?n((()=>y(r))):y(r))}]}function w(e,t){if(!r)throw new Error("useEffect must be called within a render");const n=s.get(r);i.has(r)||i.set(r,[]);const o=i.get(r),a=o[n];a&&t&&a.deps&&!t.some(((e,t)=>e!==a.deps[t]))||((null==a?void 0:a.cleanup)&&a.cleanup(),queueMicrotask((()=>{const r=e()||void 0;o[n]={cleanup:r,deps:t}}))),s.set(r,n+1)}async function y(e){try{const t=i.get(e);t&&(t.forEach((e=>{e.cleanup&&e.cleanup()})),i.set(e,[])),l&&p&&u&&await l(u,p)}catch(t){console.error("Error during rerender:",t)}}function m(e,t){console.log("JSX Transform:",{type:e,props:t});const n={...t};return arguments.length>2&&(n.children=Array.prototype.slice.call(arguments,2)),{type:e,props:n}}async function g(e){var t;if(console.log("Creating element from:",e),null==e)return document.createTextNode("");if("boolean"==typeof e)return document.createTextNode("");if("number"==typeof e||"string"==typeof e)return document.createTextNode(String(e));if(Array.isArray(e)){const t=document.createDocumentFragment();for(const n of e){const e=await g(n);t.appendChild(e)}return t}if("type"in e&&void 0!==e.props){const{type:r,props:o}=e;if("function"==typeof r)try{const e=await r(o||{}),t=await g(e);return t instanceof Element&&t.setAttribute("data-component-id",r.name||r.toString()),t}catch(n){return console.error("Error rendering component:",n),document.createTextNode("")}const s=document.createElement(r);for(const[e,n]of Object.entries(o||{}))if("children"!==e)if(e.startsWith("on")&&"function"==typeof n){const r=e.toLowerCase().slice(2),o=null==(t=s.__events)?void 0:t[r];o&&s.removeEventListener(r,o),s.addEventListener(r,n),s.__events||(s.__events={}),s.__events[r]=n}else"style"===e&&"object"==typeof n?Object.assign(s.style,n):"className"===e?s.setAttribute("class",String(n)):"key"!==e&&"ref"!==e&&s.setAttribute(e,String(n));const i=null==o?void 0:o.children;if(null!=i){const e=Array.isArray(i)?i.flat():[i];for(const t of e){const e=await g(t);s.appendChild(e)}}return s}return document.createTextNode(String(e))}let b=!1;async function v(e,t){console.log("Rendering to:",t.id),n((async()=>{r++,s.set(r,0);try{!function(e,t,n){l=e,p=n,u=t}(v,e,t);const n=await g(e);b||(t.innerHTML=""),t.appendChild(n)}finally{d&&f.delete(r),r=0}}))}async function x(e){var t,n;if(null==e||"boolean"==typeof e)return"";if("number"==typeof e||"string"==typeof e)return $(String(e));if("function"==typeof e){return x(await e({}))}if(e.type){if("function"==typeof e.type){return x(await e.type(e.props||{}))}let r=`<${e.type}`;for(const[t,o]of Object.entries(e.props||{}))"children"!==t&&"key"!==t&&"ref"!==t&&("className"===t?r+=` class="${$(String(o))}"`:"style"===t&&"object"==typeof o&&null!==o?r+=` style="${n=o,Object.entries(n).map((([e,t])=>`${e}: ${t}`)).join("; ")}"`:t.startsWith("on")||(r+=` ${t}="${$(String(o))}"`));if(r+=">",null==(t=e.props)?void 0:t.children){const t=Array.isArray(e.props.children)?e.props.children:[e.props.children];for(const e of t)r+=await x(e)}return r+=`</${e.type}>`,r}return""}function $(e){return e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}let S={pathname:"undefined"!=typeof window?window.location.pathname:"/",search:"undefined"!=typeof window?window.location.search:"",hash:"undefined"!=typeof window?window.location.hash:"",params:{}};const E=new Set;function j(e,t={}){"undefined"!=typeof window&&function(e,t={}){const n=new URL(e,window.location.origin),r={pathname:n.pathname,search:n.search,hash:n.hash,params:{}};t.replace?window.history.replaceState(r,"",n.toString()):window.history.pushState(r,"",n.toString()),S=r,E.forEach((e=>e(r))),t.scroll&&window.scrollTo(0,0)}(e,t)}exports.Fragment=({children:e})=>e,exports.Link=function({href:e,children:t,replace:n=!1,className:r,style:o,...s}){return{type:"a",props:{href:e,onClick:t=>{t.preventDefault(),j(e,{replace:n})},className:r,style:o,...s,children:t}}},exports.batchUpdates=n,exports.createContext=function(e){return{Provider:({value:e,children:t})=>t,Consumer:({children:t})=>t(e),_id:Symbol(),useSelector:t=>t(e)}},exports.hydrate=async function(e,t){b=!0;try{await v(e,t)}finally{b=!1}},exports.jsx=m,exports.jsxs=m,exports.render=v,exports.renderToString=async function(e,t={}){try{return function(e,t){const{title:n,description:r="",scripts:o=[],styles:s=[],initialState:i={},meta:a={},bodyAttrs:c={},htmlAttrs:l={lang:"en"}}=t,p=Object.entries(l).map((([e,t])=>`${e}="${t}"`)).join(" "),u=Object.entries(c).map((([e,t])=>`${e}="${t}"`)).join(" ");return`<!DOCTYPE html>\n<html ${p}>\n <head>\n <meta charset="UTF-8">\n <meta name="viewport" content="width=device-width, initial-scale=1.0">\n ${r?`<meta name="description" content="${r}">\n`:""}${Object.entries(a).map((([e,t])=>` <meta name="${e}" content="${t}">`)).join("\n")}\n <title>${n}</title>\n${s.map((e=>` <link rel="stylesheet" href="${e}">`)).join("\n")}\n <script>\n window.__INITIAL_STATE__ = ${JSON.stringify(i)};\n <\/script>\n </head>\n <body ${u}>\n <div id="root">${e}</div>\n${o.map((e=>` <script src="${e}" defer><\/script>`)).join("\n")}\n </body>\n</html>`}(await x(e),{title:"Frontend Hamroun App",...t})}catch(n){return console.error("Error during server rendering:",n),""}},exports.useContext=function(e){return e},exports.useEffect=w,exports.useErrorBoundary=function(){const[e,t]=h(null);return[e,()=>t(null)]},exports.useMemo=function(e,t){if(!r)throw new Error("useMemo must be called within a render");const n=s.get(r);a.has(r)||a.set(r,[]);const o=a.get(r),i=o[n];if(!i||t&&t.some(((e,t)=>!Object.is(e,i.deps[t])))){const i=e();return o[n]={value:i,deps:t},s.set(r,n+1),i}return s.set(r,n+1),i.value},exports.useRef=function(e){if(!r)throw new Error("useRef must be called within a render");const t=s.get(r);c.has(r)||c.set(r,[]);const n=c.get(r);if(t>=n.length){const o={current:e};return n.push(o),s.set(r,t+1),o}const o=n[t];return s.set(r,t+1),o},exports.useRouter=function(){const[e,t]=h(S);return w((()=>{const e=e=>{t(e)},n=()=>{S={pathname:window.location.pathname,search:window.location.search,hash:window.location.hash,params:{}},t(S)};return E.add(e),window.addEventListener("popstate",n),()=>{E.delete(e),window.removeEventListener("popstate",n)}}),[]),{...e,push:(e,t)=>j(e,t),replace:(e,t)=>j(e,{...t,replace:!0}),back:()=>window.history.back(),forward:()=>window.history.forward()}},exports.useState=h;
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});let e=!1;const t=[];function n(n){if(e)t.push(n);else{e=!0;try{for(n();t.length>0;){const e=t.shift();null==e||e()}}finally{e=!1}}}let r=0;const o=new Map,s=new Map,i=new Map,a=new Map,c=new Map;let l=null,p=null,u=null;const d="undefined"==typeof window,f=new Map;function h(t){if(!r)throw new Error("useState must be called within a render");if(d){f.has(r)||f.set(r,new Map);const e=f.get(r),n=s.get(r)||0;e.has(n)||e.set(n,t);const o=e.get(n),i=e=>{};return s.set(r,n+1),[o,i]}o.has(r)||o.set(r,[]);const i=o.get(r),a=s.get(r);a>=i.length&&i.push(t);const c=i[a];return s.set(r,a+1),[c,t=>{const o="function"==typeof t?t(i[a]):t;i[a]!==o&&(i[a]=o,e?n((()=>y(r))):y(r))}]}function w(e,t){if(!r)throw new Error("useEffect must be called within a render");const n=s.get(r);i.has(r)||i.set(r,[]);const o=i.get(r),a=o[n];a&&t&&a.deps&&!t.some(((e,t)=>e!==a.deps[t]))||((null==a?void 0:a.cleanup)&&a.cleanup(),queueMicrotask((()=>{const r=e()||void 0;o[n]={cleanup:r,deps:t}}))),s.set(r,n+1)}async function y(e){try{const t=i.get(e);t&&(t.forEach((e=>{e.cleanup&&e.cleanup()})),i.set(e,[])),l&&p&&u&&await l(u,p)}catch(t){console.error("Error during rerender:",t)}}function m(e,t){console.log("JSX Transform:",{type:e,props:t});const n={...t};return arguments.length>2&&(n.children=Array.prototype.slice.call(arguments,2)),{type:e,props:n}}async function g(e){var t;if(console.log("Creating element from:",e),null==e)return document.createTextNode("");if("boolean"==typeof e)return document.createTextNode("");if("number"==typeof e||"string"==typeof e)return document.createTextNode(String(e));if(Array.isArray(e)){const t=document.createDocumentFragment();for(const n of e){const e=await g(n);t.appendChild(e)}return t}if("type"in e&&void 0!==e.props){const{type:r,props:o}=e;if("function"==typeof r)try{const e=await r(o||{}),t=await g(e);return t instanceof Element&&t.setAttribute("data-component-id",r.name||r.toString()),t}catch(n){return console.error("Error rendering component:",n),document.createTextNode("")}const s=document.createElement(r);for(const[e,n]of Object.entries(o||{}))if("children"!==e)if(e.startsWith("on")&&"function"==typeof n){const r=e.toLowerCase().slice(2),o=null==(t=s.__events)?void 0:t[r];o&&s.removeEventListener(r,o),s.addEventListener(r,n),s.__events||(s.__events={}),s.__events[r]=n}else"style"===e&&"object"==typeof n?Object.assign(s.style,n):"className"===e?s.setAttribute("class",String(n)):"key"!==e&&"ref"!==e&&s.setAttribute(e,String(n));const i=null==o?void 0:o.children;if(null!=i){const e=Array.isArray(i)?i.flat():[i];for(const t of e){const e=await g(t);s.appendChild(e)}}return s}return document.createTextNode(String(e))}let b=!1;async function v(e,t){console.log("Rendering to:",t.id),n((async()=>{r++,s.set(r,0);try{!function(e,t,n){l=e,p=n,u=t}(v,e,t);const n=await g(e);b||(t.innerHTML=""),t.appendChild(n)}finally{d&&f.delete(r),r=0}}))}async function x(e){var t,n;if(null==e||"boolean"==typeof e)return"";if("number"==typeof e||"string"==typeof e)return $(String(e));if("function"==typeof e){return x(await e({}))}if(e.type){if("function"==typeof e.type){return x(await e.type(e.props||{}))}let r=`<${e.type}`;for(const[t,o]of Object.entries(e.props||{}))"children"!==t&&"key"!==t&&"ref"!==t&&("className"===t?r+=` class="${$(String(o))}"`:"style"===t&&"object"==typeof o&&null!==o?r+=` style="${n=o,Object.entries(n).map((([e,t])=>`${e}: ${t}`)).join("; ")}"`:t.startsWith("on")||(r+=` ${t}="${$(String(o))}"`));if(r+=">",null==(t=e.props)?void 0:t.children){const t=Array.isArray(e.props.children)?e.props.children:[e.props.children];for(const e of t)r+=await x(e)}return r+=`</${e.type}>`,r}return""}function $(e){return e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}let S={pathname:"undefined"!=typeof window?window.location.pathname:"/",search:"undefined"!=typeof window?window.location.search:"",hash:"undefined"!=typeof window?window.location.hash:"",params:{}};const E=new Set;function j(e,t={}){"undefined"!=typeof window&&function(e,t={}){const n=new URL(e,window.location.origin),r={pathname:n.pathname,search:n.search,hash:n.hash,params:{}};t.replace?window.history.replaceState(r,"",n.toString()):window.history.pushState(r,"",n.toString()),S=r,E.forEach((e=>e(r))),t.scroll&&window.scrollTo(0,0)}(e,t)}exports.Fragment=({children:e})=>e,exports.Link=function({href:e,children:t,replace:n=!1,className:r,style:o,...s}){return{type:"a",props:{href:e,onClick:t=>{t.preventDefault(),j(e,{replace:n})},className:r,style:o,...s,children:t}}},exports.batchUpdates=n,exports.createContext=function(e){return{Provider:({value:e,children:t})=>t,Consumer:({children:t})=>t(e),_id:Symbol(),useSelector:t=>t(e)}},exports.createElement=g,exports.hydrate=async function(e,t){b=!0;try{await v(e,t)}finally{b=!1}},exports.jsx=m,exports.jsxs=m,exports.render=v,exports.renderToString=async function(e,t={}){try{return function(e,t){const{title:n,description:r="",scripts:o=[],styles:s=[],initialState:i={},meta:a={},bodyAttrs:c={},htmlAttrs:l={lang:"en"}}=t,p=Object.entries(l).map((([e,t])=>`${e}="${t}"`)).join(" "),u=Object.entries(c).map((([e,t])=>`${e}="${t}"`)).join(" ");return`<!DOCTYPE html>\n<html ${p}>\n <head>\n <meta charset="UTF-8">\n <meta name="viewport" content="width=device-width, initial-scale=1.0">\n ${r?`<meta name="description" content="${r}">\n`:""}${Object.entries(a).map((([e,t])=>` <meta name="${e}" content="${t}">`)).join("\n")}\n <title>${n}</title>\n${s.map((e=>` <link rel="stylesheet" href="${e}">`)).join("\n")}\n <script>\n window.__INITIAL_STATE__ = ${JSON.stringify(i)};\n <\/script>\n </head>\n <body ${u}>\n <div id="root">${e}</div>\n${o.map((e=>` <script src="${e}" defer><\/script>`)).join("\n")}\n </body>\n</html>`}(await x(e),{title:"Frontend Hamroun App",...t})}catch(n){return console.error("Error during server rendering:",n),""}},exports.useContext=function(e){return e},exports.useEffect=w,exports.useErrorBoundary=function(){const[e,t]=h(null);return[e,()=>t(null)]},exports.useMemo=function(e,t){if(!r)throw new Error("useMemo must be called within a render");const n=s.get(r);a.has(r)||a.set(r,[]);const o=a.get(r),i=o[n];if(!i||t&&t.some(((e,t)=>!Object.is(e,i.deps[t])))){const i=e();return o[n]={value:i,deps:t},s.set(r,n+1),i}return s.set(r,n+1),i.value},exports.useRef=function(e){if(!r)throw new Error("useRef must be called within a render");const t=s.get(r);c.has(r)||c.set(r,[]);const n=c.get(r);if(t>=n.length){const o={current:e};return n.push(o),s.set(r,t+1),o}const o=n[t];return s.set(r,t+1),o},exports.useRouter=function(){const[e,t]=h(S);return w((()=>{const e=e=>{t(e)},n=()=>{S={pathname:window.location.pathname,search:window.location.search,hash:window.location.hash,params:{}},t(S)};return E.add(e),window.addEventListener("popstate",n),()=>{E.delete(e),window.removeEventListener("popstate",n)}}),[]),{...e,push:(e,t)=>j(e,t),replace:(e,t)=>j(e,{...t,replace:!0}),back:()=>window.history.back(),forward:()=>window.history.forward()}},exports.useState=h;
|
2
2
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../src/batch.ts","../src/hooks.ts","../src/jsx-runtime.ts","../src/renderer.ts","../src/server-renderer.ts","../src/router.ts","../src/link.tsx","../src/context.ts","../src/templates/default.ts"],"sourcesContent":["export let isBatching = false;\r\nconst queue: Function[] = [];\r\n\r\nexport function batchUpdates(fn: Function) {\r\n if (isBatching) {\r\n queue.push(fn);\r\n return;\r\n }\r\n\r\n isBatching = true;\r\n try {\r\n fn();\r\n while (queue.length > 0) {\r\n const nextFn = queue.shift();\r\n nextFn?.();\r\n }\r\n } finally {\r\n isBatching = false;\r\n }\r\n}\r\n\r\nexport function getIsBatching() {\r\n return isBatching;\r\n}\r\n","import { createElement } from './jsx-runtime';\r\nimport { batchUpdates, isBatching } from './batch';\r\nimport { diff } from './vdom';\r\n\r\nlet currentRender: number = 0;\r\nconst states = new Map<number, any[]>();\r\nconst stateIndices = new Map<number, number>();\r\nconst effects = new Map<number, Effect[]>();\r\nconst memos = new Map<number, { value: any; deps: any[] }[]>();\r\nconst refs = new Map<number, any[]>();\r\n\r\ninterface Effect {\r\n cleanup?: () => void;\r\n deps?: any[];\r\n}\r\n\r\n// Add at the top with other declarations\r\nlet globalRenderCallback: ((element: any, container: HTMLElement) => void) | null = null;\r\nlet globalContainer: HTMLElement | null = null;\r\nlet currentElement: any = null;\r\n\r\nconst isServer = typeof window === 'undefined';\r\nconst serverStates = new Map<number, any>();\r\n\r\nexport function setRenderCallback(\r\n callback: (element: any, container: HTMLElement) => void,\r\n element: any,\r\n container: HTMLElement\r\n) {\r\n globalRenderCallback = callback;\r\n globalContainer = container;\r\n currentElement = element;\r\n}\r\n\r\nexport function prepareRender() {\r\n currentRender++;\r\n stateIndices.set(currentRender, 0);\r\n return currentRender;\r\n}\r\n\r\nexport function finishRender() {\r\n if (isServer) {\r\n serverStates.delete(currentRender);\r\n }\r\n currentRender = 0;\r\n}\r\n\r\nexport function useState<T>(initial: T): [T, (value: T | ((prev: T) => T)) => void] {\r\n if (!currentRender) {\r\n throw new Error('useState must be called within a render');\r\n }\r\n\r\n if (isServer) {\r\n // Server-side state handling\r\n if (!serverStates.has(currentRender)) {\r\n serverStates.set(currentRender, new Map());\r\n }\r\n const componentState = serverStates.get(currentRender)!;\r\n const index = stateIndices.get(currentRender) || 0;\r\n \r\n if (!componentState.has(index)) {\r\n componentState.set(index, initial);\r\n }\r\n\r\n const state = componentState.get(index);\r\n const setState = (newValue: T | ((prev: T) => T)) => {\r\n // No-op for server-side\r\n };\r\n\r\n stateIndices.set(currentRender, index + 1);\r\n return [state, setState];\r\n }\r\n\r\n if (!states.has(currentRender)) {\r\n states.set(currentRender, []);\r\n }\r\n\r\n const componentStates = states.get(currentRender)!;\r\n const index = stateIndices.get(currentRender)!;\r\n \r\n if (index >= componentStates.length) {\r\n componentStates.push(initial);\r\n }\r\n\r\n const state = componentStates[index];\r\n const setState = (newValue: T | ((prev: T) => T)) => {\r\n const nextValue = typeof newValue === 'function' \r\n ? (newValue as Function)(componentStates[index])\r\n : newValue;\r\n\r\n if (componentStates[index] === nextValue) return; // Skip if value hasn't changed\r\n \r\n componentStates[index] = nextValue;\r\n \r\n if (isBatching) {\r\n batchUpdates(() => rerender(currentRender));\r\n } else {\r\n rerender(currentRender);\r\n }\r\n };\r\n\r\n stateIndices.set(currentRender, index + 1);\r\n return [state, setState];\r\n}\r\n\r\nexport function useEffect(callback: () => (() => void) | void, deps?: any[]) {\r\n if (!currentRender) throw new Error('useEffect must be called within a render');\r\n \r\n const effectIndex = stateIndices.get(currentRender)!;\r\n \r\n if (!effects.has(currentRender)) {\r\n effects.set(currentRender, []);\r\n }\r\n\r\n const componentEffects = effects.get(currentRender)!;\r\n const prevEffect = componentEffects[effectIndex];\r\n \r\n // Run effect if deps changed\r\n if (!prevEffect || !deps || !prevEffect.deps || \r\n deps.some((dep, i) => dep !== prevEffect.deps![i])) {\r\n \r\n // Cleanup previous effect\r\n if (prevEffect?.cleanup) {\r\n prevEffect.cleanup();\r\n }\r\n\r\n // Schedule new effect\r\n queueMicrotask(() => {\r\n const cleanup = callback() || undefined;\r\n componentEffects[effectIndex] = { cleanup: cleanup, deps };\r\n });\r\n }\r\n \r\n stateIndices.set(currentRender, effectIndex + 1);\r\n}\r\n\r\nexport function useMemo<T>(factory: () => T, deps: any[]): T {\r\n if (!currentRender) throw new Error('useMemo must be called within a render');\r\n \r\n const memoIndex = stateIndices.get(currentRender)!;\r\n \r\n if (!memos.has(currentRender)) {\r\n memos.set(currentRender, []);\r\n }\r\n\r\n const componentMemos = memos.get(currentRender)!;\r\n const prevMemo = componentMemos[memoIndex];\r\n \r\n if (!prevMemo || (deps && deps.some((dep, i) => !Object.is(dep, prevMemo.deps[i])))) {\r\n const value = factory();\r\n componentMemos[memoIndex] = { value, deps };\r\n stateIndices.set(currentRender, memoIndex + 1);\r\n return value;\r\n }\r\n\r\n stateIndices.set(currentRender, memoIndex + 1);\r\n return prevMemo.value;\r\n}\r\n\r\nexport function useRef<T>(initial: T) {\r\n if (!currentRender) throw new Error('useRef must be called within a render');\r\n \r\n const refIndex = stateIndices.get(currentRender)!;\r\n \r\n if (!refs.has(currentRender)) {\r\n refs.set(currentRender, []);\r\n }\r\n\r\n const componentRefs = refs.get(currentRender)!;\r\n if (refIndex >= componentRefs.length) {\r\n // Initialize with an object that has a current property\r\n const ref = { current: initial };\r\n componentRefs.push(ref);\r\n stateIndices.set(currentRender, refIndex + 1);\r\n return ref;\r\n }\r\n\r\n const ref = componentRefs[refIndex];\r\n stateIndices.set(currentRender, refIndex + 1);\r\n return ref;\r\n}\r\n\r\n// Add a map to track component DOM nodes\r\nconst componentNodes = new Map<Function, Node>();\r\n\r\nasync function rerender(rendererId: number) {\r\n try {\r\n // Clean up effects\r\n const componentEffects = effects.get(rendererId);\r\n if (componentEffects) {\r\n componentEffects.forEach(effect => {\r\n if (effect.cleanup) effect.cleanup();\r\n });\r\n effects.set(rendererId, []);\r\n }\r\n\r\n if (globalRenderCallback && globalContainer && currentElement) {\r\n await globalRenderCallback(currentElement, globalContainer);\r\n }\r\n } catch (error) {\r\n console.error('Error during rerender:', error);\r\n }\r\n}\r\n\r\n// Add new hook for error boundaries\r\nexport function useErrorBoundary(): [Error | null, () => void] {\r\n const [error, setError] = useState<Error | null>(null);\r\n return [error, () => setError(null)];\r\n}\r\n\r\n// Remove withHooks export\r\n","import type { Component } from './component';\r\n\r\ninterface VNode {\r\n type: string | Function;\r\n props: Record<string, any>;\r\n}\r\n\r\nfunction jsx(type: string | Function, props: any): VNode {\r\n console.log('JSX Transform:', { type, props });\r\n const processedProps = { ...props };\r\n \r\n // Handle children properly\r\n if (arguments.length > 2) {\r\n processedProps.children = Array.prototype.slice.call(arguments, 2);\r\n }\r\n \r\n return { type, props: processedProps };\r\n}\r\n\r\nconst Fragment = ({ children }: { children: any }) => children;\r\n\r\nasync function createElement(vnode: VNode | any): Promise<Node> {\r\n console.log('Creating element from:', vnode);\r\n\r\n // Handle primitives and null\r\n if (vnode == null) {\r\n return document.createTextNode('');\r\n }\r\n \r\n if (typeof vnode === 'boolean') {\r\n return document.createTextNode('');\r\n }\r\n\r\n if (typeof vnode === 'number' || typeof vnode === 'string') {\r\n return document.createTextNode(String(vnode));\r\n }\r\n\r\n // Handle arrays\r\n if (Array.isArray(vnode)) {\r\n const fragment = document.createDocumentFragment();\r\n for (const child of vnode) {\r\n const node = await createElement(child);\r\n fragment.appendChild(node);\r\n }\r\n return fragment;\r\n }\r\n\r\n // Handle VNode\r\n if ('type' in vnode && vnode.props !== undefined) {\r\n const { type, props } = vnode;\r\n \r\n // Handle function components\r\n if (typeof type === 'function') {\r\n try {\r\n const result = await type(props || {});\r\n const node = await createElement(result);\r\n if (node instanceof Element) {\r\n node.setAttribute('data-component-id', type.name || type.toString());\r\n }\r\n return node;\r\n } catch (error) {\r\n console.error('Error rendering component:', error);\r\n return document.createTextNode('');\r\n }\r\n }\r\n\r\n // Create DOM element\r\n const element = document.createElement(type as string);\r\n \r\n // Handle props\r\n for (const [key, value] of Object.entries(props || {})) {\r\n if (key === 'children') continue;\r\n if (key.startsWith('on') && typeof value === 'function') {\r\n const eventName = key.toLowerCase().slice(2);\r\n // Remove existing event listener if any\r\n const existingHandler = (element as any).__events?.[eventName];\r\n if (existingHandler) {\r\n element.removeEventListener(eventName, existingHandler);\r\n }\r\n \r\n // Add new event listener\r\n element.addEventListener(eventName, value as EventListener);\r\n if (!(element as any).__events) {\r\n (element as any).__events = {};\r\n }\r\n (element as any).__events[eventName] = value;\r\n } else if (key === 'style' && typeof value === 'object') {\r\n Object.assign(element.style, value);\r\n } else if (key === 'className') {\r\n element.setAttribute('class', String(value));\r\n } else if (key !== 'key' && key !== 'ref') {\r\n element.setAttribute(key, String(value));\r\n }\r\n }\r\n\r\n // Handle children\r\n const children = props?.children;\r\n if (children != null) {\r\n const childArray = Array.isArray(children) ? children.flat() : [children];\r\n for (const child of childArray) {\r\n const childNode = await createElement(child);\r\n element.appendChild(childNode);\r\n }\r\n }\r\n\r\n return element;\r\n }\r\n\r\n // Handle other objects by converting to string\r\n return document.createTextNode(String(vnode));\r\n}\r\n\r\n// Export named functions and aliases without duplicates\r\nexport {\r\n jsx,\r\n jsx as jsxs,\r\n jsx as jsxDEV,\r\n Fragment,\r\n createElement\r\n};\r\n\r\n// Named exports object\r\nconst jsxRuntime = {\r\n jsx,\r\n jsxs: jsx,\r\n jsxDEV: jsx,\r\n Fragment,\r\n createElement\r\n};\r\n\r\nexport default jsxRuntime;\r\n","import { createElement } from './jsx-runtime';\r\nimport { prepareRender, finishRender, setRenderCallback } from './hooks';\r\nimport { batchUpdates } from './batch';\r\n\r\nlet isHydrating = false;\r\n\r\nexport async function hydrate(element: any, container: HTMLElement) {\r\n isHydrating = true;\r\n try {\r\n await render(element, container);\r\n } finally {\r\n isHydrating = false;\r\n }\r\n}\r\n\r\nexport async function render(element: any, container: HTMLElement) {\r\n console.log('Rendering to:', container.id);\r\n \r\n batchUpdates(async () => {\r\n const rendererId = prepareRender();\r\n try {\r\n setRenderCallback(render, element, container);\r\n const domNode = await createElement(element);\r\n \r\n if (!isHydrating) {\r\n container.innerHTML = '';\r\n }\r\n container.appendChild(domNode);\r\n \r\n } finally {\r\n finishRender();\r\n }\r\n });\r\n}\r\n","import { VNode } from './types';\r\nimport { defaultTemplate, TemplateOptions } from './templates/default';\r\n\r\nexport async function renderToString(\r\n element: JSX.Element, \r\n options: Partial<TemplateOptions> = {}\r\n): Promise<string> {\r\n try {\r\n const content = await renderNodeToString(element);\r\n return defaultTemplate(content, {\r\n title: 'Frontend Hamroun App',\r\n ...options\r\n });\r\n } catch (error) {\r\n console.error('Error during server rendering:', error);\r\n return '';\r\n }\r\n}\r\n\r\nasync function renderNodeToString(node: VNode | any): Promise<string> {\r\n if (node == null || typeof node === 'boolean') {\r\n return '';\r\n }\r\n\r\n if (typeof node === 'number' || typeof node === 'string') {\r\n return escapeHtml(String(node));\r\n }\r\n\r\n if (typeof node === 'function') {\r\n const result = await node({ });\r\n return renderNodeToString(result);\r\n }\r\n\r\n if (node.type) {\r\n if (typeof node.type === 'function') {\r\n const result = await node.type(node.props || {});\r\n return renderNodeToString(result);\r\n }\r\n\r\n let html = `<${node.type}`;\r\n \r\n // Handle props\r\n for (const [key, value] of Object.entries(node.props || {})) {\r\n if (key === 'children' || key === 'key' || key === 'ref') continue;\r\n if (key === 'className') {\r\n html += ` class=\"${escapeHtml(String(value))}\"`;\r\n } else if (key === 'style' && typeof value === 'object' && value !== null) {\r\n html += ` style=\"${styleToString(value)}\"`;\r\n } else if (!key.startsWith('on')) {\r\n html += ` ${key}=\"${escapeHtml(String(value))}\"`;\r\n }\r\n }\r\n\r\n html += '>';\r\n\r\n // Handle children\r\n if (node.props?.children) {\r\n const children = Array.isArray(node.props.children) \r\n ? node.props.children \r\n : [node.props.children];\r\n \r\n for (const child of children) {\r\n html += await renderNodeToString(child);\r\n }\r\n }\r\n\r\n html += `</${node.type}>`;\r\n return html;\r\n }\r\n\r\n return '';\r\n}\r\n\r\nfunction escapeHtml(str: string): string {\r\n return str\r\n .replace(/&/g, '&')\r\n .replace(/</g, '<')\r\n .replace(/>/g, '>')\r\n .replace(/\"/g, '"')\r\n .replace(/'/g, ''');\r\n}\r\n\r\nfunction styleToString(style: Record<string, any>): string {\r\n return Object.entries(style)\r\n .map(([key, value]) => `${key}: ${value}`)\r\n .join('; ');\r\n}\r\n","import { useState, useEffect } from './hooks';\r\n\r\ninterface RouterState {\r\n pathname: string;\r\n search: string;\r\n hash: string;\r\n params: Record<string, string>;\r\n}\r\n\r\ninterface RouterOptions {\r\n replace?: boolean;\r\n scroll?: boolean;\r\n}\r\n\r\nlet currentState: RouterState = {\r\n pathname: typeof window !== 'undefined' ? window.location.pathname : '/',\r\n search: typeof window !== 'undefined' ? window.location.search : '',\r\n hash: typeof window !== 'undefined' ? window.location.hash : '',\r\n params: {}\r\n};\r\n\r\nconst listeners = new Set<(state: RouterState) => void>();\r\n\r\n// Parse route pattern and extract params\r\nfunction matchRoute(pattern: string, pathname: string): Record<string, string> | null {\r\n const paramNames: string[] = [];\r\n const regexPattern = pattern.replace(/:([^/]+)/g, (_, name) => {\r\n paramNames.push(name);\r\n return '([^/]+)';\r\n });\r\n\r\n const match = pathname.match(new RegExp(`^${regexPattern}$`));\r\n if (!match) return null;\r\n\r\n const params: Record<string, string> = {};\r\n paramNames.forEach((name, i) => {\r\n params[name] = match[i + 1];\r\n });\r\n\r\n return params;\r\n}\r\n\r\nfunction updateState(newPath: string, options: RouterOptions = {}) {\r\n const url = new URL(newPath, window.location.origin);\r\n const newState: RouterState = {\r\n pathname: url.pathname,\r\n search: url.search,\r\n hash: url.hash,\r\n params: {}\r\n };\r\n\r\n if (options.replace) {\r\n window.history.replaceState(newState, '', url.toString());\r\n } else {\r\n window.history.pushState(newState, '', url.toString());\r\n }\r\n\r\n currentState = newState;\r\n listeners.forEach(listener => listener(newState));\r\n\r\n if (options.scroll) {\r\n window.scrollTo(0, 0);\r\n }\r\n}\r\n\r\nexport function navigate(to: string, options: RouterOptions = {}) {\r\n if (typeof window === 'undefined') return;\r\n updateState(to, options);\r\n}\r\n\r\nexport function useRouter() {\r\n const [state, setState] = useState<RouterState>(currentState);\r\n\r\n useEffect(() => {\r\n const handleRouteChange = (newState: RouterState) => {\r\n setState(newState);\r\n };\r\n\r\n const handlePopState = () => {\r\n currentState = {\r\n pathname: window.location.pathname,\r\n search: window.location.search,\r\n hash: window.location.hash,\r\n params: {}\r\n };\r\n setState(currentState);\r\n };\r\n\r\n listeners.add(handleRouteChange);\r\n window.addEventListener('popstate', handlePopState);\r\n\r\n return () => {\r\n listeners.delete(handleRouteChange);\r\n window.removeEventListener('popstate', handlePopState);\r\n };\r\n }, []);\r\n\r\n return {\r\n ...state,\r\n push: (to: string, options?: RouterOptions) => navigate(to, options),\r\n replace: (to: string, options?: RouterOptions) => navigate(to, { ...options, replace: true }),\r\n back: () => window.history.back(),\r\n forward: () => window.history.forward()\r\n };\r\n}\r\n\r\nexport function useRoute(pattern: string) {\r\n const { pathname } = useRouter();\r\n const [params, setParams] = useState<Record<string, string>>({});\r\n const [isMatch, setIsMatch] = useState(false);\r\n\r\n useEffect(() => {\r\n const matchedParams = matchRoute(pattern, pathname);\r\n setIsMatch(!!matchedParams);\r\n setParams(matchedParams || {});\r\n }, [pattern, pathname]);\r\n\r\n return { isMatch, params };\r\n}\r\n\r\nexport function useParams<T extends Record<string, string>>() {\r\n const router = useRouter();\r\n return router.params as T;\r\n}\r\n\r\nexport function useSearchParams() {\r\n const { search } = useRouter();\r\n return new URLSearchParams(search);\r\n}\r\n","import { navigate } from './router';\r\n\r\ninterface LinkProps {\r\n href: string;\r\n children?: any;\r\n replace?: boolean;\r\n className?: string;\r\n style?: Record<string, string>;\r\n [key: string]: any;\r\n}\r\n\r\nexport function Link({ \r\n href, \r\n children, \r\n replace = false, \r\n className,\r\n style,\r\n ...rest \r\n}: LinkProps) {\r\n const handleClick = (e: MouseEvent) => {\r\n e.preventDefault();\r\n navigate(href, { replace });\r\n };\r\n\r\n return {\r\n type: 'a',\r\n props: {\r\n href,\r\n onClick: handleClick,\r\n className,\r\n style,\r\n ...rest,\r\n children\r\n }\r\n };\r\n}\r\n","\r\n\r\nconst contexts = new Map<symbol, any>();\r\nlet currentRender: Function | null = null;\r\n\r\nexport interface Context<T> {\r\n Provider: (props: { value: T; children?: any }) => any;\r\n Consumer: (props: { children: (value: T) => any }) => any;\r\n _id: symbol;\r\n useSelector: <S>(selector: (state: T) => S) => S;\r\n}\r\n\r\nexport function createContext<T>(defaultValue: T): Context<T> {\r\n const context = {\r\n Provider: ({ value, children }: { value: T, children?: any }) => {\r\n return children;\r\n },\r\n Consumer: ({ children }: { children: (value: T) => any }) => {\r\n return children(defaultValue);\r\n },\r\n _id: Symbol(),\r\n useSelector: <S>(selector: (state: T) => S) => {\r\n return selector(defaultValue);\r\n }\r\n };\r\n\r\n return context;\r\n}\r\n\r\nexport function useContext<T>(context: any): T {\r\n return context;\r\n}\r\n","export interface TemplateOptions {\r\n title: string;\r\n description?: string;\r\n scripts?: string[];\r\n styles?: string[];\r\n initialState?: any;\r\n meta?: Record<string, string>;\r\n bodyAttrs?: Record<string, string>;\r\n htmlAttrs?: Record<string, string>;\r\n}\r\n\r\nexport function defaultTemplate(content: string, options: TemplateOptions): string {\r\n const {\r\n title,\r\n description = '',\r\n scripts = [],\r\n styles = [],\r\n initialState = {},\r\n meta = {},\r\n bodyAttrs = {},\r\n htmlAttrs = { lang: 'en' }\r\n } = options;\r\n\r\n const htmlAttributes = Object.entries(htmlAttrs)\r\n .map(([key, value]) => `${key}=\"${value}\"`)\r\n .join(' ');\r\n\r\n const bodyAttributes = Object.entries(bodyAttrs)\r\n .map(([key, value]) => `${key}=\"${value}\"`)\r\n .join(' ');\r\n\r\n const metaTags = Object.entries(meta)\r\n .map(([name, content]) => ` <meta name=\"${name}\" content=\"${content}\">`)\r\n .join('\\n');\r\n\r\n return `<!DOCTYPE html>\r\n<html ${htmlAttributes}>\r\n <head>\r\n <meta charset=\"UTF-8\">\r\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\r\n ${description ? `<meta name=\"description\" content=\"${description}\">\\n` : ''}${metaTags}\r\n <title>${title}</title>\r\n${styles.map(href => ` <link rel=\"stylesheet\" href=\"${href}\">`).join('\\n')}\r\n <script>\r\n window.__INITIAL_STATE__ = ${JSON.stringify(initialState)};\r\n </script>\r\n </head>\r\n <body ${bodyAttributes}>\r\n <div id=\"root\">${content}</div>\r\n${scripts.map(src => ` <script src=\"${src}\" defer></script>`).join('\\n')}\r\n </body>\r\n</html>`;\r\n}\r\n"],"names":["isBatching","queue","batchUpdates","fn","push","length","nextFn","shift","currentRender","states","Map","stateIndices","effects","memos","refs","globalRenderCallback","globalContainer","currentElement","isServer","window","serverStates","useState","initial","Error","has","set","componentState","get","index","state","setState","newValue","componentStates","nextValue","rerender","useEffect","callback","deps","effectIndex","componentEffects","prevEffect","some","dep","i","cleanup","queueMicrotask","async","rendererId","forEach","effect","error","console","jsx","type","props","log","processedProps","arguments","children","Array","prototype","slice","call","createElement","vnode","document","createTextNode","String","isArray","fragment","createDocumentFragment","child","node","appendChild","result","Element","setAttribute","name","toString","element","key","value","Object","entries","startsWith","eventName","toLowerCase","existingHandler","_a","__events","removeEventListener","addEventListener","assign","style","childArray","flat","childNode","isHydrating","render","container","id","setRenderCallback","domNode","innerHTML","delete","renderNodeToString","escapeHtml","html","map","join","str","replace","currentState","pathname","location","search","hash","params","listeners","Set","navigate","to","options","newPath","url","URL","origin","newState","history","replaceState","pushState","listener","scroll","scrollTo","updateState","href","className","rest","onClick","e","preventDefault","defaultValue","Provider","Consumer","_id","Symbol","useSelector","selector","content","title","description","scripts","styles","initialState","meta","bodyAttrs","htmlAttrs","lang","htmlAttributes","bodyAttributes","JSON","stringify","src","defaultTemplate","context","setError","factory","memoIndex","componentMemos","prevMemo","is","refIndex","componentRefs","ref","current","handleRouteChange","handlePopState","add","back","forward"],"mappings":"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"}
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/batch.ts","../src/hooks.ts","../src/jsx-runtime.ts","../src/renderer.ts","../src/server-renderer.ts","../src/router.ts","../src/link.tsx","../src/context.ts","../src/templates/default.ts"],"sourcesContent":["export let isBatching = false;\r\nconst queue: Function[] = [];\r\n\r\nexport function batchUpdates(fn: Function) {\r\n if (isBatching) {\r\n queue.push(fn);\r\n return;\r\n }\r\n\r\n isBatching = true;\r\n try {\r\n fn();\r\n while (queue.length > 0) {\r\n const nextFn = queue.shift();\r\n nextFn?.();\r\n }\r\n } finally {\r\n isBatching = false;\r\n }\r\n}\r\n\r\nexport function getIsBatching() {\r\n return isBatching;\r\n}\r\n","import { createElement } from './jsx-runtime';\r\nimport { batchUpdates, isBatching } from './batch';\r\nimport { diff } from './vdom';\r\n\r\nlet currentRender: number = 0;\r\nconst states = new Map<number, any[]>();\r\nconst stateIndices = new Map<number, number>();\r\nconst effects = new Map<number, Effect[]>();\r\nconst memos = new Map<number, { value: any; deps: any[] }[]>();\r\nconst refs = new Map<number, any[]>();\r\n\r\ninterface Effect {\r\n cleanup?: () => void;\r\n deps?: any[];\r\n}\r\n\r\n// Add at the top with other declarations\r\nlet globalRenderCallback: ((element: any, container: HTMLElement) => void) | null = null;\r\nlet globalContainer: HTMLElement | null = null;\r\nlet currentElement: any = null;\r\n\r\nconst isServer = typeof window === 'undefined';\r\nconst serverStates = new Map<number, any>();\r\n\r\nexport function setRenderCallback(\r\n callback: (element: any, container: HTMLElement) => void,\r\n element: any,\r\n container: HTMLElement\r\n) {\r\n globalRenderCallback = callback;\r\n globalContainer = container;\r\n currentElement = element;\r\n}\r\n\r\nexport function prepareRender() {\r\n currentRender++;\r\n stateIndices.set(currentRender, 0);\r\n return currentRender;\r\n}\r\n\r\nexport function finishRender() {\r\n if (isServer) {\r\n serverStates.delete(currentRender);\r\n }\r\n currentRender = 0;\r\n}\r\n\r\nexport function useState<T>(initial: T): [T, (value: T | ((prev: T) => T)) => void] {\r\n if (!currentRender) {\r\n throw new Error('useState must be called within a render');\r\n }\r\n\r\n if (isServer) {\r\n // Server-side state handling\r\n if (!serverStates.has(currentRender)) {\r\n serverStates.set(currentRender, new Map());\r\n }\r\n const componentState = serverStates.get(currentRender)!;\r\n const index = stateIndices.get(currentRender) || 0;\r\n \r\n if (!componentState.has(index)) {\r\n componentState.set(index, initial);\r\n }\r\n\r\n const state = componentState.get(index);\r\n const setState = (newValue: T | ((prev: T) => T)) => {\r\n // No-op for server-side\r\n };\r\n\r\n stateIndices.set(currentRender, index + 1);\r\n return [state, setState];\r\n }\r\n\r\n if (!states.has(currentRender)) {\r\n states.set(currentRender, []);\r\n }\r\n\r\n const componentStates = states.get(currentRender)!;\r\n const index = stateIndices.get(currentRender)!;\r\n \r\n if (index >= componentStates.length) {\r\n componentStates.push(initial);\r\n }\r\n\r\n const state = componentStates[index];\r\n const setState = (newValue: T | ((prev: T) => T)) => {\r\n const nextValue = typeof newValue === 'function' \r\n ? (newValue as Function)(componentStates[index])\r\n : newValue;\r\n\r\n if (componentStates[index] === nextValue) return; // Skip if value hasn't changed\r\n \r\n componentStates[index] = nextValue;\r\n \r\n if (isBatching) {\r\n batchUpdates(() => rerender(currentRender));\r\n } else {\r\n rerender(currentRender);\r\n }\r\n };\r\n\r\n stateIndices.set(currentRender, index + 1);\r\n return [state, setState];\r\n}\r\n\r\nexport function useEffect(callback: () => (() => void) | void, deps?: any[]) {\r\n if (!currentRender) throw new Error('useEffect must be called within a render');\r\n \r\n const effectIndex = stateIndices.get(currentRender)!;\r\n \r\n if (!effects.has(currentRender)) {\r\n effects.set(currentRender, []);\r\n }\r\n\r\n const componentEffects = effects.get(currentRender)!;\r\n const prevEffect = componentEffects[effectIndex];\r\n \r\n // Run effect if deps changed\r\n if (!prevEffect || !deps || !prevEffect.deps || \r\n deps.some((dep, i) => dep !== prevEffect.deps![i])) {\r\n \r\n // Cleanup previous effect\r\n if (prevEffect?.cleanup) {\r\n prevEffect.cleanup();\r\n }\r\n\r\n // Schedule new effect\r\n queueMicrotask(() => {\r\n const cleanup = callback() || undefined;\r\n componentEffects[effectIndex] = { cleanup: cleanup, deps };\r\n });\r\n }\r\n \r\n stateIndices.set(currentRender, effectIndex + 1);\r\n}\r\n\r\nexport function useMemo<T>(factory: () => T, deps: any[]): T {\r\n if (!currentRender) throw new Error('useMemo must be called within a render');\r\n \r\n const memoIndex = stateIndices.get(currentRender)!;\r\n \r\n if (!memos.has(currentRender)) {\r\n memos.set(currentRender, []);\r\n }\r\n\r\n const componentMemos = memos.get(currentRender)!;\r\n const prevMemo = componentMemos[memoIndex];\r\n \r\n if (!prevMemo || (deps && deps.some((dep, i) => !Object.is(dep, prevMemo.deps[i])))) {\r\n const value = factory();\r\n componentMemos[memoIndex] = { value, deps };\r\n stateIndices.set(currentRender, memoIndex + 1);\r\n return value;\r\n }\r\n\r\n stateIndices.set(currentRender, memoIndex + 1);\r\n return prevMemo.value;\r\n}\r\n\r\nexport function useRef<T>(initial: T) {\r\n if (!currentRender) throw new Error('useRef must be called within a render');\r\n \r\n const refIndex = stateIndices.get(currentRender)!;\r\n \r\n if (!refs.has(currentRender)) {\r\n refs.set(currentRender, []);\r\n }\r\n\r\n const componentRefs = refs.get(currentRender)!;\r\n if (refIndex >= componentRefs.length) {\r\n // Initialize with an object that has a current property\r\n const ref = { current: initial };\r\n componentRefs.push(ref);\r\n stateIndices.set(currentRender, refIndex + 1);\r\n return ref;\r\n }\r\n\r\n const ref = componentRefs[refIndex];\r\n stateIndices.set(currentRender, refIndex + 1);\r\n return ref;\r\n}\r\n\r\n// Add a map to track component DOM nodes\r\nconst componentNodes = new Map<Function, Node>();\r\n\r\nasync function rerender(rendererId: number) {\r\n try {\r\n // Clean up effects\r\n const componentEffects = effects.get(rendererId);\r\n if (componentEffects) {\r\n componentEffects.forEach(effect => {\r\n if (effect.cleanup) effect.cleanup();\r\n });\r\n effects.set(rendererId, []);\r\n }\r\n\r\n if (globalRenderCallback && globalContainer && currentElement) {\r\n await globalRenderCallback(currentElement, globalContainer);\r\n }\r\n } catch (error) {\r\n console.error('Error during rerender:', error);\r\n }\r\n}\r\n\r\n// Add new hook for error boundaries\r\nexport function useErrorBoundary(): [Error | null, () => void] {\r\n const [error, setError] = useState<Error | null>(null);\r\n return [error, () => setError(null)];\r\n}\r\n\r\n// Remove withHooks export\r\n","import type { Component } from './component';\r\n\r\ninterface VNode {\r\n type: string | Function;\r\n props: Record<string, any>;\r\n}\r\n\r\nfunction jsx(type: string | Function, props: any): VNode {\r\n console.log('JSX Transform:', { type, props });\r\n const processedProps = { ...props };\r\n \r\n // Handle children properly\r\n if (arguments.length > 2) {\r\n processedProps.children = Array.prototype.slice.call(arguments, 2);\r\n }\r\n \r\n return { type, props: processedProps };\r\n}\r\n\r\nconst Fragment = ({ children }: { children: any }) => children;\r\n\r\nasync function createElement(vnode: VNode | any): Promise<Node> {\r\n console.log('Creating element from:', vnode);\r\n\r\n // Handle primitives and null\r\n if (vnode == null) {\r\n return document.createTextNode('');\r\n }\r\n \r\n if (typeof vnode === 'boolean') {\r\n return document.createTextNode('');\r\n }\r\n\r\n if (typeof vnode === 'number' || typeof vnode === 'string') {\r\n return document.createTextNode(String(vnode));\r\n }\r\n\r\n // Handle arrays\r\n if (Array.isArray(vnode)) {\r\n const fragment = document.createDocumentFragment();\r\n for (const child of vnode) {\r\n const node = await createElement(child);\r\n fragment.appendChild(node);\r\n }\r\n return fragment;\r\n }\r\n\r\n // Handle VNode\r\n if ('type' in vnode && vnode.props !== undefined) {\r\n const { type, props } = vnode;\r\n \r\n // Handle function components\r\n if (typeof type === 'function') {\r\n try {\r\n const result = await type(props || {});\r\n const node = await createElement(result);\r\n if (node instanceof Element) {\r\n node.setAttribute('data-component-id', type.name || type.toString());\r\n }\r\n return node;\r\n } catch (error) {\r\n console.error('Error rendering component:', error);\r\n return document.createTextNode('');\r\n }\r\n }\r\n\r\n // Create DOM element\r\n const element = document.createElement(type as string);\r\n \r\n // Handle props\r\n for (const [key, value] of Object.entries(props || {})) {\r\n if (key === 'children') continue;\r\n if (key.startsWith('on') && typeof value === 'function') {\r\n const eventName = key.toLowerCase().slice(2);\r\n // Remove existing event listener if any\r\n const existingHandler = (element as any).__events?.[eventName];\r\n if (existingHandler) {\r\n element.removeEventListener(eventName, existingHandler);\r\n }\r\n \r\n // Add new event listener\r\n element.addEventListener(eventName, value as EventListener);\r\n if (!(element as any).__events) {\r\n (element as any).__events = {};\r\n }\r\n (element as any).__events[eventName] = value;\r\n } else if (key === 'style' && typeof value === 'object') {\r\n Object.assign(element.style, value);\r\n } else if (key === 'className') {\r\n element.setAttribute('class', String(value));\r\n } else if (key !== 'key' && key !== 'ref') {\r\n element.setAttribute(key, String(value));\r\n }\r\n }\r\n\r\n // Handle children\r\n const children = props?.children;\r\n if (children != null) {\r\n const childArray = Array.isArray(children) ? children.flat() : [children];\r\n for (const child of childArray) {\r\n const childNode = await createElement(child);\r\n element.appendChild(childNode);\r\n }\r\n }\r\n\r\n return element;\r\n }\r\n\r\n // Handle other objects by converting to string\r\n return document.createTextNode(String(vnode));\r\n}\r\n\r\n// Export named functions and aliases without duplicates\r\nexport {\r\n jsx,\r\n jsx as jsxs,\r\n jsx as jsxDEV,\r\n Fragment,\r\n createElement\r\n};\r\n\r\n// Named exports object\r\nconst jsxRuntime = {\r\n jsx,\r\n jsxs: jsx,\r\n jsxDEV: jsx,\r\n Fragment,\r\n createElement\r\n};\r\n\r\nexport default jsxRuntime;\r\n","import { createElement } from './jsx-runtime';\r\nimport { prepareRender, finishRender, setRenderCallback } from './hooks';\r\nimport { batchUpdates } from './batch';\r\n\r\nlet isHydrating = false;\r\n\r\nexport async function hydrate(element: any, container: HTMLElement) {\r\n isHydrating = true;\r\n try {\r\n await render(element, container);\r\n } finally {\r\n isHydrating = false;\r\n }\r\n}\r\n\r\nexport async function render(element: any, container: HTMLElement) {\r\n console.log('Rendering to:', container.id);\r\n \r\n batchUpdates(async () => {\r\n const rendererId = prepareRender();\r\n try {\r\n setRenderCallback(render, element, container);\r\n const domNode = await createElement(element);\r\n \r\n if (!isHydrating) {\r\n container.innerHTML = '';\r\n }\r\n container.appendChild(domNode);\r\n \r\n } finally {\r\n finishRender();\r\n }\r\n });\r\n}\r\n","import { VNode } from './types';\r\nimport { defaultTemplate, TemplateOptions } from './templates/default';\r\n\r\nexport async function renderToString(\r\n element: JSX.Element, \r\n options: Partial<TemplateOptions> = {}\r\n): Promise<string> {\r\n try {\r\n const content = await renderNodeToString(element);\r\n return defaultTemplate(content, {\r\n title: 'Frontend Hamroun App',\r\n ...options\r\n });\r\n } catch (error) {\r\n console.error('Error during server rendering:', error);\r\n return '';\r\n }\r\n}\r\n\r\nasync function renderNodeToString(node: VNode | any): Promise<string> {\r\n if (node == null || typeof node === 'boolean') {\r\n return '';\r\n }\r\n\r\n if (typeof node === 'number' || typeof node === 'string') {\r\n return escapeHtml(String(node));\r\n }\r\n\r\n if (typeof node === 'function') {\r\n const result = await node({ });\r\n return renderNodeToString(result);\r\n }\r\n\r\n if (node.type) {\r\n if (typeof node.type === 'function') {\r\n const result = await node.type(node.props || {});\r\n return renderNodeToString(result);\r\n }\r\n\r\n let html = `<${node.type}`;\r\n \r\n // Handle props\r\n for (const [key, value] of Object.entries(node.props || {})) {\r\n if (key === 'children' || key === 'key' || key === 'ref') continue;\r\n if (key === 'className') {\r\n html += ` class=\"${escapeHtml(String(value))}\"`;\r\n } else if (key === 'style' && typeof value === 'object' && value !== null) {\r\n html += ` style=\"${styleToString(value)}\"`;\r\n } else if (!key.startsWith('on')) {\r\n html += ` ${key}=\"${escapeHtml(String(value))}\"`;\r\n }\r\n }\r\n\r\n html += '>';\r\n\r\n // Handle children\r\n if (node.props?.children) {\r\n const children = Array.isArray(node.props.children) \r\n ? node.props.children \r\n : [node.props.children];\r\n \r\n for (const child of children) {\r\n html += await renderNodeToString(child);\r\n }\r\n }\r\n\r\n html += `</${node.type}>`;\r\n return html;\r\n }\r\n\r\n return '';\r\n}\r\n\r\nfunction escapeHtml(str: string): string {\r\n return str\r\n .replace(/&/g, '&')\r\n .replace(/</g, '<')\r\n .replace(/>/g, '>')\r\n .replace(/\"/g, '"')\r\n .replace(/'/g, ''');\r\n}\r\n\r\nfunction styleToString(style: Record<string, any>): string {\r\n return Object.entries(style)\r\n .map(([key, value]) => `${key}: ${value}`)\r\n .join('; ');\r\n}\r\n","import { useState, useEffect } from './hooks';\r\n\r\ninterface RouterState {\r\n pathname: string;\r\n search: string;\r\n hash: string;\r\n params: Record<string, string>;\r\n}\r\n\r\ninterface RouterOptions {\r\n replace?: boolean;\r\n scroll?: boolean;\r\n}\r\n\r\nlet currentState: RouterState = {\r\n pathname: typeof window !== 'undefined' ? window.location.pathname : '/',\r\n search: typeof window !== 'undefined' ? window.location.search : '',\r\n hash: typeof window !== 'undefined' ? window.location.hash : '',\r\n params: {}\r\n};\r\n\r\nconst listeners = new Set<(state: RouterState) => void>();\r\n\r\n// Parse route pattern and extract params\r\nfunction matchRoute(pattern: string, pathname: string): Record<string, string> | null {\r\n const paramNames: string[] = [];\r\n const regexPattern = pattern.replace(/:([^/]+)/g, (_, name) => {\r\n paramNames.push(name);\r\n return '([^/]+)';\r\n });\r\n\r\n const match = pathname.match(new RegExp(`^${regexPattern}$`));\r\n if (!match) return null;\r\n\r\n const params: Record<string, string> = {};\r\n paramNames.forEach((name, i) => {\r\n params[name] = match[i + 1];\r\n });\r\n\r\n return params;\r\n}\r\n\r\nfunction updateState(newPath: string, options: RouterOptions = {}) {\r\n const url = new URL(newPath, window.location.origin);\r\n const newState: RouterState = {\r\n pathname: url.pathname,\r\n search: url.search,\r\n hash: url.hash,\r\n params: {}\r\n };\r\n\r\n if (options.replace) {\r\n window.history.replaceState(newState, '', url.toString());\r\n } else {\r\n window.history.pushState(newState, '', url.toString());\r\n }\r\n\r\n currentState = newState;\r\n listeners.forEach(listener => listener(newState));\r\n\r\n if (options.scroll) {\r\n window.scrollTo(0, 0);\r\n }\r\n}\r\n\r\nexport function navigate(to: string, options: RouterOptions = {}) {\r\n if (typeof window === 'undefined') return;\r\n updateState(to, options);\r\n}\r\n\r\nexport function useRouter() {\r\n const [state, setState] = useState<RouterState>(currentState);\r\n\r\n useEffect(() => {\r\n const handleRouteChange = (newState: RouterState) => {\r\n setState(newState);\r\n };\r\n\r\n const handlePopState = () => {\r\n currentState = {\r\n pathname: window.location.pathname,\r\n search: window.location.search,\r\n hash: window.location.hash,\r\n params: {}\r\n };\r\n setState(currentState);\r\n };\r\n\r\n listeners.add(handleRouteChange);\r\n window.addEventListener('popstate', handlePopState);\r\n\r\n return () => {\r\n listeners.delete(handleRouteChange);\r\n window.removeEventListener('popstate', handlePopState);\r\n };\r\n }, []);\r\n\r\n return {\r\n ...state,\r\n push: (to: string, options?: RouterOptions) => navigate(to, options),\r\n replace: (to: string, options?: RouterOptions) => navigate(to, { ...options, replace: true }),\r\n back: () => window.history.back(),\r\n forward: () => window.history.forward()\r\n };\r\n}\r\n\r\nexport function useRoute(pattern: string) {\r\n const { pathname } = useRouter();\r\n const [params, setParams] = useState<Record<string, string>>({});\r\n const [isMatch, setIsMatch] = useState(false);\r\n\r\n useEffect(() => {\r\n const matchedParams = matchRoute(pattern, pathname);\r\n setIsMatch(!!matchedParams);\r\n setParams(matchedParams || {});\r\n }, [pattern, pathname]);\r\n\r\n return { isMatch, params };\r\n}\r\n\r\nexport function useParams<T extends Record<string, string>>() {\r\n const router = useRouter();\r\n return router.params as T;\r\n}\r\n\r\nexport function useSearchParams() {\r\n const { search } = useRouter();\r\n return new URLSearchParams(search);\r\n}\r\n","import { navigate } from './router';\r\n\r\ninterface LinkProps {\r\n href: string;\r\n children?: any;\r\n replace?: boolean;\r\n className?: string;\r\n style?: Record<string, string>;\r\n [key: string]: any;\r\n}\r\n\r\nexport function Link({ \r\n href, \r\n children, \r\n replace = false, \r\n className,\r\n style,\r\n ...rest \r\n}: LinkProps) {\r\n const handleClick = (e: MouseEvent) => {\r\n e.preventDefault();\r\n navigate(href, { replace });\r\n };\r\n\r\n return {\r\n type: 'a',\r\n props: {\r\n href,\r\n onClick: handleClick,\r\n className,\r\n style,\r\n ...rest,\r\n children\r\n }\r\n };\r\n}\r\n","\r\n\r\nconst contexts = new Map<symbol, any>();\r\nlet currentRender: Function | null = null;\r\n\r\nexport interface Context<T> {\r\n Provider: (props: { value: T; children?: any }) => any;\r\n Consumer: (props: { children: (value: T) => any }) => any;\r\n _id: symbol;\r\n useSelector: <S>(selector: (state: T) => S) => S;\r\n}\r\n\r\nexport function createContext<T>(defaultValue: T): Context<T> {\r\n const context = {\r\n Provider: ({ value, children }: { value: T, children?: any }) => {\r\n return children;\r\n },\r\n Consumer: ({ children }: { children: (value: T) => any }) => {\r\n return children(defaultValue);\r\n },\r\n _id: Symbol(),\r\n useSelector: <S>(selector: (state: T) => S) => {\r\n return selector(defaultValue);\r\n }\r\n };\r\n\r\n return context;\r\n}\r\n\r\nexport function useContext<T>(context: any): T {\r\n return context;\r\n}\r\n","export interface TemplateOptions {\r\n title: string;\r\n description?: string;\r\n scripts?: string[];\r\n styles?: string[];\r\n initialState?: any;\r\n meta?: Record<string, string>;\r\n bodyAttrs?: Record<string, string>;\r\n htmlAttrs?: Record<string, string>;\r\n}\r\n\r\nexport function defaultTemplate(content: string, options: TemplateOptions): string {\r\n const {\r\n title,\r\n description = '',\r\n scripts = [],\r\n styles = [],\r\n initialState = {},\r\n meta = {},\r\n bodyAttrs = {},\r\n htmlAttrs = { lang: 'en' }\r\n } = options;\r\n\r\n const htmlAttributes = Object.entries(htmlAttrs)\r\n .map(([key, value]) => `${key}=\"${value}\"`)\r\n .join(' ');\r\n\r\n const bodyAttributes = Object.entries(bodyAttrs)\r\n .map(([key, value]) => `${key}=\"${value}\"`)\r\n .join(' ');\r\n\r\n const metaTags = Object.entries(meta)\r\n .map(([name, content]) => ` <meta name=\"${name}\" content=\"${content}\">`)\r\n .join('\\n');\r\n\r\n return `<!DOCTYPE html>\r\n<html ${htmlAttributes}>\r\n <head>\r\n <meta charset=\"UTF-8\">\r\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\r\n ${description ? `<meta name=\"description\" content=\"${description}\">\\n` : ''}${metaTags}\r\n <title>${title}</title>\r\n${styles.map(href => ` <link rel=\"stylesheet\" href=\"${href}\">`).join('\\n')}\r\n <script>\r\n window.__INITIAL_STATE__ = ${JSON.stringify(initialState)};\r\n </script>\r\n </head>\r\n <body ${bodyAttributes}>\r\n <div id=\"root\">${content}</div>\r\n${scripts.map(src => ` <script src=\"${src}\" defer></script>`).join('\\n')}\r\n </body>\r\n</html>`;\r\n}\r\n"],"names":["isBatching","queue","batchUpdates","fn","push","length","nextFn","shift","currentRender","states","Map","stateIndices","effects","memos","refs","globalRenderCallback","globalContainer","currentElement","isServer","window","serverStates","useState","initial","Error","has","set","componentState","get","index","state","setState","newValue","componentStates","nextValue","rerender","useEffect","callback","deps","effectIndex","componentEffects","prevEffect","some","dep","i","cleanup","queueMicrotask","async","rendererId","forEach","effect","error","console","jsx","type","props","log","processedProps","arguments","children","Array","prototype","slice","call","createElement","vnode","document","createTextNode","String","isArray","fragment","createDocumentFragment","child","node","appendChild","result","Element","setAttribute","name","toString","element","key","value","Object","entries","startsWith","eventName","toLowerCase","existingHandler","_a","__events","removeEventListener","addEventListener","assign","style","childArray","flat","childNode","isHydrating","render","container","id","setRenderCallback","domNode","innerHTML","delete","renderNodeToString","escapeHtml","html","map","join","str","replace","currentState","pathname","location","search","hash","params","listeners","Set","navigate","to","options","newPath","url","URL","origin","newState","history","replaceState","pushState","listener","scroll","scrollTo","updateState","href","className","rest","onClick","e","preventDefault","defaultValue","Provider","Consumer","_id","Symbol","useSelector","selector","content","title","description","scripts","styles","initialState","meta","bodyAttrs","htmlAttrs","lang","htmlAttributes","bodyAttributes","JSON","stringify","src","defaultTemplate","context","setError","factory","memoIndex","componentMemos","prevMemo","is","refIndex","componentRefs","ref","current","handleRouteChange","handlePopState","add","back","forward"],"mappings":"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"}
|
package/dist/index.mjs
CHANGED
@@ -162,24 +162,6 @@ function useErrorBoundary() {
|
|
162
162
|
const [error, setError] = useState(null);
|
163
163
|
return [error, () => setError(null)];
|
164
164
|
}
|
165
|
-
function createContext(defaultValue) {
|
166
|
-
const context = {
|
167
|
-
Provider: ({ value, children }) => {
|
168
|
-
return children;
|
169
|
-
},
|
170
|
-
Consumer: ({ children }) => {
|
171
|
-
return children(defaultValue);
|
172
|
-
},
|
173
|
-
_id: Symbol(),
|
174
|
-
useSelector: (selector) => {
|
175
|
-
return selector(defaultValue);
|
176
|
-
}
|
177
|
-
};
|
178
|
-
return context;
|
179
|
-
}
|
180
|
-
function useContext(context) {
|
181
|
-
return context;
|
182
|
-
}
|
183
165
|
function jsx(type, props) {
|
184
166
|
console.log("JSX Transform:", { type, props });
|
185
167
|
const processedProps = { ...props };
|
@@ -259,6 +241,24 @@ async function createElement(vnode) {
|
|
259
241
|
}
|
260
242
|
return document.createTextNode(String(vnode));
|
261
243
|
}
|
244
|
+
function createContext(defaultValue) {
|
245
|
+
const context = {
|
246
|
+
Provider: ({ value, children }) => {
|
247
|
+
return children;
|
248
|
+
},
|
249
|
+
Consumer: ({ children }) => {
|
250
|
+
return children(defaultValue);
|
251
|
+
},
|
252
|
+
_id: Symbol(),
|
253
|
+
useSelector: (selector) => {
|
254
|
+
return selector(defaultValue);
|
255
|
+
}
|
256
|
+
};
|
257
|
+
return context;
|
258
|
+
}
|
259
|
+
function useContext(context) {
|
260
|
+
return context;
|
261
|
+
}
|
262
262
|
let isHydrating = false;
|
263
263
|
async function hydrate(element, container) {
|
264
264
|
isHydrating = true;
|
@@ -466,6 +466,7 @@ export {
|
|
466
466
|
Link,
|
467
467
|
batchUpdates,
|
468
468
|
createContext,
|
469
|
+
createElement,
|
469
470
|
hydrate,
|
470
471
|
jsx,
|
471
472
|
jsx as jsxs,
|
package/dist/index.mjs.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"index.mjs","sources":["../src/batch.ts","../src/hooks.ts","../src/context.ts","../src/jsx-runtime.ts","../src/renderer.ts","../src/templates/default.ts","../src/server-renderer.ts","../src/router.ts","../src/link.tsx"],"sourcesContent":["export let isBatching = false;\r\nconst queue: Function[] = [];\r\n\r\nexport function batchUpdates(fn: Function) {\r\n if (isBatching) {\r\n queue.push(fn);\r\n return;\r\n }\r\n\r\n isBatching = true;\r\n try {\r\n fn();\r\n while (queue.length > 0) {\r\n const nextFn = queue.shift();\r\n nextFn?.();\r\n }\r\n } finally {\r\n isBatching = false;\r\n }\r\n}\r\n\r\nexport function getIsBatching() {\r\n return isBatching;\r\n}\r\n","import { createElement } from './jsx-runtime';\r\nimport { batchUpdates, isBatching } from './batch';\r\nimport { diff } from './vdom';\r\n\r\nlet currentRender: number = 0;\r\nconst states = new Map<number, any[]>();\r\nconst stateIndices = new Map<number, number>();\r\nconst effects = new Map<number, Effect[]>();\r\nconst memos = new Map<number, { value: any; deps: any[] }[]>();\r\nconst refs = new Map<number, any[]>();\r\n\r\ninterface Effect {\r\n cleanup?: () => void;\r\n deps?: any[];\r\n}\r\n\r\n// Add at the top with other declarations\r\nlet globalRenderCallback: ((element: any, container: HTMLElement) => void) | null = null;\r\nlet globalContainer: HTMLElement | null = null;\r\nlet currentElement: any = null;\r\n\r\nconst isServer = typeof window === 'undefined';\r\nconst serverStates = new Map<number, any>();\r\n\r\nexport function setRenderCallback(\r\n callback: (element: any, container: HTMLElement) => void,\r\n element: any,\r\n container: HTMLElement\r\n) {\r\n globalRenderCallback = callback;\r\n globalContainer = container;\r\n currentElement = element;\r\n}\r\n\r\nexport function prepareRender() {\r\n currentRender++;\r\n stateIndices.set(currentRender, 0);\r\n return currentRender;\r\n}\r\n\r\nexport function finishRender() {\r\n if (isServer) {\r\n serverStates.delete(currentRender);\r\n }\r\n currentRender = 0;\r\n}\r\n\r\nexport function useState<T>(initial: T): [T, (value: T | ((prev: T) => T)) => void] {\r\n if (!currentRender) {\r\n throw new Error('useState must be called within a render');\r\n }\r\n\r\n if (isServer) {\r\n // Server-side state handling\r\n if (!serverStates.has(currentRender)) {\r\n serverStates.set(currentRender, new Map());\r\n }\r\n const componentState = serverStates.get(currentRender)!;\r\n const index = stateIndices.get(currentRender) || 0;\r\n \r\n if (!componentState.has(index)) {\r\n componentState.set(index, initial);\r\n }\r\n\r\n const state = componentState.get(index);\r\n const setState = (newValue: T | ((prev: T) => T)) => {\r\n // No-op for server-side\r\n };\r\n\r\n stateIndices.set(currentRender, index + 1);\r\n return [state, setState];\r\n }\r\n\r\n if (!states.has(currentRender)) {\r\n states.set(currentRender, []);\r\n }\r\n\r\n const componentStates = states.get(currentRender)!;\r\n const index = stateIndices.get(currentRender)!;\r\n \r\n if (index >= componentStates.length) {\r\n componentStates.push(initial);\r\n }\r\n\r\n const state = componentStates[index];\r\n const setState = (newValue: T | ((prev: T) => T)) => {\r\n const nextValue = typeof newValue === 'function' \r\n ? (newValue as Function)(componentStates[index])\r\n : newValue;\r\n\r\n if (componentStates[index] === nextValue) return; // Skip if value hasn't changed\r\n \r\n componentStates[index] = nextValue;\r\n \r\n if (isBatching) {\r\n batchUpdates(() => rerender(currentRender));\r\n } else {\r\n rerender(currentRender);\r\n }\r\n };\r\n\r\n stateIndices.set(currentRender, index + 1);\r\n return [state, setState];\r\n}\r\n\r\nexport function useEffect(callback: () => (() => void) | void, deps?: any[]) {\r\n if (!currentRender) throw new Error('useEffect must be called within a render');\r\n \r\n const effectIndex = stateIndices.get(currentRender)!;\r\n \r\n if (!effects.has(currentRender)) {\r\n effects.set(currentRender, []);\r\n }\r\n\r\n const componentEffects = effects.get(currentRender)!;\r\n const prevEffect = componentEffects[effectIndex];\r\n \r\n // Run effect if deps changed\r\n if (!prevEffect || !deps || !prevEffect.deps || \r\n deps.some((dep, i) => dep !== prevEffect.deps![i])) {\r\n \r\n // Cleanup previous effect\r\n if (prevEffect?.cleanup) {\r\n prevEffect.cleanup();\r\n }\r\n\r\n // Schedule new effect\r\n queueMicrotask(() => {\r\n const cleanup = callback() || undefined;\r\n componentEffects[effectIndex] = { cleanup: cleanup, deps };\r\n });\r\n }\r\n \r\n stateIndices.set(currentRender, effectIndex + 1);\r\n}\r\n\r\nexport function useMemo<T>(factory: () => T, deps: any[]): T {\r\n if (!currentRender) throw new Error('useMemo must be called within a render');\r\n \r\n const memoIndex = stateIndices.get(currentRender)!;\r\n \r\n if (!memos.has(currentRender)) {\r\n memos.set(currentRender, []);\r\n }\r\n\r\n const componentMemos = memos.get(currentRender)!;\r\n const prevMemo = componentMemos[memoIndex];\r\n \r\n if (!prevMemo || (deps && deps.some((dep, i) => !Object.is(dep, prevMemo.deps[i])))) {\r\n const value = factory();\r\n componentMemos[memoIndex] = { value, deps };\r\n stateIndices.set(currentRender, memoIndex + 1);\r\n return value;\r\n }\r\n\r\n stateIndices.set(currentRender, memoIndex + 1);\r\n return prevMemo.value;\r\n}\r\n\r\nexport function useRef<T>(initial: T) {\r\n if (!currentRender) throw new Error('useRef must be called within a render');\r\n \r\n const refIndex = stateIndices.get(currentRender)!;\r\n \r\n if (!refs.has(currentRender)) {\r\n refs.set(currentRender, []);\r\n }\r\n\r\n const componentRefs = refs.get(currentRender)!;\r\n if (refIndex >= componentRefs.length) {\r\n // Initialize with an object that has a current property\r\n const ref = { current: initial };\r\n componentRefs.push(ref);\r\n stateIndices.set(currentRender, refIndex + 1);\r\n return ref;\r\n }\r\n\r\n const ref = componentRefs[refIndex];\r\n stateIndices.set(currentRender, refIndex + 1);\r\n return ref;\r\n}\r\n\r\n// Add a map to track component DOM nodes\r\nconst componentNodes = new Map<Function, Node>();\r\n\r\nasync function rerender(rendererId: number) {\r\n try {\r\n // Clean up effects\r\n const componentEffects = effects.get(rendererId);\r\n if (componentEffects) {\r\n componentEffects.forEach(effect => {\r\n if (effect.cleanup) effect.cleanup();\r\n });\r\n effects.set(rendererId, []);\r\n }\r\n\r\n if (globalRenderCallback && globalContainer && currentElement) {\r\n await globalRenderCallback(currentElement, globalContainer);\r\n }\r\n } catch (error) {\r\n console.error('Error during rerender:', error);\r\n }\r\n}\r\n\r\n// Add new hook for error boundaries\r\nexport function useErrorBoundary(): [Error | null, () => void] {\r\n const [error, setError] = useState<Error | null>(null);\r\n return [error, () => setError(null)];\r\n}\r\n\r\n// Remove withHooks export\r\n","\r\n\r\nconst contexts = new Map<symbol, any>();\r\nlet currentRender: Function | null = null;\r\n\r\nexport interface Context<T> {\r\n Provider: (props: { value: T; children?: any }) => any;\r\n Consumer: (props: { children: (value: T) => any }) => any;\r\n _id: symbol;\r\n useSelector: <S>(selector: (state: T) => S) => S;\r\n}\r\n\r\nexport function createContext<T>(defaultValue: T): Context<T> {\r\n const context = {\r\n Provider: ({ value, children }: { value: T, children?: any }) => {\r\n return children;\r\n },\r\n Consumer: ({ children }: { children: (value: T) => any }) => {\r\n return children(defaultValue);\r\n },\r\n _id: Symbol(),\r\n useSelector: <S>(selector: (state: T) => S) => {\r\n return selector(defaultValue);\r\n }\r\n };\r\n\r\n return context;\r\n}\r\n\r\nexport function useContext<T>(context: any): T {\r\n return context;\r\n}\r\n","import type { Component } from './component';\r\n\r\ninterface VNode {\r\n type: string | Function;\r\n props: Record<string, any>;\r\n}\r\n\r\nfunction jsx(type: string | Function, props: any): VNode {\r\n console.log('JSX Transform:', { type, props });\r\n const processedProps = { ...props };\r\n \r\n // Handle children properly\r\n if (arguments.length > 2) {\r\n processedProps.children = Array.prototype.slice.call(arguments, 2);\r\n }\r\n \r\n return { type, props: processedProps };\r\n}\r\n\r\nconst Fragment = ({ children }: { children: any }) => children;\r\n\r\nasync function createElement(vnode: VNode | any): Promise<Node> {\r\n console.log('Creating element from:', vnode);\r\n\r\n // Handle primitives and null\r\n if (vnode == null) {\r\n return document.createTextNode('');\r\n }\r\n \r\n if (typeof vnode === 'boolean') {\r\n return document.createTextNode('');\r\n }\r\n\r\n if (typeof vnode === 'number' || typeof vnode === 'string') {\r\n return document.createTextNode(String(vnode));\r\n }\r\n\r\n // Handle arrays\r\n if (Array.isArray(vnode)) {\r\n const fragment = document.createDocumentFragment();\r\n for (const child of vnode) {\r\n const node = await createElement(child);\r\n fragment.appendChild(node);\r\n }\r\n return fragment;\r\n }\r\n\r\n // Handle VNode\r\n if ('type' in vnode && vnode.props !== undefined) {\r\n const { type, props } = vnode;\r\n \r\n // Handle function components\r\n if (typeof type === 'function') {\r\n try {\r\n const result = await type(props || {});\r\n const node = await createElement(result);\r\n if (node instanceof Element) {\r\n node.setAttribute('data-component-id', type.name || type.toString());\r\n }\r\n return node;\r\n } catch (error) {\r\n console.error('Error rendering component:', error);\r\n return document.createTextNode('');\r\n }\r\n }\r\n\r\n // Create DOM element\r\n const element = document.createElement(type as string);\r\n \r\n // Handle props\r\n for (const [key, value] of Object.entries(props || {})) {\r\n if (key === 'children') continue;\r\n if (key.startsWith('on') && typeof value === 'function') {\r\n const eventName = key.toLowerCase().slice(2);\r\n // Remove existing event listener if any\r\n const existingHandler = (element as any).__events?.[eventName];\r\n if (existingHandler) {\r\n element.removeEventListener(eventName, existingHandler);\r\n }\r\n \r\n // Add new event listener\r\n element.addEventListener(eventName, value as EventListener);\r\n if (!(element as any).__events) {\r\n (element as any).__events = {};\r\n }\r\n (element as any).__events[eventName] = value;\r\n } else if (key === 'style' && typeof value === 'object') {\r\n Object.assign(element.style, value);\r\n } else if (key === 'className') {\r\n element.setAttribute('class', String(value));\r\n } else if (key !== 'key' && key !== 'ref') {\r\n element.setAttribute(key, String(value));\r\n }\r\n }\r\n\r\n // Handle children\r\n const children = props?.children;\r\n if (children != null) {\r\n const childArray = Array.isArray(children) ? children.flat() : [children];\r\n for (const child of childArray) {\r\n const childNode = await createElement(child);\r\n element.appendChild(childNode);\r\n }\r\n }\r\n\r\n return element;\r\n }\r\n\r\n // Handle other objects by converting to string\r\n return document.createTextNode(String(vnode));\r\n}\r\n\r\n// Export named functions and aliases without duplicates\r\nexport {\r\n jsx,\r\n jsx as jsxs,\r\n jsx as jsxDEV,\r\n Fragment,\r\n createElement\r\n};\r\n\r\n// Named exports object\r\nconst jsxRuntime = {\r\n jsx,\r\n jsxs: jsx,\r\n jsxDEV: jsx,\r\n Fragment,\r\n createElement\r\n};\r\n\r\nexport default jsxRuntime;\r\n","import { createElement } from './jsx-runtime';\r\nimport { prepareRender, finishRender, setRenderCallback } from './hooks';\r\nimport { batchUpdates } from './batch';\r\n\r\nlet isHydrating = false;\r\n\r\nexport async function hydrate(element: any, container: HTMLElement) {\r\n isHydrating = true;\r\n try {\r\n await render(element, container);\r\n } finally {\r\n isHydrating = false;\r\n }\r\n}\r\n\r\nexport async function render(element: any, container: HTMLElement) {\r\n console.log('Rendering to:', container.id);\r\n \r\n batchUpdates(async () => {\r\n const rendererId = prepareRender();\r\n try {\r\n setRenderCallback(render, element, container);\r\n const domNode = await createElement(element);\r\n \r\n if (!isHydrating) {\r\n container.innerHTML = '';\r\n }\r\n container.appendChild(domNode);\r\n \r\n } finally {\r\n finishRender();\r\n }\r\n });\r\n}\r\n","export interface TemplateOptions {\r\n title: string;\r\n description?: string;\r\n scripts?: string[];\r\n styles?: string[];\r\n initialState?: any;\r\n meta?: Record<string, string>;\r\n bodyAttrs?: Record<string, string>;\r\n htmlAttrs?: Record<string, string>;\r\n}\r\n\r\nexport function defaultTemplate(content: string, options: TemplateOptions): string {\r\n const {\r\n title,\r\n description = '',\r\n scripts = [],\r\n styles = [],\r\n initialState = {},\r\n meta = {},\r\n bodyAttrs = {},\r\n htmlAttrs = { lang: 'en' }\r\n } = options;\r\n\r\n const htmlAttributes = Object.entries(htmlAttrs)\r\n .map(([key, value]) => `${key}=\"${value}\"`)\r\n .join(' ');\r\n\r\n const bodyAttributes = Object.entries(bodyAttrs)\r\n .map(([key, value]) => `${key}=\"${value}\"`)\r\n .join(' ');\r\n\r\n const metaTags = Object.entries(meta)\r\n .map(([name, content]) => ` <meta name=\"${name}\" content=\"${content}\">`)\r\n .join('\\n');\r\n\r\n return `<!DOCTYPE html>\r\n<html ${htmlAttributes}>\r\n <head>\r\n <meta charset=\"UTF-8\">\r\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\r\n ${description ? `<meta name=\"description\" content=\"${description}\">\\n` : ''}${metaTags}\r\n <title>${title}</title>\r\n${styles.map(href => ` <link rel=\"stylesheet\" href=\"${href}\">`).join('\\n')}\r\n <script>\r\n window.__INITIAL_STATE__ = ${JSON.stringify(initialState)};\r\n </script>\r\n </head>\r\n <body ${bodyAttributes}>\r\n <div id=\"root\">${content}</div>\r\n${scripts.map(src => ` <script src=\"${src}\" defer></script>`).join('\\n')}\r\n </body>\r\n</html>`;\r\n}\r\n","import { VNode } from './types';\r\nimport { defaultTemplate, TemplateOptions } from './templates/default';\r\n\r\nexport async function renderToString(\r\n element: JSX.Element, \r\n options: Partial<TemplateOptions> = {}\r\n): Promise<string> {\r\n try {\r\n const content = await renderNodeToString(element);\r\n return defaultTemplate(content, {\r\n title: 'Frontend Hamroun App',\r\n ...options\r\n });\r\n } catch (error) {\r\n console.error('Error during server rendering:', error);\r\n return '';\r\n }\r\n}\r\n\r\nasync function renderNodeToString(node: VNode | any): Promise<string> {\r\n if (node == null || typeof node === 'boolean') {\r\n return '';\r\n }\r\n\r\n if (typeof node === 'number' || typeof node === 'string') {\r\n return escapeHtml(String(node));\r\n }\r\n\r\n if (typeof node === 'function') {\r\n const result = await node({ });\r\n return renderNodeToString(result);\r\n }\r\n\r\n if (node.type) {\r\n if (typeof node.type === 'function') {\r\n const result = await node.type(node.props || {});\r\n return renderNodeToString(result);\r\n }\r\n\r\n let html = `<${node.type}`;\r\n \r\n // Handle props\r\n for (const [key, value] of Object.entries(node.props || {})) {\r\n if (key === 'children' || key === 'key' || key === 'ref') continue;\r\n if (key === 'className') {\r\n html += ` class=\"${escapeHtml(String(value))}\"`;\r\n } else if (key === 'style' && typeof value === 'object' && value !== null) {\r\n html += ` style=\"${styleToString(value)}\"`;\r\n } else if (!key.startsWith('on')) {\r\n html += ` ${key}=\"${escapeHtml(String(value))}\"`;\r\n }\r\n }\r\n\r\n html += '>';\r\n\r\n // Handle children\r\n if (node.props?.children) {\r\n const children = Array.isArray(node.props.children) \r\n ? node.props.children \r\n : [node.props.children];\r\n \r\n for (const child of children) {\r\n html += await renderNodeToString(child);\r\n }\r\n }\r\n\r\n html += `</${node.type}>`;\r\n return html;\r\n }\r\n\r\n return '';\r\n}\r\n\r\nfunction escapeHtml(str: string): string {\r\n return str\r\n .replace(/&/g, '&')\r\n .replace(/</g, '<')\r\n .replace(/>/g, '>')\r\n .replace(/\"/g, '"')\r\n .replace(/'/g, ''');\r\n}\r\n\r\nfunction styleToString(style: Record<string, any>): string {\r\n return Object.entries(style)\r\n .map(([key, value]) => `${key}: ${value}`)\r\n .join('; ');\r\n}\r\n","import { useState, useEffect } from './hooks';\r\n\r\ninterface RouterState {\r\n pathname: string;\r\n search: string;\r\n hash: string;\r\n params: Record<string, string>;\r\n}\r\n\r\ninterface RouterOptions {\r\n replace?: boolean;\r\n scroll?: boolean;\r\n}\r\n\r\nlet currentState: RouterState = {\r\n pathname: typeof window !== 'undefined' ? window.location.pathname : '/',\r\n search: typeof window !== 'undefined' ? window.location.search : '',\r\n hash: typeof window !== 'undefined' ? window.location.hash : '',\r\n params: {}\r\n};\r\n\r\nconst listeners = new Set<(state: RouterState) => void>();\r\n\r\n// Parse route pattern and extract params\r\nfunction matchRoute(pattern: string, pathname: string): Record<string, string> | null {\r\n const paramNames: string[] = [];\r\n const regexPattern = pattern.replace(/:([^/]+)/g, (_, name) => {\r\n paramNames.push(name);\r\n return '([^/]+)';\r\n });\r\n\r\n const match = pathname.match(new RegExp(`^${regexPattern}$`));\r\n if (!match) return null;\r\n\r\n const params: Record<string, string> = {};\r\n paramNames.forEach((name, i) => {\r\n params[name] = match[i + 1];\r\n });\r\n\r\n return params;\r\n}\r\n\r\nfunction updateState(newPath: string, options: RouterOptions = {}) {\r\n const url = new URL(newPath, window.location.origin);\r\n const newState: RouterState = {\r\n pathname: url.pathname,\r\n search: url.search,\r\n hash: url.hash,\r\n params: {}\r\n };\r\n\r\n if (options.replace) {\r\n window.history.replaceState(newState, '', url.toString());\r\n } else {\r\n window.history.pushState(newState, '', url.toString());\r\n }\r\n\r\n currentState = newState;\r\n listeners.forEach(listener => listener(newState));\r\n\r\n if (options.scroll) {\r\n window.scrollTo(0, 0);\r\n }\r\n}\r\n\r\nexport function navigate(to: string, options: RouterOptions = {}) {\r\n if (typeof window === 'undefined') return;\r\n updateState(to, options);\r\n}\r\n\r\nexport function useRouter() {\r\n const [state, setState] = useState<RouterState>(currentState);\r\n\r\n useEffect(() => {\r\n const handleRouteChange = (newState: RouterState) => {\r\n setState(newState);\r\n };\r\n\r\n const handlePopState = () => {\r\n currentState = {\r\n pathname: window.location.pathname,\r\n search: window.location.search,\r\n hash: window.location.hash,\r\n params: {}\r\n };\r\n setState(currentState);\r\n };\r\n\r\n listeners.add(handleRouteChange);\r\n window.addEventListener('popstate', handlePopState);\r\n\r\n return () => {\r\n listeners.delete(handleRouteChange);\r\n window.removeEventListener('popstate', handlePopState);\r\n };\r\n }, []);\r\n\r\n return {\r\n ...state,\r\n push: (to: string, options?: RouterOptions) => navigate(to, options),\r\n replace: (to: string, options?: RouterOptions) => navigate(to, { ...options, replace: true }),\r\n back: () => window.history.back(),\r\n forward: () => window.history.forward()\r\n };\r\n}\r\n\r\nexport function useRoute(pattern: string) {\r\n const { pathname } = useRouter();\r\n const [params, setParams] = useState<Record<string, string>>({});\r\n const [isMatch, setIsMatch] = useState(false);\r\n\r\n useEffect(() => {\r\n const matchedParams = matchRoute(pattern, pathname);\r\n setIsMatch(!!matchedParams);\r\n setParams(matchedParams || {});\r\n }, [pattern, pathname]);\r\n\r\n return { isMatch, params };\r\n}\r\n\r\nexport function useParams<T extends Record<string, string>>() {\r\n const router = useRouter();\r\n return router.params as T;\r\n}\r\n\r\nexport function useSearchParams() {\r\n const { search } = useRouter();\r\n return new URLSearchParams(search);\r\n}\r\n","import { navigate } from './router';\r\n\r\ninterface LinkProps {\r\n href: string;\r\n children?: any;\r\n replace?: boolean;\r\n className?: string;\r\n style?: Record<string, string>;\r\n [key: string]: any;\r\n}\r\n\r\nexport function Link({ \r\n href, \r\n children, \r\n replace = false, \r\n className,\r\n style,\r\n ...rest \r\n}: LinkProps) {\r\n const handleClick = (e: MouseEvent) => {\r\n e.preventDefault();\r\n navigate(href, { replace });\r\n };\r\n\r\n return {\r\n type: 'a',\r\n props: {\r\n href,\r\n onClick: handleClick,\r\n className,\r\n style,\r\n ...rest,\r\n children\r\n }\r\n };\r\n}\r\n"],"names":["index","state","setState","ref","content"],"mappings":"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"}
|
1
|
+
{"version":3,"file":"index.mjs","sources":["../src/batch.ts","../src/hooks.ts","../src/jsx-runtime.ts","../src/context.ts","../src/renderer.ts","../src/templates/default.ts","../src/server-renderer.ts","../src/router.ts","../src/link.tsx"],"sourcesContent":["export let isBatching = false;\r\nconst queue: Function[] = [];\r\n\r\nexport function batchUpdates(fn: Function) {\r\n if (isBatching) {\r\n queue.push(fn);\r\n return;\r\n }\r\n\r\n isBatching = true;\r\n try {\r\n fn();\r\n while (queue.length > 0) {\r\n const nextFn = queue.shift();\r\n nextFn?.();\r\n }\r\n } finally {\r\n isBatching = false;\r\n }\r\n}\r\n\r\nexport function getIsBatching() {\r\n return isBatching;\r\n}\r\n","import { createElement } from './jsx-runtime';\r\nimport { batchUpdates, isBatching } from './batch';\r\nimport { diff } from './vdom';\r\n\r\nlet currentRender: number = 0;\r\nconst states = new Map<number, any[]>();\r\nconst stateIndices = new Map<number, number>();\r\nconst effects = new Map<number, Effect[]>();\r\nconst memos = new Map<number, { value: any; deps: any[] }[]>();\r\nconst refs = new Map<number, any[]>();\r\n\r\ninterface Effect {\r\n cleanup?: () => void;\r\n deps?: any[];\r\n}\r\n\r\n// Add at the top with other declarations\r\nlet globalRenderCallback: ((element: any, container: HTMLElement) => void) | null = null;\r\nlet globalContainer: HTMLElement | null = null;\r\nlet currentElement: any = null;\r\n\r\nconst isServer = typeof window === 'undefined';\r\nconst serverStates = new Map<number, any>();\r\n\r\nexport function setRenderCallback(\r\n callback: (element: any, container: HTMLElement) => void,\r\n element: any,\r\n container: HTMLElement\r\n) {\r\n globalRenderCallback = callback;\r\n globalContainer = container;\r\n currentElement = element;\r\n}\r\n\r\nexport function prepareRender() {\r\n currentRender++;\r\n stateIndices.set(currentRender, 0);\r\n return currentRender;\r\n}\r\n\r\nexport function finishRender() {\r\n if (isServer) {\r\n serverStates.delete(currentRender);\r\n }\r\n currentRender = 0;\r\n}\r\n\r\nexport function useState<T>(initial: T): [T, (value: T | ((prev: T) => T)) => void] {\r\n if (!currentRender) {\r\n throw new Error('useState must be called within a render');\r\n }\r\n\r\n if (isServer) {\r\n // Server-side state handling\r\n if (!serverStates.has(currentRender)) {\r\n serverStates.set(currentRender, new Map());\r\n }\r\n const componentState = serverStates.get(currentRender)!;\r\n const index = stateIndices.get(currentRender) || 0;\r\n \r\n if (!componentState.has(index)) {\r\n componentState.set(index, initial);\r\n }\r\n\r\n const state = componentState.get(index);\r\n const setState = (newValue: T | ((prev: T) => T)) => {\r\n // No-op for server-side\r\n };\r\n\r\n stateIndices.set(currentRender, index + 1);\r\n return [state, setState];\r\n }\r\n\r\n if (!states.has(currentRender)) {\r\n states.set(currentRender, []);\r\n }\r\n\r\n const componentStates = states.get(currentRender)!;\r\n const index = stateIndices.get(currentRender)!;\r\n \r\n if (index >= componentStates.length) {\r\n componentStates.push(initial);\r\n }\r\n\r\n const state = componentStates[index];\r\n const setState = (newValue: T | ((prev: T) => T)) => {\r\n const nextValue = typeof newValue === 'function' \r\n ? (newValue as Function)(componentStates[index])\r\n : newValue;\r\n\r\n if (componentStates[index] === nextValue) return; // Skip if value hasn't changed\r\n \r\n componentStates[index] = nextValue;\r\n \r\n if (isBatching) {\r\n batchUpdates(() => rerender(currentRender));\r\n } else {\r\n rerender(currentRender);\r\n }\r\n };\r\n\r\n stateIndices.set(currentRender, index + 1);\r\n return [state, setState];\r\n}\r\n\r\nexport function useEffect(callback: () => (() => void) | void, deps?: any[]) {\r\n if (!currentRender) throw new Error('useEffect must be called within a render');\r\n \r\n const effectIndex = stateIndices.get(currentRender)!;\r\n \r\n if (!effects.has(currentRender)) {\r\n effects.set(currentRender, []);\r\n }\r\n\r\n const componentEffects = effects.get(currentRender)!;\r\n const prevEffect = componentEffects[effectIndex];\r\n \r\n // Run effect if deps changed\r\n if (!prevEffect || !deps || !prevEffect.deps || \r\n deps.some((dep, i) => dep !== prevEffect.deps![i])) {\r\n \r\n // Cleanup previous effect\r\n if (prevEffect?.cleanup) {\r\n prevEffect.cleanup();\r\n }\r\n\r\n // Schedule new effect\r\n queueMicrotask(() => {\r\n const cleanup = callback() || undefined;\r\n componentEffects[effectIndex] = { cleanup: cleanup, deps };\r\n });\r\n }\r\n \r\n stateIndices.set(currentRender, effectIndex + 1);\r\n}\r\n\r\nexport function useMemo<T>(factory: () => T, deps: any[]): T {\r\n if (!currentRender) throw new Error('useMemo must be called within a render');\r\n \r\n const memoIndex = stateIndices.get(currentRender)!;\r\n \r\n if (!memos.has(currentRender)) {\r\n memos.set(currentRender, []);\r\n }\r\n\r\n const componentMemos = memos.get(currentRender)!;\r\n const prevMemo = componentMemos[memoIndex];\r\n \r\n if (!prevMemo || (deps && deps.some((dep, i) => !Object.is(dep, prevMemo.deps[i])))) {\r\n const value = factory();\r\n componentMemos[memoIndex] = { value, deps };\r\n stateIndices.set(currentRender, memoIndex + 1);\r\n return value;\r\n }\r\n\r\n stateIndices.set(currentRender, memoIndex + 1);\r\n return prevMemo.value;\r\n}\r\n\r\nexport function useRef<T>(initial: T) {\r\n if (!currentRender) throw new Error('useRef must be called within a render');\r\n \r\n const refIndex = stateIndices.get(currentRender)!;\r\n \r\n if (!refs.has(currentRender)) {\r\n refs.set(currentRender, []);\r\n }\r\n\r\n const componentRefs = refs.get(currentRender)!;\r\n if (refIndex >= componentRefs.length) {\r\n // Initialize with an object that has a current property\r\n const ref = { current: initial };\r\n componentRefs.push(ref);\r\n stateIndices.set(currentRender, refIndex + 1);\r\n return ref;\r\n }\r\n\r\n const ref = componentRefs[refIndex];\r\n stateIndices.set(currentRender, refIndex + 1);\r\n return ref;\r\n}\r\n\r\n// Add a map to track component DOM nodes\r\nconst componentNodes = new Map<Function, Node>();\r\n\r\nasync function rerender(rendererId: number) {\r\n try {\r\n // Clean up effects\r\n const componentEffects = effects.get(rendererId);\r\n if (componentEffects) {\r\n componentEffects.forEach(effect => {\r\n if (effect.cleanup) effect.cleanup();\r\n });\r\n effects.set(rendererId, []);\r\n }\r\n\r\n if (globalRenderCallback && globalContainer && currentElement) {\r\n await globalRenderCallback(currentElement, globalContainer);\r\n }\r\n } catch (error) {\r\n console.error('Error during rerender:', error);\r\n }\r\n}\r\n\r\n// Add new hook for error boundaries\r\nexport function useErrorBoundary(): [Error | null, () => void] {\r\n const [error, setError] = useState<Error | null>(null);\r\n return [error, () => setError(null)];\r\n}\r\n\r\n// Remove withHooks export\r\n","import type { Component } from './component';\r\n\r\ninterface VNode {\r\n type: string | Function;\r\n props: Record<string, any>;\r\n}\r\n\r\nfunction jsx(type: string | Function, props: any): VNode {\r\n console.log('JSX Transform:', { type, props });\r\n const processedProps = { ...props };\r\n \r\n // Handle children properly\r\n if (arguments.length > 2) {\r\n processedProps.children = Array.prototype.slice.call(arguments, 2);\r\n }\r\n \r\n return { type, props: processedProps };\r\n}\r\n\r\nconst Fragment = ({ children }: { children: any }) => children;\r\n\r\nasync function createElement(vnode: VNode | any): Promise<Node> {\r\n console.log('Creating element from:', vnode);\r\n\r\n // Handle primitives and null\r\n if (vnode == null) {\r\n return document.createTextNode('');\r\n }\r\n \r\n if (typeof vnode === 'boolean') {\r\n return document.createTextNode('');\r\n }\r\n\r\n if (typeof vnode === 'number' || typeof vnode === 'string') {\r\n return document.createTextNode(String(vnode));\r\n }\r\n\r\n // Handle arrays\r\n if (Array.isArray(vnode)) {\r\n const fragment = document.createDocumentFragment();\r\n for (const child of vnode) {\r\n const node = await createElement(child);\r\n fragment.appendChild(node);\r\n }\r\n return fragment;\r\n }\r\n\r\n // Handle VNode\r\n if ('type' in vnode && vnode.props !== undefined) {\r\n const { type, props } = vnode;\r\n \r\n // Handle function components\r\n if (typeof type === 'function') {\r\n try {\r\n const result = await type(props || {});\r\n const node = await createElement(result);\r\n if (node instanceof Element) {\r\n node.setAttribute('data-component-id', type.name || type.toString());\r\n }\r\n return node;\r\n } catch (error) {\r\n console.error('Error rendering component:', error);\r\n return document.createTextNode('');\r\n }\r\n }\r\n\r\n // Create DOM element\r\n const element = document.createElement(type as string);\r\n \r\n // Handle props\r\n for (const [key, value] of Object.entries(props || {})) {\r\n if (key === 'children') continue;\r\n if (key.startsWith('on') && typeof value === 'function') {\r\n const eventName = key.toLowerCase().slice(2);\r\n // Remove existing event listener if any\r\n const existingHandler = (element as any).__events?.[eventName];\r\n if (existingHandler) {\r\n element.removeEventListener(eventName, existingHandler);\r\n }\r\n \r\n // Add new event listener\r\n element.addEventListener(eventName, value as EventListener);\r\n if (!(element as any).__events) {\r\n (element as any).__events = {};\r\n }\r\n (element as any).__events[eventName] = value;\r\n } else if (key === 'style' && typeof value === 'object') {\r\n Object.assign(element.style, value);\r\n } else if (key === 'className') {\r\n element.setAttribute('class', String(value));\r\n } else if (key !== 'key' && key !== 'ref') {\r\n element.setAttribute(key, String(value));\r\n }\r\n }\r\n\r\n // Handle children\r\n const children = props?.children;\r\n if (children != null) {\r\n const childArray = Array.isArray(children) ? children.flat() : [children];\r\n for (const child of childArray) {\r\n const childNode = await createElement(child);\r\n element.appendChild(childNode);\r\n }\r\n }\r\n\r\n return element;\r\n }\r\n\r\n // Handle other objects by converting to string\r\n return document.createTextNode(String(vnode));\r\n}\r\n\r\n// Export named functions and aliases without duplicates\r\nexport {\r\n jsx,\r\n jsx as jsxs,\r\n jsx as jsxDEV,\r\n Fragment,\r\n createElement\r\n};\r\n\r\n// Named exports object\r\nconst jsxRuntime = {\r\n jsx,\r\n jsxs: jsx,\r\n jsxDEV: jsx,\r\n Fragment,\r\n createElement\r\n};\r\n\r\nexport default jsxRuntime;\r\n","\r\n\r\nconst contexts = new Map<symbol, any>();\r\nlet currentRender: Function | null = null;\r\n\r\nexport interface Context<T> {\r\n Provider: (props: { value: T; children?: any }) => any;\r\n Consumer: (props: { children: (value: T) => any }) => any;\r\n _id: symbol;\r\n useSelector: <S>(selector: (state: T) => S) => S;\r\n}\r\n\r\nexport function createContext<T>(defaultValue: T): Context<T> {\r\n const context = {\r\n Provider: ({ value, children }: { value: T, children?: any }) => {\r\n return children;\r\n },\r\n Consumer: ({ children }: { children: (value: T) => any }) => {\r\n return children(defaultValue);\r\n },\r\n _id: Symbol(),\r\n useSelector: <S>(selector: (state: T) => S) => {\r\n return selector(defaultValue);\r\n }\r\n };\r\n\r\n return context;\r\n}\r\n\r\nexport function useContext<T>(context: any): T {\r\n return context;\r\n}\r\n","import { createElement } from './jsx-runtime';\r\nimport { prepareRender, finishRender, setRenderCallback } from './hooks';\r\nimport { batchUpdates } from './batch';\r\n\r\nlet isHydrating = false;\r\n\r\nexport async function hydrate(element: any, container: HTMLElement) {\r\n isHydrating = true;\r\n try {\r\n await render(element, container);\r\n } finally {\r\n isHydrating = false;\r\n }\r\n}\r\n\r\nexport async function render(element: any, container: HTMLElement) {\r\n console.log('Rendering to:', container.id);\r\n \r\n batchUpdates(async () => {\r\n const rendererId = prepareRender();\r\n try {\r\n setRenderCallback(render, element, container);\r\n const domNode = await createElement(element);\r\n \r\n if (!isHydrating) {\r\n container.innerHTML = '';\r\n }\r\n container.appendChild(domNode);\r\n \r\n } finally {\r\n finishRender();\r\n }\r\n });\r\n}\r\n","export interface TemplateOptions {\r\n title: string;\r\n description?: string;\r\n scripts?: string[];\r\n styles?: string[];\r\n initialState?: any;\r\n meta?: Record<string, string>;\r\n bodyAttrs?: Record<string, string>;\r\n htmlAttrs?: Record<string, string>;\r\n}\r\n\r\nexport function defaultTemplate(content: string, options: TemplateOptions): string {\r\n const {\r\n title,\r\n description = '',\r\n scripts = [],\r\n styles = [],\r\n initialState = {},\r\n meta = {},\r\n bodyAttrs = {},\r\n htmlAttrs = { lang: 'en' }\r\n } = options;\r\n\r\n const htmlAttributes = Object.entries(htmlAttrs)\r\n .map(([key, value]) => `${key}=\"${value}\"`)\r\n .join(' ');\r\n\r\n const bodyAttributes = Object.entries(bodyAttrs)\r\n .map(([key, value]) => `${key}=\"${value}\"`)\r\n .join(' ');\r\n\r\n const metaTags = Object.entries(meta)\r\n .map(([name, content]) => ` <meta name=\"${name}\" content=\"${content}\">`)\r\n .join('\\n');\r\n\r\n return `<!DOCTYPE html>\r\n<html ${htmlAttributes}>\r\n <head>\r\n <meta charset=\"UTF-8\">\r\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\r\n ${description ? `<meta name=\"description\" content=\"${description}\">\\n` : ''}${metaTags}\r\n <title>${title}</title>\r\n${styles.map(href => ` <link rel=\"stylesheet\" href=\"${href}\">`).join('\\n')}\r\n <script>\r\n window.__INITIAL_STATE__ = ${JSON.stringify(initialState)};\r\n </script>\r\n </head>\r\n <body ${bodyAttributes}>\r\n <div id=\"root\">${content}</div>\r\n${scripts.map(src => ` <script src=\"${src}\" defer></script>`).join('\\n')}\r\n </body>\r\n</html>`;\r\n}\r\n","import { VNode } from './types';\r\nimport { defaultTemplate, TemplateOptions } from './templates/default';\r\n\r\nexport async function renderToString(\r\n element: JSX.Element, \r\n options: Partial<TemplateOptions> = {}\r\n): Promise<string> {\r\n try {\r\n const content = await renderNodeToString(element);\r\n return defaultTemplate(content, {\r\n title: 'Frontend Hamroun App',\r\n ...options\r\n });\r\n } catch (error) {\r\n console.error('Error during server rendering:', error);\r\n return '';\r\n }\r\n}\r\n\r\nasync function renderNodeToString(node: VNode | any): Promise<string> {\r\n if (node == null || typeof node === 'boolean') {\r\n return '';\r\n }\r\n\r\n if (typeof node === 'number' || typeof node === 'string') {\r\n return escapeHtml(String(node));\r\n }\r\n\r\n if (typeof node === 'function') {\r\n const result = await node({ });\r\n return renderNodeToString(result);\r\n }\r\n\r\n if (node.type) {\r\n if (typeof node.type === 'function') {\r\n const result = await node.type(node.props || {});\r\n return renderNodeToString(result);\r\n }\r\n\r\n let html = `<${node.type}`;\r\n \r\n // Handle props\r\n for (const [key, value] of Object.entries(node.props || {})) {\r\n if (key === 'children' || key === 'key' || key === 'ref') continue;\r\n if (key === 'className') {\r\n html += ` class=\"${escapeHtml(String(value))}\"`;\r\n } else if (key === 'style' && typeof value === 'object' && value !== null) {\r\n html += ` style=\"${styleToString(value)}\"`;\r\n } else if (!key.startsWith('on')) {\r\n html += ` ${key}=\"${escapeHtml(String(value))}\"`;\r\n }\r\n }\r\n\r\n html += '>';\r\n\r\n // Handle children\r\n if (node.props?.children) {\r\n const children = Array.isArray(node.props.children) \r\n ? node.props.children \r\n : [node.props.children];\r\n \r\n for (const child of children) {\r\n html += await renderNodeToString(child);\r\n }\r\n }\r\n\r\n html += `</${node.type}>`;\r\n return html;\r\n }\r\n\r\n return '';\r\n}\r\n\r\nfunction escapeHtml(str: string): string {\r\n return str\r\n .replace(/&/g, '&')\r\n .replace(/</g, '<')\r\n .replace(/>/g, '>')\r\n .replace(/\"/g, '"')\r\n .replace(/'/g, ''');\r\n}\r\n\r\nfunction styleToString(style: Record<string, any>): string {\r\n return Object.entries(style)\r\n .map(([key, value]) => `${key}: ${value}`)\r\n .join('; ');\r\n}\r\n","import { useState, useEffect } from './hooks';\r\n\r\ninterface RouterState {\r\n pathname: string;\r\n search: string;\r\n hash: string;\r\n params: Record<string, string>;\r\n}\r\n\r\ninterface RouterOptions {\r\n replace?: boolean;\r\n scroll?: boolean;\r\n}\r\n\r\nlet currentState: RouterState = {\r\n pathname: typeof window !== 'undefined' ? window.location.pathname : '/',\r\n search: typeof window !== 'undefined' ? window.location.search : '',\r\n hash: typeof window !== 'undefined' ? window.location.hash : '',\r\n params: {}\r\n};\r\n\r\nconst listeners = new Set<(state: RouterState) => void>();\r\n\r\n// Parse route pattern and extract params\r\nfunction matchRoute(pattern: string, pathname: string): Record<string, string> | null {\r\n const paramNames: string[] = [];\r\n const regexPattern = pattern.replace(/:([^/]+)/g, (_, name) => {\r\n paramNames.push(name);\r\n return '([^/]+)';\r\n });\r\n\r\n const match = pathname.match(new RegExp(`^${regexPattern}$`));\r\n if (!match) return null;\r\n\r\n const params: Record<string, string> = {};\r\n paramNames.forEach((name, i) => {\r\n params[name] = match[i + 1];\r\n });\r\n\r\n return params;\r\n}\r\n\r\nfunction updateState(newPath: string, options: RouterOptions = {}) {\r\n const url = new URL(newPath, window.location.origin);\r\n const newState: RouterState = {\r\n pathname: url.pathname,\r\n search: url.search,\r\n hash: url.hash,\r\n params: {}\r\n };\r\n\r\n if (options.replace) {\r\n window.history.replaceState(newState, '', url.toString());\r\n } else {\r\n window.history.pushState(newState, '', url.toString());\r\n }\r\n\r\n currentState = newState;\r\n listeners.forEach(listener => listener(newState));\r\n\r\n if (options.scroll) {\r\n window.scrollTo(0, 0);\r\n }\r\n}\r\n\r\nexport function navigate(to: string, options: RouterOptions = {}) {\r\n if (typeof window === 'undefined') return;\r\n updateState(to, options);\r\n}\r\n\r\nexport function useRouter() {\r\n const [state, setState] = useState<RouterState>(currentState);\r\n\r\n useEffect(() => {\r\n const handleRouteChange = (newState: RouterState) => {\r\n setState(newState);\r\n };\r\n\r\n const handlePopState = () => {\r\n currentState = {\r\n pathname: window.location.pathname,\r\n search: window.location.search,\r\n hash: window.location.hash,\r\n params: {}\r\n };\r\n setState(currentState);\r\n };\r\n\r\n listeners.add(handleRouteChange);\r\n window.addEventListener('popstate', handlePopState);\r\n\r\n return () => {\r\n listeners.delete(handleRouteChange);\r\n window.removeEventListener('popstate', handlePopState);\r\n };\r\n }, []);\r\n\r\n return {\r\n ...state,\r\n push: (to: string, options?: RouterOptions) => navigate(to, options),\r\n replace: (to: string, options?: RouterOptions) => navigate(to, { ...options, replace: true }),\r\n back: () => window.history.back(),\r\n forward: () => window.history.forward()\r\n };\r\n}\r\n\r\nexport function useRoute(pattern: string) {\r\n const { pathname } = useRouter();\r\n const [params, setParams] = useState<Record<string, string>>({});\r\n const [isMatch, setIsMatch] = useState(false);\r\n\r\n useEffect(() => {\r\n const matchedParams = matchRoute(pattern, pathname);\r\n setIsMatch(!!matchedParams);\r\n setParams(matchedParams || {});\r\n }, [pattern, pathname]);\r\n\r\n return { isMatch, params };\r\n}\r\n\r\nexport function useParams<T extends Record<string, string>>() {\r\n const router = useRouter();\r\n return router.params as T;\r\n}\r\n\r\nexport function useSearchParams() {\r\n const { search } = useRouter();\r\n return new URLSearchParams(search);\r\n}\r\n","import { navigate } from './router';\r\n\r\ninterface LinkProps {\r\n href: string;\r\n children?: any;\r\n replace?: boolean;\r\n className?: string;\r\n style?: Record<string, string>;\r\n [key: string]: any;\r\n}\r\n\r\nexport function Link({ \r\n href, \r\n children, \r\n replace = false, \r\n className,\r\n style,\r\n ...rest \r\n}: LinkProps) {\r\n const handleClick = (e: MouseEvent) => {\r\n e.preventDefault();\r\n navigate(href, { replace });\r\n };\r\n\r\n return {\r\n type: 'a',\r\n props: {\r\n href,\r\n onClick: handleClick,\r\n className,\r\n style,\r\n ...rest,\r\n children\r\n }\r\n };\r\n}\r\n"],"names":["index","state","setState","ref","content"],"mappings":"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"}
|
package/package.json
CHANGED
@@ -1,26 +1,36 @@
|
|
1
|
-
import { useState } from 'frontend-hamroun';
|
1
|
+
import { useState, useEffect } from 'frontend-hamroun';
|
2
|
+
|
3
|
+
interface AppProps {
|
4
|
+
initialUrl?: string;
|
5
|
+
initialSettings?: {
|
6
|
+
theme: string;
|
7
|
+
};
|
8
|
+
user?: any;
|
9
|
+
}
|
10
|
+
|
11
|
+
export function App({
|
12
|
+
initialUrl = '/',
|
13
|
+
initialSettings = { theme: 'light' },
|
14
|
+
user = null
|
15
|
+
}: AppProps) {
|
16
|
+
const [theme, setTheme] = useState(initialSettings.theme);
|
17
|
+
|
18
|
+
useEffect(() => {
|
19
|
+
document.body.dataset.theme = theme;
|
20
|
+
}, [theme]);
|
2
21
|
|
3
|
-
export function App() {
|
4
|
-
// Initialize with a default state that works on both server and client
|
5
|
-
const [count, setCount] = useState(0);
|
6
|
-
|
7
22
|
return (
|
8
|
-
<div>
|
9
|
-
<
|
10
|
-
|
11
|
-
<button
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
<
|
17
|
-
|
18
|
-
|
19
|
-
>+</button>
|
20
|
-
</div>
|
21
|
-
<script dangerouslySetInnerHTML={{
|
22
|
-
__html: `window.__INITIAL_STATE__ = ${JSON.stringify({ count: 0 })};`
|
23
|
-
}} />
|
23
|
+
<div className="app">
|
24
|
+
<header>
|
25
|
+
<h1>My SSR App</h1>
|
26
|
+
<button onClick={() => setTheme(t => t === 'light' ? 'dark' : 'light')}>
|
27
|
+
Toggle Theme
|
28
|
+
</button>
|
29
|
+
</header>
|
30
|
+
<main>
|
31
|
+
<p>Current URL: {initialUrl}</p>
|
32
|
+
{user && <p>Welcome, {user.name}!</p>}
|
33
|
+
</main>
|
24
34
|
</div>
|
25
35
|
);
|
26
36
|
}
|
@@ -1,11 +1,29 @@
|
|
1
1
|
import { hydrate } from 'frontend-hamroun';
|
2
2
|
import { App } from './App';
|
3
3
|
|
4
|
+
// Type-safe initial state access
|
5
|
+
declare global {
|
6
|
+
interface Window {
|
7
|
+
__INITIAL_STATE__: {
|
8
|
+
url: string;
|
9
|
+
user: any;
|
10
|
+
settings: {
|
11
|
+
theme: string;
|
12
|
+
};
|
13
|
+
};
|
14
|
+
}
|
15
|
+
}
|
4
16
|
|
17
|
+
// Get state from server
|
18
|
+
const initialState = window.__INITIAL_STATE__;
|
5
19
|
|
6
20
|
document.addEventListener('DOMContentLoaded', () => {
|
7
21
|
hydrate(
|
8
|
-
<App
|
22
|
+
<App
|
23
|
+
initialUrl={initialState.url}
|
24
|
+
initialSettings={initialState.settings}
|
25
|
+
user={initialState.user}
|
26
|
+
/>,
|
9
27
|
document.getElementById('root')!
|
10
28
|
);
|
11
29
|
});
|
@@ -1,43 +1,42 @@
|
|
1
1
|
import express from 'express';
|
2
2
|
import path from 'path';
|
3
3
|
import { fileURLToPath } from 'url';
|
4
|
-
import { renderToString,
|
5
|
-
import { App } from './App
|
6
|
-
import fs from 'fs';
|
7
|
-
import { title } from 'process';
|
4
|
+
import { renderToString, createElement } from 'frontend-hamroun';
|
5
|
+
import { App } from './App';
|
8
6
|
|
9
7
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
10
8
|
const app = express();
|
11
9
|
const port = 3000;
|
12
10
|
|
13
|
-
//
|
14
|
-
|
15
|
-
const assetsDir = path.join(__dirname, './');
|
16
|
-
const files = fs.readdirSync(assetsDir);
|
17
|
-
const entry = files.find(file => file.startsWith("client") && file.endsWith('.js'));
|
18
|
-
if (!entry) {
|
19
|
-
throw new Error('Client entry file not found');
|
20
|
-
}
|
21
|
-
return entry;
|
22
|
-
}
|
23
|
-
|
24
|
-
// Static file serving
|
25
|
-
app.use('/assets', express.static(path.join(__dirname, './')));
|
26
|
-
app.use(express.static(path.join(__dirname, 'dist')));
|
11
|
+
// Static files
|
12
|
+
app.use('/assets', express.static(path.join(__dirname, './assets')));
|
27
13
|
|
28
|
-
//
|
29
|
-
app.get('
|
14
|
+
// All routes handler
|
15
|
+
app.get('*', async (req, res) => {
|
30
16
|
try {
|
31
|
-
|
32
|
-
const
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
17
|
+
// Get initial state based on route
|
18
|
+
const initialState = {
|
19
|
+
url: req.url,
|
20
|
+
user: null, // Add your user data here
|
21
|
+
settings: { theme: 'light' }
|
22
|
+
};
|
23
|
+
|
24
|
+
const html = await renderToString(createElement(App, {
|
25
|
+
initialUrl: req.url,
|
26
|
+
initialSettings: initialState.settings,
|
27
|
+
user: initialState.user
|
28
|
+
}), {
|
29
|
+
title: 'My SSR App',
|
30
|
+
description: 'Server-side rendered application',
|
31
|
+
scripts: ['/assets/client.js'],
|
32
|
+
styles: ['/assets/styles.css'],
|
33
|
+
initialState,
|
39
34
|
meta: {
|
40
|
-
'
|
35
|
+
'theme-color': '#ffffff',
|
36
|
+
'og:title': 'My SSR App'
|
37
|
+
},
|
38
|
+
bodyAttrs: {
|
39
|
+
'data-theme': initialState.settings.theme
|
41
40
|
}
|
42
41
|
});
|
43
42
|
|
@@ -49,5 +48,5 @@ app.get('/', async (_req: any, res: { send: (arg0: string) => void; status: (arg
|
|
49
48
|
});
|
50
49
|
|
51
50
|
app.listen(port, () => {
|
52
|
-
console.log(
|
51
|
+
console.log(`✓ Server running at http://localhost:${port}`);
|
53
52
|
});
|