frontend-hamroun 1.2.50 → 1.2.52
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 +710 -121
- package/package.json +1 -1
package/README.md
CHANGED
@@ -1,46 +1,67 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
A lightweight JavaScript framework with Virtual DOM and hooks implementation inspired by modern frameworks.
|
4
|
-
|
5
|
-

|
6
|
-

|
7
|
-

|
8
|
-

|
9
|
-
|
10
|
-
## Installation
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
1
|
+
<div align="center">
|
19
2
|
|
3
|
+
# 🚀 Frontend Hamroun
|
20
4
|
|
5
|
+
A lightweight full-stack JavaScript framework with Virtual DOM and hooks implementation
|
21
6
|
|
7
|
+
[](https://www.npmjs.com/package/frontend-hamroun)
|
8
|
+
[](https://bundlephobia.com/result?p=frontend-hamroun)
|
9
|
+
[](https://www.npmjs.com/package/frontend-hamroun)
|
10
|
+
[](LICENSE)
|
22
11
|
|
12
|
+
<img src="https://via.placeholder.com/800x400?text=Frontend+Hamroun+Framework" alt="Framework Banner" width="800" style="border-radius: 10px;"/>
|
23
13
|
|
14
|
+
</div>
|
24
15
|
|
16
|
+
<br>
|
25
17
|
|
18
|
+
## 📋 Contents
|
26
19
|
|
20
|
+
- [Installation](#-installation)
|
21
|
+
- [Quick Start](#-quick-start)
|
22
|
+
- [Features](#-features)
|
23
|
+
- [Client-side Features](#-client-side-features)
|
24
|
+
- [Server-side Features](#-server-side-features)
|
25
|
+
- [Server-Side Rendering](#-server-side-rendering)
|
26
|
+
- [Performance Optimization](#-performance-optimization)
|
27
|
+
- [CLI Tools](#-cli-tools)
|
28
|
+
- [TypeScript Support](#-typescript-support)
|
29
|
+
- [Browser Compatibility](#-browser-compatibility)
|
30
|
+
- [Contributing](#-contributing)
|
31
|
+
- [Documentation](#-documentation)
|
27
32
|
|
33
|
+
<br>
|
28
34
|
|
35
|
+
## 🔌 Installation
|
29
36
|
|
30
37
|
```bash
|
31
38
|
npm install frontend-hamroun
|
32
39
|
```
|
33
40
|
|
34
|
-
|
41
|
+
<div align="center">
|
42
|
+
|
43
|
+
### ✨ Quick Links
|
44
|
+
|
45
|
+
[](https://github.com/hamroun/frontend-hamroun)
|
46
|
+
[](https://github.com/hamroun/frontend-hamroun/examples)
|
47
|
+
[](https://github.com/hamroun/frontend-hamroun/docs/API.md)
|
48
|
+
[](https://discord.gg/frontendhamroun)
|
49
|
+
|
50
|
+
</div>
|
35
51
|
|
36
|
-
|
52
|
+
## 🚀 Quick Start
|
53
|
+
|
54
|
+
Create a new project with a single command:
|
37
55
|
|
38
56
|
```bash
|
57
|
+
# Using create-frontend-app
|
39
58
|
npx create-frontend-app my-app
|
40
|
-
|
41
|
-
|
59
|
+
|
60
|
+
# Or using the frontend-hamroun CLI
|
61
|
+
npx frontend-hamroun create my-app
|
42
62
|
```
|
43
|
-
|
63
|
+
|
64
|
+
Then launch your new project:
|
44
65
|
|
45
66
|
```bash
|
46
67
|
cd my-app
|
@@ -48,17 +69,92 @@ npm install
|
|
48
69
|
npm run dev
|
49
70
|
```
|
50
71
|
|
51
|
-
|
72
|
+
<div align="center">
|
73
|
+
|
74
|
+
### 🎮 Interactive Demo
|
75
|
+
|
76
|
+
[](https://codesandbox.io)
|
77
|
+
[](https://stackblitz.com)
|
78
|
+
|
79
|
+
</div>
|
80
|
+
|
81
|
+
## 🎯 Features
|
82
|
+
|
83
|
+
<div class="features-grid" style="display: grid; grid-template-columns: repeat(2, 1fr); gap: 20px;">
|
84
|
+
|
85
|
+
<div class="feature-card" style="background: #f8f9fa; border-radius: 8px; padding: 20px;">
|
86
|
+
<h3>🔍 Lightweight Core</h3>
|
87
|
+
<p><strong><5KB</strong> gzipped for essential runtime</p>
|
88
|
+
</div>
|
89
|
+
|
90
|
+
<div class="feature-card" style="background: #f8f9fa; border-radius: 8px; padding: 20px;">
|
91
|
+
<h3>⚡ Full-Stack Solution</h3>
|
92
|
+
<p>Client and server capabilities in one package</p>
|
93
|
+
</div>
|
94
|
+
|
95
|
+
<div class="feature-card" style="background: #f8f9fa; border-radius: 8px; padding: 20px;">
|
96
|
+
<h3>🔄 Virtual DOM</h3>
|
97
|
+
<p>Efficient rendering and diffing algorithm</p>
|
98
|
+
</div>
|
99
|
+
|
100
|
+
<div class="feature-card" style="background: #f8f9fa; border-radius: 8px; padding: 20px;">
|
101
|
+
<h3>🪝 Hooks API</h3>
|
102
|
+
<p>Complete hooks system for state management</p>
|
103
|
+
</div>
|
104
|
+
|
105
|
+
<div class="feature-card" style="background: #f8f9fa; border-radius: 8px; padding: 20px;">
|
106
|
+
<h3>🌐 Server-Side Rendering</h3>
|
107
|
+
<p>Optimized SSR with hydration</p>
|
108
|
+
</div>
|
109
|
+
|
110
|
+
<div class="feature-card" style="background: #f8f9fa; border-radius: 8px; padding: 20px;">
|
111
|
+
<h3>🔐 Authentication</h3>
|
112
|
+
<p>Built-in JWT authentication system</p>
|
113
|
+
</div>
|
114
|
+
|
115
|
+
<div class="feature-card" style="background: #f8f9fa; border-radius: 8px; padding: 20px;">
|
116
|
+
<h3>💾 Database Integration</h3>
|
117
|
+
<p>Support for MongoDB, MySQL, PostgreSQL</p>
|
118
|
+
</div>
|
119
|
+
|
120
|
+
<div class="feature-card" style="background: #f8f9fa; border-radius: 8px; padding: 20px;">
|
121
|
+
<h3>🧩 TypeScript Support</h3>
|
122
|
+
<p>Full type definitions included</p>
|
123
|
+
</div>
|
124
|
+
|
125
|
+
</div>
|
126
|
+
|
127
|
+
<br>
|
128
|
+
|
129
|
+
## 📊 Framework Comparison
|
130
|
+
|
131
|
+
| Feature | Frontend Hamroun | React | Vue | Angular |
|
132
|
+
|---------|------------------|-------|-----|---------|
|
133
|
+
| Bundle Size | < 5KB | 42KB | 33KB | 65KB |
|
134
|
+
| Virtual DOM | ✅ | ✅ | ✅ | ❌ |
|
135
|
+
| Hooks API | ✅ | ✅ | ⚠️ | ❌ |
|
136
|
+
| Built-in SSR | ✅ | ❌ | ⚠️ | ✅ |
|
137
|
+
| Built-in API Server | ✅ | ❌ | ❌ | ❌ |
|
138
|
+
| DB Integration | ✅ | ❌ | ❌ | ❌ |
|
139
|
+
| Learning Curve | Low | Medium | Low | High |
|
140
|
+
|
141
|
+
<br>
|
142
|
+
|
143
|
+
## 💻 Basic Usage
|
52
144
|
|
53
145
|
```jsx
|
54
146
|
import { render, useState } from 'frontend-hamroun';
|
55
147
|
|
56
148
|
function App() {
|
57
149
|
const [count, setCount] = useState(0);
|
150
|
+
|
58
151
|
return (
|
59
|
-
<div>
|
60
|
-
<h1>
|
61
|
-
<
|
152
|
+
<div className="app">
|
153
|
+
<h1>Frontend Hamroun Demo</h1>
|
154
|
+
<p>Count: {count}</p>
|
155
|
+
<button onClick={() => setCount(count + 1)}>
|
156
|
+
Increment
|
157
|
+
</button>
|
62
158
|
</div>
|
63
159
|
);
|
64
160
|
}
|
@@ -66,164 +162,657 @@ function App() {
|
|
66
162
|
render(<App />, document.getElementById('root'));
|
67
163
|
```
|
68
164
|
|
69
|
-
|
165
|
+
<div align="center">
|
166
|
+
<img src="https://via.placeholder.com/600x300?text=Application+Screenshot" alt="Application Screenshot" width="600" style="border-radius: 8px;"/>
|
167
|
+
</div>
|
70
168
|
|
71
|
-
|
72
|
-
- Virtual DOM with efficient diffing algorithm
|
73
|
-
- Hooks API (useState, useEffect, useMemo, useRef)
|
74
|
-
- Context API
|
75
|
-
- Server-Side Rendering
|
76
|
-
- Error Boundaries
|
77
|
-
- JSX support
|
78
|
-
- TypeScript support
|
79
|
-
- Built-in CLI for project scaffolding
|
169
|
+
## 🧩 Client-side Features
|
80
170
|
|
81
|
-
|
171
|
+
### Component Development
|
82
172
|
|
83
|
-
|
84
|
-
Manages component state.
|
173
|
+
Frontend Hamroun provides a React-like development experience:
|
85
174
|
|
86
|
-
```
|
87
|
-
|
88
|
-
|
89
|
-
|
175
|
+
```jsx
|
176
|
+
import { useState, useEffect } from 'frontend-hamroun';
|
177
|
+
|
178
|
+
function Counter() {
|
179
|
+
const [count, setCount] = useState(0);
|
180
|
+
|
181
|
+
useEffect(() => {
|
182
|
+
document.title = `Count: ${count}`;
|
183
|
+
return () => document.title = 'App';
|
184
|
+
}, [count]);
|
185
|
+
|
186
|
+
return (
|
187
|
+
<div className="counter">
|
188
|
+
<h2>Counter: {count}</h2>
|
189
|
+
<div className="buttons">
|
190
|
+
<button onClick={() => setCount(count + 1)}>+</button>
|
191
|
+
<button onClick={() => setCount(count - 1)}>-</button>
|
192
|
+
</div>
|
193
|
+
</div>
|
194
|
+
);
|
195
|
+
}
|
90
196
|
```
|
91
197
|
|
92
|
-
|
93
|
-
|
198
|
+
<details>
|
199
|
+
<summary><b>🔍 View Hooks API Reference</b></summary>
|
94
200
|
|
95
|
-
|
201
|
+
### Hooks System
|
202
|
+
|
203
|
+
#### 🔄 useState
|
204
|
+
```jsx
|
205
|
+
const [count, setCount] = useState(0);
|
206
|
+
setCount(count + 1); // Direct update
|
207
|
+
setCount(prev => prev + 1); // Functional update
|
208
|
+
```
|
209
|
+
|
210
|
+
#### 🔄 useEffect
|
211
|
+
```jsx
|
96
212
|
useEffect(() => {
|
97
|
-
|
213
|
+
// Effect logic
|
214
|
+
const subscription = api.subscribe();
|
98
215
|
|
99
216
|
return () => {
|
100
|
-
// Cleanup
|
101
|
-
|
217
|
+
// Cleanup logic
|
218
|
+
subscription.unsubscribe();
|
102
219
|
};
|
103
|
-
}, [
|
220
|
+
}, [dependency]); // Dependency array
|
104
221
|
```
|
105
222
|
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
console.log('Computing doubled value');
|
112
|
-
return count * 2;
|
113
|
-
}, [count]);
|
223
|
+
#### 🔄 useMemo
|
224
|
+
```jsx
|
225
|
+
const expensiveValue = useMemo(() => {
|
226
|
+
return computeExpensiveValue(a, b);
|
227
|
+
}, [a, b]); // Recomputes only when a or b changes
|
114
228
|
```
|
115
229
|
|
116
|
-
|
117
|
-
|
230
|
+
#### 🔄 useRef
|
231
|
+
```jsx
|
232
|
+
const inputRef = useRef(null);
|
118
233
|
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
234
|
+
// Access the DOM element directly
|
235
|
+
useEffect(() => {
|
236
|
+
inputRef.current.focus();
|
237
|
+
}, []);
|
123
238
|
|
124
|
-
|
125
|
-
|
239
|
+
return <input ref={inputRef} />;
|
240
|
+
```
|
126
241
|
|
127
|
-
|
242
|
+
#### 🔄 useErrorBoundary
|
243
|
+
```jsx
|
128
244
|
const [error, resetError] = useErrorBoundary();
|
129
245
|
|
130
246
|
if (error) {
|
131
247
|
return (
|
132
|
-
<div>
|
133
|
-
<
|
248
|
+
<div className="error-boundary">
|
249
|
+
<h2>Something went wrong</h2>
|
250
|
+
<p>{error.message}</p>
|
134
251
|
<button onClick={resetError}>Try again</button>
|
135
252
|
</div>
|
136
253
|
);
|
137
254
|
}
|
138
255
|
```
|
139
256
|
|
140
|
-
|
257
|
+
</details>
|
141
258
|
|
142
|
-
|
259
|
+
### 🔄 Context API
|
143
260
|
|
144
|
-
|
261
|
+
Share state across your component tree:
|
262
|
+
|
263
|
+
<div class="code-with-diagram" style="display: flex; align-items: flex-start; gap: 20px;">
|
264
|
+
|
265
|
+
```jsx
|
145
266
|
// Create context
|
146
267
|
const ThemeContext = createContext('light');
|
147
268
|
|
148
|
-
// Provider
|
269
|
+
// Provider
|
149
270
|
function App() {
|
150
271
|
const [theme, setTheme] = useState('light');
|
151
272
|
|
152
273
|
return (
|
153
274
|
<ThemeContext.Provider value={theme}>
|
154
|
-
<
|
155
|
-
|
156
|
-
|
157
|
-
|
275
|
+
<Header />
|
276
|
+
<Main />
|
277
|
+
<button onClick={() => setTheme(
|
278
|
+
theme === 'light' ? 'dark' : 'light'
|
279
|
+
)}>
|
280
|
+
Toggle theme
|
281
|
+
</button>
|
158
282
|
</ThemeContext.Provider>
|
159
283
|
);
|
160
284
|
}
|
161
285
|
|
162
|
-
// Consumer
|
163
|
-
function
|
286
|
+
// Consumer
|
287
|
+
function Header() {
|
164
288
|
const theme = useContext(ThemeContext);
|
165
|
-
return
|
166
|
-
|
167
|
-
|
289
|
+
return (
|
290
|
+
<header className={theme}>
|
291
|
+
<h1>My App</h1>
|
292
|
+
</header>
|
293
|
+
);
|
168
294
|
}
|
169
295
|
```
|
170
296
|
|
171
|
-
|
297
|
+
<div class="diagram" style="background: #f8f9fa; border-radius: 8px; padding: 15px; width: 300px;">
|
298
|
+
<strong>Context Flow Diagram</strong><br>
|
299
|
+
<pre style="background: #f0f0f0; padding: 10px; margin-top: 10px; border-radius: 5px;">
|
300
|
+
App (Provider)
|
301
|
+
│
|
302
|
+
├─► Header (Consumer)
|
303
|
+
│ Uses theme value
|
304
|
+
│
|
305
|
+
├─► Main
|
306
|
+
│ │
|
307
|
+
│ └─► Article (Consumer)
|
308
|
+
│ Uses theme value
|
309
|
+
│
|
310
|
+
└─► Footer (Consumer)
|
311
|
+
Uses theme value
|
312
|
+
</pre>
|
313
|
+
</div>
|
314
|
+
|
315
|
+
</div>
|
316
|
+
|
317
|
+
## 🖥️ Server-Side Features
|
318
|
+
|
319
|
+
### Express Server Integration
|
320
|
+
|
321
|
+
```js
|
322
|
+
import { server } from 'frontend-hamroun/server';
|
323
|
+
|
324
|
+
const app = await server.createServer({
|
325
|
+
port: 3000,
|
326
|
+
apiDir: './api',
|
327
|
+
pagesDir: './pages',
|
328
|
+
staticDir: './public',
|
329
|
+
db: {
|
330
|
+
url: process.env.DATABASE_URL,
|
331
|
+
type: 'mongodb' // or 'mysql', 'postgres'
|
332
|
+
},
|
333
|
+
auth: {
|
334
|
+
secret: process.env.JWT_SECRET,
|
335
|
+
expiresIn: '7d'
|
336
|
+
}
|
337
|
+
});
|
172
338
|
|
173
|
-
|
339
|
+
await app.start();
|
340
|
+
console.log('Server running at http://localhost:3000');
|
341
|
+
```
|
174
342
|
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
343
|
+
<div align="center">
|
344
|
+
<img src="https://via.placeholder.com/600x300?text=Server+Architecture+Diagram" alt="Server Architecture" width="600" style="border-radius: 8px;"/>
|
345
|
+
</div>
|
346
|
+
|
347
|
+
### API Routes
|
348
|
+
|
349
|
+
Create API endpoints easily with file-based routing:
|
350
|
+
|
351
|
+
<div class="file-structure" style="display: flex; gap: 20px;">
|
352
|
+
|
353
|
+
<div class="code-example" style="flex: 1;">
|
354
|
+
|
355
|
+
```js
|
356
|
+
// api/users.js - Automatically mapped to /api/users
|
357
|
+
export async function get(req, res) {
|
358
|
+
const users = await req.db.collection('users').find().toArray();
|
359
|
+
res.json(users);
|
360
|
+
}
|
361
|
+
|
362
|
+
export async function post(req, res) {
|
363
|
+
const { name, email } = req.body;
|
364
|
+
|
365
|
+
if (!name || !email) {
|
366
|
+
return res.status(400).json({
|
367
|
+
error: 'Name and email are required'
|
368
|
+
});
|
369
|
+
}
|
370
|
+
|
371
|
+
const result = await req.db.collection('users').insertOne({
|
372
|
+
name,
|
373
|
+
email
|
374
|
+
});
|
375
|
+
|
376
|
+
res.status(201).json(result);
|
377
|
+
}
|
378
|
+
```
|
379
|
+
|
380
|
+
</div>
|
381
|
+
|
382
|
+
<div class="file-structure-diagram" style="background: #f8f9fa; border-radius: 8px; padding: 15px; min-width: 250px;">
|
383
|
+
<strong>File-based Routing</strong><br>
|
384
|
+
<pre style="background: #f0f0f0; padding: 10px; margin-top: 10px; border-radius: 5px;">
|
385
|
+
api/
|
386
|
+
├── users.js
|
387
|
+
│ ├── get() → GET /api/users
|
388
|
+
│ └── post() → POST /api/users
|
389
|
+
├── posts/
|
390
|
+
│ ├── index.js
|
391
|
+
│ │ └── get() → GET /api/posts
|
392
|
+
│ └── [id].js
|
393
|
+
│ └── get() → GET /api/posts/:id
|
394
|
+
└── auth/
|
395
|
+
├── login.js
|
396
|
+
│ └── post() → POST /api/auth/login
|
397
|
+
└── register.js
|
398
|
+
└── post() → POST /api/auth/register
|
399
|
+
</pre>
|
400
|
+
</div>
|
401
|
+
|
402
|
+
</div>
|
403
|
+
|
404
|
+
<details>
|
405
|
+
<summary><b>🔍 View Database Integration Examples</b></summary>
|
406
|
+
|
407
|
+
### 💾 Database Integration
|
408
|
+
|
409
|
+
Access your database directly in API routes:
|
410
|
+
|
411
|
+
<div class="tabs">
|
412
|
+
<div class="tab" id="mongodb">
|
413
|
+
|
414
|
+
#### MongoDB Example
|
415
|
+
|
416
|
+
```js
|
417
|
+
// MongoDB example
|
418
|
+
export async function get(req, res) {
|
419
|
+
const { id } = req.params;
|
420
|
+
const user = await req.db.collection('users').findOne({
|
421
|
+
_id: new ObjectId(id)
|
422
|
+
});
|
423
|
+
|
424
|
+
if (!user) {
|
425
|
+
return res.status(404).json({ error: 'User not found' });
|
426
|
+
}
|
427
|
+
|
428
|
+
res.json(user);
|
429
|
+
}
|
430
|
+
```
|
431
|
+
|
432
|
+
</div>
|
433
|
+
<div class="tab" id="mysql">
|
434
|
+
|
435
|
+
#### MySQL Example
|
436
|
+
|
437
|
+
```js
|
438
|
+
// MySQL example
|
439
|
+
export async function get(req, res) {
|
440
|
+
const [users] = await req.db.execute(
|
441
|
+
'SELECT * FROM users WHERE active = ?',
|
442
|
+
[true]
|
443
|
+
);
|
444
|
+
res.json(users);
|
445
|
+
}
|
446
|
+
```
|
447
|
+
|
448
|
+
</div>
|
449
|
+
<div class="tab" id="postgres">
|
450
|
+
|
451
|
+
#### PostgreSQL Example
|
452
|
+
|
453
|
+
```js
|
454
|
+
// PostgreSQL example
|
455
|
+
export async function get(req, res) {
|
456
|
+
const result = await req.db.query(
|
457
|
+
'SELECT * FROM users WHERE role = $1',
|
458
|
+
['admin']
|
459
|
+
);
|
460
|
+
res.json(result.rows);
|
461
|
+
}
|
462
|
+
```
|
463
|
+
|
464
|
+
</div>
|
465
|
+
</div>
|
466
|
+
|
467
|
+
</details>
|
468
|
+
|
469
|
+
<details>
|
470
|
+
<summary><b>🔍 View Authentication Example</b></summary>
|
471
|
+
|
472
|
+
### 🔐 Authentication
|
473
|
+
|
474
|
+
Built-in JWT authentication:
|
475
|
+
|
476
|
+
```js
|
477
|
+
// api/auth/login.js
|
478
|
+
export async function post(req, res) {
|
479
|
+
const { username, password } = req.body;
|
480
|
+
const user = await req.db.collection('users').findOne({ username });
|
481
|
+
|
482
|
+
if (!user || !await req.auth.comparePasswords(password, user.password)) {
|
483
|
+
return res.status(401).json({ error: 'Invalid credentials' });
|
484
|
+
}
|
485
|
+
|
486
|
+
const token = req.auth.generateToken(user);
|
487
|
+
res.json({
|
488
|
+
token,
|
489
|
+
user: { id: user._id, username: user.username }
|
490
|
+
});
|
491
|
+
}
|
492
|
+
|
493
|
+
// Protected route
|
494
|
+
// api/profile.js
|
495
|
+
export async function get(req, res) {
|
496
|
+
// req.auth.requireAuth middleware automatically added
|
497
|
+
// req.user contains the authenticated user
|
498
|
+
res.json(req.user);
|
499
|
+
}
|
500
|
+
```
|
501
|
+
|
502
|
+
</details>
|
503
|
+
|
504
|
+
<details>
|
505
|
+
<summary><b>🔍 View Middleware Example</b></summary>
|
506
|
+
|
507
|
+
### Middleware Support
|
508
|
+
|
509
|
+
Add custom middleware to your routes:
|
510
|
+
|
511
|
+
```js
|
512
|
+
// middleware/logger.js
|
513
|
+
export default function logger(req, res, next) {
|
514
|
+
console.log(`${req.method} ${req.path}`);
|
515
|
+
next();
|
516
|
+
}
|
517
|
+
|
518
|
+
// server.js
|
519
|
+
import logger from './middleware/logger';
|
520
|
+
|
521
|
+
const app = await server.createServer({
|
522
|
+
// ...other options
|
523
|
+
middleware: [logger]
|
524
|
+
});
|
525
|
+
```
|
526
|
+
|
527
|
+
</details>
|
528
|
+
|
529
|
+
## 🌐 Server-Side Rendering
|
530
|
+
|
531
|
+
Frontend Hamroun provides seamless SSR with hydration:
|
532
|
+
|
533
|
+
<div class="ssr-diagram-container" style="display: flex; gap: 20px; margin-bottom: 20px;">
|
534
|
+
|
535
|
+
<div class="code-example" style="flex: 1;">
|
536
|
+
|
537
|
+
```jsx
|
538
|
+
// server.js
|
539
|
+
import { renderToString } from 'frontend-hamroun/ssr';
|
540
|
+
import App from './App';
|
541
|
+
|
542
|
+
app.get('*', async (req, res) => {
|
543
|
+
const html = await renderToString(<App url={req.url} />);
|
544
|
+
|
545
|
+
res.send(`
|
546
|
+
<!DOCTYPE html>
|
547
|
+
<html>
|
548
|
+
<head>
|
549
|
+
<title>My SSR App</title>
|
550
|
+
<link rel="stylesheet" href="/styles.css">
|
551
|
+
</head>
|
552
|
+
<body>
|
553
|
+
<div id="root">${html}</div>
|
554
|
+
<script src="/client.js"></script>
|
555
|
+
</body>
|
556
|
+
</html>
|
557
|
+
`);
|
558
|
+
});
|
559
|
+
|
560
|
+
// client.js
|
192
561
|
import { hydrate } from 'frontend-hamroun';
|
562
|
+
import App from './App';
|
193
563
|
|
194
|
-
hydrate(<App />,
|
564
|
+
hydrate(<App url={window.location.pathname} />,
|
565
|
+
document.getElementById('root'));
|
195
566
|
```
|
196
567
|
|
197
|
-
|
568
|
+
</div>
|
569
|
+
|
570
|
+
<div class="ssr-flow-diagram" style="background: #f8f9fa; border-radius: 8px; padding: 15px; min-width: 250px;">
|
571
|
+
<strong>SSR Flow</strong><br>
|
572
|
+
<pre style="background: #f0f0f0; padding: 10px; margin-top: 10px; border-radius: 5px;">
|
573
|
+
1. HTTP Request
|
574
|
+
↓
|
575
|
+
2. Server renders React to HTML
|
576
|
+
↓
|
577
|
+
3. HTML sent to browser
|
578
|
+
↓
|
579
|
+
4. Browser displays HTML
|
580
|
+
↓
|
581
|
+
5. JavaScript loads
|
582
|
+
↓
|
583
|
+
6. Hydration attaches event
|
584
|
+
handlers to existing DOM
|
585
|
+
↓
|
586
|
+
7. App becomes interactive
|
587
|
+
</pre>
|
588
|
+
</div>
|
589
|
+
|
590
|
+
</div>
|
591
|
+
|
592
|
+
<div align="center">
|
593
|
+
<img src="https://via.placeholder.com/700x200?text=SSR+vs+CSR+Performance+Comparison" alt="SSR Performance" width="700" style="border-radius: 8px;"/>
|
594
|
+
</div>
|
595
|
+
|
596
|
+
## ⚡ Performance Optimization
|
198
597
|
|
199
598
|
### Batch Updates
|
200
|
-
Group multiple state updates together to prevent unnecessary re-renders.
|
201
599
|
|
202
|
-
|
600
|
+
Group state updates for better performance:
|
601
|
+
|
602
|
+
```jsx
|
203
603
|
import { batchUpdates } from 'frontend-hamroun';
|
204
604
|
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
});
|
605
|
+
function handleSubmit() {
|
606
|
+
batchUpdates(() => {
|
607
|
+
setSubmitting(true);
|
608
|
+
setFormData({ name: '', email: '' });
|
609
|
+
setErrors({});
|
610
|
+
setSubmitCount(c => c + 1);
|
611
|
+
});
|
612
|
+
}
|
210
613
|
```
|
211
614
|
|
212
|
-
|
615
|
+
### Virtual DOM Diffing
|
616
|
+
|
617
|
+
The framework uses an efficient diffing algorithm to minimize DOM operations:
|
618
|
+
|
619
|
+
<div class="diffing-container" style="display: flex; gap: 20px; margin-bottom: 20px;">
|
213
620
|
|
214
|
-
|
621
|
+
<div class="code-example" style="flex: 1;">
|
215
622
|
|
216
|
-
|
217
|
-
|
623
|
+
```jsx
|
624
|
+
// This only updates the changed parts of the DOM
|
625
|
+
function Counter() {
|
626
|
+
const [count, setCount] = useState(0);
|
627
|
+
return (
|
628
|
+
<div>
|
629
|
+
<h1>Counter</h1>
|
630
|
+
<p>Count: {count}</p> {/* Only this text node updates */}
|
631
|
+
<button onClick={() => setCount(count + 1)}>
|
632
|
+
Increment
|
633
|
+
</button>
|
634
|
+
</div>
|
635
|
+
);
|
636
|
+
}
|
637
|
+
```
|
218
638
|
|
219
|
-
|
639
|
+
</div>
|
220
640
|
|
221
|
-
|
641
|
+
<div class="diffing-diagram" style="background: #f8f9fa; border-radius: 8px; padding: 15px; min-width: 250px;">
|
642
|
+
<strong>Diffing Process</strong><br>
|
643
|
+
<pre style="background: #f0f0f0; padding: 10px; margin-top: 10px; border-radius: 5px;">
|
644
|
+
Old Virtual DOM
|
645
|
+
↓
|
646
|
+
New Virtual DOM
|
647
|
+
↓
|
648
|
+
Compare Trees
|
649
|
+
↓
|
650
|
+
Identify Differences
|
651
|
+
↓
|
652
|
+
Update Only Changed
|
653
|
+
DOM Elements
|
654
|
+
</pre>
|
655
|
+
</div>
|
222
656
|
|
223
|
-
|
657
|
+
</div>
|
224
658
|
|
225
|
-
|
659
|
+
<div align="center">
|
660
|
+
<img src="https://via.placeholder.com/700x200?text=Performance+Benchmark+Graph" alt="Performance Benchmark" width="700" style="border-radius: 8px;"/>
|
661
|
+
</div>
|
226
662
|
|
227
|
-
##
|
663
|
+
## 🛠️ CLI Tools
|
664
|
+
|
665
|
+
Frontend Hamroun includes powerful CLI tools for development:
|
666
|
+
|
667
|
+
<div class="cli-examples" style="background: #f8f9fa; border-radius: 8px; padding: 20px; margin-bottom: 20px;">
|
668
|
+
|
669
|
+
```bash
|
670
|
+
# Create a new project with interactive template selection
|
671
|
+
npx frontend-hamroun create my-app
|
672
|
+
|
673
|
+
# Generate a new component with customizable features
|
674
|
+
npx frontend-hamroun add:component Button
|
675
|
+
|
676
|
+
# Create a new page component
|
677
|
+
npx frontend-hamroun add:page Home
|
678
|
+
|
679
|
+
# Generate an API route
|
680
|
+
npx frontend-hamroun add:api users --methods=get,post,put,delete
|
681
|
+
|
682
|
+
# View development tools and tips
|
683
|
+
npx frontend-hamroun dev:tools
|
684
|
+
```
|
685
|
+
|
686
|
+
</div>
|
687
|
+
|
688
|
+
### 📦 Project Templates
|
689
|
+
|
690
|
+
<div class="templates-container" style="display: flex; gap: 20px; overflow-x: auto; padding-bottom: 15px; margin-bottom: 20px;">
|
691
|
+
|
692
|
+
<div class="template-card" style="background: #f0f5ff; border-radius: 8px; padding: 15px; min-width: 250px; border-left: 5px solid #4285f4;">
|
693
|
+
<h3>🚀 Basic App</h3>
|
694
|
+
<p>Client-side SPA with essential features</p>
|
695
|
+
<ul>
|
696
|
+
<li>Quick setup</li>
|
697
|
+
<li>No build step in development</li>
|
698
|
+
<li>Focused on simplicity</li>
|
699
|
+
<li>Perfect for learning</li>
|
700
|
+
</ul>
|
701
|
+
</div>
|
702
|
+
|
703
|
+
<div class="template-card" style="background: #f0fff4; border-radius: 8px; padding: 15px; min-width: 250px; border-left: 5px solid #34a853;">
|
704
|
+
<h3>🌐 SSR Template</h3>
|
705
|
+
<p>Server-side rendering with hydration</p>
|
706
|
+
<ul>
|
707
|
+
<li>SEO-friendly</li>
|
708
|
+
<li>Fast initial load</li>
|
709
|
+
<li>Express server included</li>
|
710
|
+
<li>Optimized for content sites</li>
|
711
|
+
</ul>
|
712
|
+
</div>
|
713
|
+
|
714
|
+
<div class="template-card" style="background: #fff8e1; border-radius: 8px; padding: 15px; min-width: 250px; border-left: 5px solid #fbbc04;">
|
715
|
+
<h3>⚡ Fullstack App</h3>
|
716
|
+
<p>Complete solution with API, authentication, and database</p>
|
717
|
+
<ul>
|
718
|
+
<li>API routes included</li>
|
719
|
+
<li>Database integration</li>
|
720
|
+
<li>Authentication ready</li>
|
721
|
+
<li>Production-ready setup</li>
|
722
|
+
</ul>
|
723
|
+
</div>
|
724
|
+
|
725
|
+
</div>
|
726
|
+
|
727
|
+
## 📘 TypeScript Support
|
728
|
+
|
729
|
+
Frontend Hamroun is built with TypeScript and includes full type definitions:
|
730
|
+
|
731
|
+
```tsx
|
732
|
+
import { useState } from 'frontend-hamroun';
|
733
|
+
|
734
|
+
interface UserProps {
|
735
|
+
id: number;
|
736
|
+
name: string;
|
737
|
+
email: string;
|
738
|
+
}
|
739
|
+
|
740
|
+
function UserProfile({ id, name, email }: UserProps) {
|
741
|
+
const [isEditing, setEditing] = useState(false);
|
742
|
+
|
743
|
+
return (
|
744
|
+
<div className="user-profile">
|
745
|
+
<h2>{name}</h2>
|
746
|
+
<p>{email}</p>
|
747
|
+
<button onClick={() => setEditing(!isEditing)}>
|
748
|
+
{isEditing ? 'Cancel' : 'Edit'}
|
749
|
+
</button>
|
750
|
+
</div>
|
751
|
+
);
|
752
|
+
}
|
753
|
+
```
|
228
754
|
|
229
|
-
|
755
|
+
## 🌍 Browser Compatibility
|
756
|
+
|
757
|
+
Frontend Hamroun works in all modern browsers:
|
758
|
+
|
759
|
+
<div class="browser-compatibility" style="display: flex; justify-content: space-between; margin: 20px 0;">
|
760
|
+
<div style="text-align: center; padding: 10px;">
|
761
|
+
<div style="font-size: 2em;">�Chrome</div>
|
762
|
+
<div>Latest 2 versions</div>
|
763
|
+
</div>
|
764
|
+
<div style="text-align: center; padding: 10px;">
|
765
|
+
<div style="font-size: 2em;">🦊</div>
|
766
|
+
<div>Firefox</div>
|
767
|
+
<div>Latest 2 versions</div>
|
768
|
+
</div>
|
769
|
+
<div style="text-align: center; padding: 10px;">
|
770
|
+
<div style="font-size: 2em;">🧭</div>
|
771
|
+
<div>Safari</div>
|
772
|
+
<div>Latest 2 versions</div>
|
773
|
+
</div>
|
774
|
+
<div style="text-align: center; padding: 10px;">
|
775
|
+
<div style="font-size: 2em;">🌐</div>
|
776
|
+
<div>Edge</div>
|
777
|
+
<div>Latest 2 versions</div>
|
778
|
+
</div>
|
779
|
+
<div style="text-align: center; padding: 10px;">
|
780
|
+
<div style="font-size: 2em;">🏛️</div>
|
781
|
+
<div>IE11</div>
|
782
|
+
<div>With polyfills</div>
|
783
|
+
</div>
|
784
|
+
</div>
|
785
|
+
|
786
|
+
## 👥 Contributing
|
787
|
+
|
788
|
+
Contributions are welcome! See [CONTRIBUTING.md](./docs/CONTRIBUTING.md) for details.
|
789
|
+
|
790
|
+
<div class="contribution-workflow" style="background: #f8f9fa; border-radius: 8px; padding: 20px; margin: 20px 0;">
|
791
|
+
<h3>Contribution Workflow</h3>
|
792
|
+
<ol>
|
793
|
+
<li>Fork the repository</li>
|
794
|
+
<li>Create your feature branch: <code>git checkout -b feature/amazing-feature</code></li>
|
795
|
+
<li>Commit your changes: <code>git commit -m 'Add amazing feature'</code></li>
|
796
|
+
<li>Push to the branch: <code>git push origin feature/amazing-feature</code></li>
|
797
|
+
<li>Open a Pull Request</li>
|
798
|
+
</ol>
|
799
|
+
</div>
|
800
|
+
|
801
|
+
## 📚 Documentation
|
802
|
+
|
803
|
+
For complete documentation, visit [our documentation site](https://github.com/hamroun/frontend-hamroun).
|
804
|
+
|
805
|
+
<div align="center">
|
806
|
+
|
807
|
+
<div style="margin-top: 40px;">
|
808
|
+
<h3>💖 Support the Project</h3>
|
809
|
+
|
810
|
+
[](https://github.com/sponsors/hamroun)
|
811
|
+
[](https://github.com/hamroun/frontend-hamroun)
|
812
|
+
</div>
|
813
|
+
|
814
|
+
<div style="margin-top: 30px;">
|
815
|
+
<p>MIT © Hamroun</p>
|
816
|
+
</div>
|
817
|
+
|
818
|
+
</div>
|