create-aziz-app 2.0.14 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/README.md +227 -0
  2. package/bin/create-aziz-app.js +9 -9
  3. package/package.json +10 -11
  4. package/template/README.md +862 -138
  5. package/template/_framework/boot.js +36 -0
  6. package/template/_framework/hooks.js +207 -0
  7. package/template/{modules → _framework}/next-response.js +5 -13
  8. package/template/_framework/router.js +279 -0
  9. package/template/_framework/runtime.js +86 -0
  10. package/template/api/createUser.js +1 -1
  11. package/template/api/hello.js +8 -17
  12. package/template/api/loginUser.js +1 -1
  13. package/template/api/users.js +38 -134
  14. package/template/app/about/page.js +45 -0
  15. package/template/app/layout.js +23 -0
  16. package/template/app/page.js +54 -0
  17. package/template/app/test/page.js +55 -0
  18. package/template/components/Footer.js +10 -0
  19. package/template/components/Navbar.js +30 -0
  20. package/template/index.html +24 -0
  21. package/template/package.json +5 -14
  22. package/template/scripts/dev-server.js +330 -302
  23. package/template/scripts/live-reload-client.js +0 -1
  24. package/template/.vscode/settings.json +0 -15
  25. package/template/api/getUser.js +0 -60
  26. package/template/api/getUserWithDB.js +0 -65
  27. package/template/app.config.js +0 -41
  28. package/template/app.html +0 -55
  29. package/template/components/Counter.jsx +0 -36
  30. package/template/components/Footer.jsx +0 -9
  31. package/template/components/Navbar.jsx +0 -17
  32. package/template/docs/API-GUIDE.md +0 -196
  33. package/template/docs/API-ROUTES.md +0 -538
  34. package/template/docs/AUTO-IMPORT.md +0 -99
  35. package/template/docs/AUTO-REGISTRATION.md +0 -248
  36. package/template/docs/CSS-FRAMEWORKS.md +0 -221
  37. package/template/docs/DEV-SERVER.md +0 -184
  38. package/template/docs/GETTING-STARTED.md +0 -205
  39. package/template/docs/HOW-IT-WORKS.md +0 -362
  40. package/template/docs/NEXTJS-APP-ROUTER.md +0 -536
  41. package/template/docs/NEXTJS-COMPARISON.md +0 -473
  42. package/template/docs/QUICK-START.md +0 -111
  43. package/template/docs/STYLING.md +0 -269
  44. package/template/docs/TROUBLESHOOTING.md +0 -282
  45. package/template/modules/README.md +0 -129
  46. package/template/modules/api.js +0 -44
  47. package/template/modules/auto-import.js +0 -130
  48. package/template/modules/router.js +0 -218
  49. package/template/modules/state.js +0 -248
  50. package/template/package-lock.json +0 -13
  51. package/template/pages/About.jsx +0 -48
  52. package/template/pages/ApiDemo.jsx +0 -209
  53. package/template/pages/Contact.jsx +0 -25
  54. package/template/pages/Example.jsx +0 -59
  55. package/template/pages/Home.jsx +0 -39
  56. package/template/pages/HooksDemo.jsx +0 -194
  57. package/template/pages/test.jsx +0 -72
  58. package/template/scripts/build.js +0 -81
  59. package/template/scripts/generate-imports.js +0 -88
  60. package/template/tailwind.config.js +0 -17
@@ -1,212 +1,936 @@
1
- # Aziz App - Lightweight Next.js Clone
1
+ # ⚡ Aziz.js
2
2
 
3
- A **lightweight Next.js clone** with React hooks, API routes, and file-based routing. All the benefits of Next.js, but **6x smaller** with **zero dependencies**!
3
+ A lightweight Next.js clone with file-based routing, React hooks, server-side API routes, and ES module imports — **zero dependencies, instant startup**.
4
4
 
5
5
  ```
6
- Next.js: ~400KB + 20 dependencies
7
- Aziz App: ~50KB + 0 dependencies
6
+ Next.js: ~400KB + 20 dependencies + 10s startup
7
+ Aziz.js: ~50KB + 0 dependencies + <1s startup
8
8
  ```
9
9
 
10
- ## 📁 Project Structure
10
+ ---
11
11
 
12
+ ## Quick Start
13
+
14
+ ```bash
15
+ npx create-aziz-app my-app
16
+ cd my-app
17
+ npm run dev
12
18
  ```
13
- template/
14
- ├── app.html # Main HTML file
15
- ├── app.config.js # Auto-generated config (don't edit manually)
19
+
20
+ Open [http://localhost:3000](http://localhost:3000) — that's it.
21
+
22
+ ---
23
+
24
+ ## Project Structure
25
+
26
+ ```
27
+ my-app/
28
+ ├── index.html ← entry point (don't touch)
16
29
  │
17
- ├── modules/ # Core system modules
18
- │ ├── router.js # Routing & rendering engine
19
- │ ├── state.js # State management (useState)
20
- │ ├── api.js # API route system
21
- │ └── README.md # Module documentation
30
+ ├── app/ ← your pages and layouts
31
+ │ ├── layout.js ← root layout (navbar, footer, etc.)
32
+ │ ├── page.js ← route: /
33
+ │ ├── about/
34
+ │ │ └── page.js ← route: /about
35
+ │ └── blog/
36
+ │ └── [slug]/
37
+ │ └── page.js ← route: /blog/:slug (dynamic)
22
38
  │
23
- ├── scripts/ # Build & dev tools
24
- │ ├── dev-server.js # Development server with auto-import
25
- │ ├── generate-imports.js # Import generator
26
- │ └── build.js # Build script
39
+ ├── api/ ← server-side API routes (Node.js)
40
+ │ ├── users.js ← route: /api/users
41
+ │ └── hello.js ← route: /api/hello
27
42
  │
28
- ├── docs/ # Documentation
29
- │ ├── API-GUIDE.md # API routes guide
30
- │ ├── AUTO-IMPORT.md # Auto-import system docs
31
- │ ├── GETTING-STARTED.md # Getting started guide
32
- │ └── QUICK-START.md # Quick start guide
43
+ ├── components/ ← shared UI components
44
+ │ ├── Navbar.js
45
+ │ └── Footer.js
33
46
  │
34
- ├── api/ # API route handlers
35
- │ ├── hello.js # Example: /api/hello
36
- │ └── users.js # Example: /api/users
47
+ ├── lib/ ← utilities, database connections
48
+ │ └── db.js
37
49
  │
38
- ├── components/ # Reusable UI components
39
- │ ├── Navbar.jsx
40
- │ ├── Footer.jsx
41
- │ └── Counter.jsx
50
+ ├── models/ ← data models
51
+ │ └── User.js
42
52
  │
43
- └── pages/ # Page components (routes)
44
- ├── Home.jsx # Route: #/home
45
- ├── About.jsx # Route: #/about
46
- ├── Contact.jsx # Route: #/contact
47
- ├── test.jsx # Route: #/test
48
- └── ApiDemo.jsx # Route: #/api-demo
53
+ └── styles/
54
+ └── globals.css
49
55
  ```
50
56
 
51
- ## 🚀 Quick Start
57
+ ---
52
58
 
53
- ### 1. Start the Dev Server
59
+ ## Pages
54
60
 
55
- ```bash
56
- npm run dev
61
+ Every `page.js` inside `app/` becomes a route. Export a default function called `Page`.
62
+
63
+ ```js
64
+ // app/about/page.js → route: /about
65
+ /** @jsx h */
66
+ import { h } from '/_framework/runtime.js';
67
+
68
+ export default function Page() {
69
+ return (
70
+ <div>
71
+ <h1>About</h1>
72
+ <p>Hello from the about page!</p>
73
+ </div>
74
+ );
75
+ }
57
76
  ```
58
77
 
59
- This will:
60
- - Start HTTP server on `http://localhost:3000/`
61
- - Watch for file changes in `api/`, `components/`, and `pages/`
62
- - Auto-generate imports when you create new files
63
- - Auto-reload on changes
78
+ ### Route mapping
64
79
 
65
- ### 2. Open Your Browser
80
+ | File | Route |
81
+ |------|-------|
82
+ | `app/page.js` | `/` |
83
+ | `app/about/page.js` | `/about` |
84
+ | `app/blog/page.js` | `/blog` |
85
+ | `app/blog/[slug]/page.js` | `/blog/:slug` |
86
+ | `app/blog/[...slug]/page.js` | `/blog/*` (catch-all) |
66
87
 
88
+ ### Creating a new page
89
+
90
+ Just create the file — no registration, no imports to add:
91
+
92
+ ```bash
93
+ # Creates route /dashboard
94
+ mkdir app/dashboard
95
+ touch app/dashboard/page.js
67
96
  ```
68
- http://localhost:3000/
97
+
98
+ ```js
99
+ // app/dashboard/page.js
100
+ /** @jsx h */
101
+ import { h } from '/_framework/runtime.js';
102
+
103
+ export default function Page() {
104
+ return <h1>Dashboard</h1>;
105
+ }
69
106
  ```
70
107
 
71
- ### 3. Create New Files
108
+ ---
109
+
110
+ ## Layouts
111
+
112
+ `layout.js` wraps all pages at the same level and below. The root `app/layout.js` wraps every page in your app.
113
+
114
+ ```js
115
+ // app/layout.js
116
+ /** @jsx h */
117
+ import { h } from '/_framework/runtime.js';
118
+ import Navbar from '/components/Navbar.js';
119
+ import Footer from '/components/Footer.js';
120
+
121
+ export default function Layout({ children }) {
122
+ return (
123
+ <div>
124
+ <Navbar />
125
+ <main>{children}</main>
126
+ <Footer />
127
+ </div>
128
+ );
129
+ }
130
+ ```
72
131
 
73
- Just create files in the appropriate folders - they're automatically imported!
132
+ ### Nested layouts
74
133
 
75
- **Create a new page:**
76
- ```javascript
77
- // pages/Profile.jsx
134
+ ```js
135
+ // app/dashboard/layout.js — wraps all /dashboard/* pages
78
136
  /** @jsx h */
137
+ import { h } from '/_framework/runtime.js';
138
+ import Sidebar from '/components/Sidebar.js';
139
+
140
+ export default function Layout({ children }) {
141
+ return (
142
+ <div style={{ display: 'flex' }}>
143
+ <Sidebar />
144
+ <div style={{ flex: 1 }}>{children}</div>
145
+ </div>
146
+ );
147
+ }
148
+ ```
149
+
150
+ ---
151
+
152
+ ## Navigation
153
+
154
+ ### navigate()
155
+
156
+ ```js
157
+ import { navigate } from '/_framework/router.js';
158
+
159
+ navigate('/about');
160
+ navigate('/blog/my-post');
161
+ navigate('/');
162
+ ```
163
+
164
+ ### Link component
165
+
166
+ ```js
167
+ import { Link } from '/_framework/router.js';
168
+
169
+ <Link href="/about">About</Link>
170
+ <Link href="/blog/hello" className="nav-link">Blog Post</Link>
171
+ ```
172
+
173
+ ### useRouter hook
174
+
175
+ ```js
176
+ import { useRouter } from '/_framework/router.js';
177
+
178
+ export default function Page() {
179
+ const router = useRouter();
79
180
 
80
- // Auto-registers as "#/profile" - no registerPage() needed!
81
- function ProfilePage() {
82
- const [name, setName] = useState('');
83
-
84
181
  return (
85
182
  <div>
86
- <h1>Profile</h1>
87
- <input
88
- value={name}
89
- onInput={(e) => setName(e.target.value)}
90
- placeholder="Your name"
91
- />
92
- <p>Hello, {name}!</p>
183
+ <p>Current path: {router.pathname}</p>
184
+ <button onClick={() => router.push('/about')}>Go to About</button>
185
+ <button onClick={() => router.back()}>Back</button>
93
186
  </div>
94
187
  );
95
188
  }
96
189
  ```
97
190
 
98
- **Navigate to:** `http://localhost:3000/#/profile`
191
+ ### useParams — dynamic routes
192
+
193
+ ```js
194
+ // app/blog/[slug]/page.js
195
+ import { useParams } from '/_framework/router.js';
196
+
197
+ export default function Page() {
198
+ const { slug } = useParams();
199
+ return <h1>Post: {slug}</h1>;
200
+ }
201
+ ```
202
+
203
+ ### useSearchParams — query strings
204
+
205
+ ```js
206
+ // URL: /search?q=hello&page=2
207
+ import { useSearchParams } from '/_framework/router.js';
208
+
209
+ export default function Page() {
210
+ const searchParams = useSearchParams();
211
+ const query = searchParams.get('q'); // "hello"
212
+ const page = searchParams.get('page'); // "2"
213
+
214
+ return <p>Searching for: {query}</p>;
215
+ }
216
+ ```
217
+
218
+ ---
99
219
 
100
- ✨ **That's it!** No `registerPage()` call needed. Just name your function `YourNamePage()` and it auto-registers!
220
+ ## React Hooks
101
221
 
102
- ## ✨ Features
222
+ All hooks work exactly like React — no imports needed in pages.
103
223
 
104
- ### React Hooks (Identical to Next.js!)
105
- ```javascript
224
+ ### useState
225
+
226
+ ```js
106
227
  const [count, setCount] = useState(0);
107
- const [name, setName] = useState('');
228
+ const [user, setUser] = useState(null);
229
+ const [items, setItems] = useState([]);
108
230
 
231
+ // Functional update
232
+ setCount(prev => prev + 1);
233
+ ```
234
+
235
+ ### useEffect
236
+
237
+ ```js
238
+ // Run on mount
109
239
  useEffect(() => {
110
- console.log('Mounted!');
240
+ console.log('mounted');
111
241
  }, []);
112
242
 
113
- const memoized = useMemo(() => expensive(), [dep]);
114
- const callback = useCallback(() => action(), [dep]);
115
- const ref = useRef(null);
116
- const [state, dispatch] = useReducer(reducer, initial);
243
+ // Run when value changes
244
+ useEffect(() => {
245
+ document.title = `Count: ${count}`;
246
+ }, [count]);
247
+
248
+ // Cleanup
249
+ useEffect(() => {
250
+ const timer = setInterval(() => tick(), 1000);
251
+ return () => clearInterval(timer);
252
+ }, []);
253
+ ```
254
+
255
+ ### useMemo
256
+
257
+ ```js
258
+ const expensiveResult = useMemo(() => {
259
+ return items.filter(i => i.active).length;
260
+ }, [items]);
261
+ ```
262
+
263
+ ### useCallback
264
+
265
+ ```js
266
+ const handleClick = useCallback(() => {
267
+ doSomething(id);
268
+ }, [id]);
269
+ ```
270
+
271
+ ### useRef
272
+
273
+ ```js
274
+ const inputRef = useRef(null);
275
+
276
+ // In JSX
277
+ <input ref={inputRef} type="text" />
278
+
279
+ // Access DOM element
280
+ inputRef.current.focus();
117
281
  ```
118
282
 
119
- **All hooks work exactly like React/Next.js!**
283
+ ### useReducer
120
284
 
121
- ### API Routes
122
- ```javascript
123
- // api/todos.js - Runs on SERVER (Node.js)!
124
- module.exports = async function handler(req, res) {
125
- if (req.method === 'GET') {
126
- return res.status(200).json({ todos: [] });
285
+ ```js
286
+ const reducer = (state, action) => {
287
+ switch (action.type) {
288
+ case 'increment': return { count: state.count + 1 };
289
+ case 'decrement': return { count: state.count - 1 };
290
+ case 'reset': return { count: 0 };
291
+ default: return state;
127
292
  }
128
293
  };
129
294
 
130
- // Use in components
131
- const response = await fetchApi('/api/todos');
132
- const data = await response.json();
295
+ const [state, dispatch] = useReducer(reducer, { count: 0 });
296
+
297
+ dispatch({ type: 'increment' });
298
+ dispatch({ type: 'reset' });
299
+ ```
300
+
301
+ ### useContext
302
+
303
+ ```js
304
+ // Create context
305
+ const ThemeContext = createContext('light');
306
+
307
+ // Provide value (in layout or parent)
308
+ <ThemeContext.Provider value="dark">
309
+ {children}
310
+ </ThemeContext.Provider>
311
+
312
+ // Consume in any child
313
+ const theme = useContext(ThemeContext);
314
+ ```
315
+
316
+ ### useLocalStorage
317
+
318
+ ```js
319
+ // Persists across page refreshes
320
+ const [name, setName] = useLocalStorage('userName', '');
321
+ ```
322
+
323
+ ### useFetch
324
+
325
+ ```js
326
+ const { data, loading, error } = useFetch('/api/users');
327
+
328
+ if (loading) return <p>Loading...</p>;
329
+ if (error) return <p>Error: {error}</p>;
330
+
331
+ return <pre>{JSON.stringify(data, null, 2)}</pre>;
332
+ ```
333
+
334
+ ---
335
+
336
+ ## API Routes
337
+
338
+ API routes run on the **server** (Node.js). Every `.js` file in `api/` becomes an endpoint.
339
+
340
+ ### Basic example
341
+
342
+ ```js
343
+ // api/hello.js → GET /api/hello
344
+ const { NextResponse } = require('../modules/next-response');
345
+
346
+ async function GET(request) {
347
+ const { searchParams } = new URL(request.url);
348
+ const name = searchParams.get('name') || 'World';
349
+
350
+ return NextResponse.json({ message: `Hello, ${name}!` });
351
+ }
352
+
353
+ module.exports = { GET };
354
+ ```
355
+
356
+ ### CRUD example
357
+
358
+ ```js
359
+ // api/users.js → /api/users
360
+ const { NextResponse } = require('../modules/next-response');
361
+
362
+ async function GET(request) {
363
+ const { searchParams } = new URL(request.url);
364
+ const id = searchParams.get('id');
365
+
366
+ if (id) {
367
+ const user = await User.findById(id);
368
+ if (!user) return NextResponse.json({ error: 'Not found' }, { status: 404 });
369
+ return NextResponse.json(user);
370
+ }
371
+
372
+ const users = await User.find();
373
+ return NextResponse.json(users);
374
+ }
375
+
376
+ async function POST(request) {
377
+ const body = await request.json();
378
+ const { name, email } = body;
379
+
380
+ if (!name || !email) {
381
+ return NextResponse.json({ error: 'Name and email required' }, { status: 400 });
382
+ }
383
+
384
+ const user = await User.create({ name, email });
385
+ return NextResponse.json(user, { status: 201 });
386
+ }
387
+
388
+ async function DELETE(request) {
389
+ const { searchParams } = new URL(request.url);
390
+ const id = searchParams.get('id');
391
+
392
+ await User.findByIdAndDelete(id);
393
+ return NextResponse.json({ message: 'Deleted' });
394
+ }
395
+
396
+ module.exports = { GET, POST, DELETE };
397
+ ```
398
+
399
+ ### Request object
400
+
401
+ ```js
402
+ async function POST(request) {
403
+ // Parse body
404
+ const body = await request.json();
405
+
406
+ // Query params
407
+ const { searchParams } = new URL(request.url);
408
+ const page = searchParams.get('page');
409
+
410
+ // Headers
411
+ const token = request.headers.authorization;
412
+
413
+ // Method
414
+ console.log(request.method); // "POST"
415
+ }
416
+ ```
417
+
418
+ ### NextResponse
419
+
420
+ ```js
421
+ // JSON response
422
+ return NextResponse.json({ data: 'value' });
423
+
424
+ // With status code
425
+ return NextResponse.json({ error: 'Not found' }, { status: 404 });
426
+
427
+ // With custom headers
428
+ return NextResponse.json(data, {
429
+ status: 200,
430
+ headers: { 'X-Custom': 'value' }
431
+ });
432
+
433
+ // Redirect
434
+ return NextResponse.redirect('/login');
435
+
436
+ // Plain text
437
+ return NextResponse.text('Hello');
438
+ ```
439
+
440
+ ### HTTP status codes
441
+
442
+ | Code | Meaning |
443
+ |------|---------|
444
+ | `200` | OK |
445
+ | `201` | Created |
446
+ | `400` | Bad Request |
447
+ | `401` | Unauthorized |
448
+ | `403` | Forbidden |
449
+ | `404` | Not Found |
450
+ | `409` | Conflict |
451
+ | `500` | Server Error |
452
+
453
+ ---
454
+
455
+ ## Imports
456
+
457
+ Use ES module `import` statements anywhere. The dev server resolves everything automatically.
458
+
459
+ ### Framework imports
460
+
461
+ ```js
462
+ import { h } from '/_framework/runtime.js';
463
+ import { navigate, Link, useRouter } from '/_framework/router.js';
464
+ ```
465
+
466
+ ### Absolute path imports
467
+
468
+ ```js
469
+ import Navbar from '/components/Navbar.js';
470
+ import connectDB from '/lib/db.js';
471
+ import User from '/models/User.js';
472
+ ```
473
+
474
+ ### @/ alias (same as absolute)
475
+
476
+ ```js
477
+ import connectDB from '@/lib/db';
478
+ import User from '@/models/User';
479
+ import Button from '@/components/Button';
480
+ ```
481
+
482
+ ### npm packages (bare imports)
483
+
484
+ ```js
485
+ // Install first: npm install mongoose
486
+ import mongoose from 'mongoose';
487
+
488
+ // Install first: npm install bcryptjs
489
+ import bcrypt from 'bcryptjs';
490
+
491
+ // Install first: npm install jsonwebtoken
492
+ import jwt from 'jsonwebtoken';
493
+ ```
494
+
495
+ The dev server resolves bare imports from `node_modules` automatically — no bundler config needed.
496
+
497
+ ---
498
+
499
+ ## Components
500
+
501
+ Components are just functions that return JSX. Always add `/** @jsx h */` at the top.
502
+
503
+ ```js
504
+ // components/Button.js
505
+ /** @jsx h */
506
+ import { h } from '/_framework/runtime.js';
507
+
508
+ export default function Button({ onClick, children, variant = 'primary' }) {
509
+ return (
510
+ <button
511
+ class={`btn btn-${variant}`}
512
+ onClick={onClick}
513
+ >
514
+ {children}
515
+ </button>
516
+ );
517
+ }
518
+ ```
519
+
520
+ ```js
521
+ // Using the component
522
+ import Button from '/components/Button.js';
523
+
524
+ <Button onClick={() => alert('hi')} variant="danger">
525
+ Delete
526
+ </Button>
527
+ ```
528
+
529
+ ### Props
530
+
531
+ ```js
532
+ // Strings
533
+ <Component title="Hello" />
534
+
535
+ // Numbers
536
+ <Component count={42} />
537
+
538
+ // Booleans
539
+ <Component disabled={true} />
540
+ <Component disabled />
541
+
542
+ // Objects / arrays
543
+ <Component style={{ color: 'red' }} />
544
+ <Component items={[1, 2, 3]} />
545
+
546
+ // Functions
547
+ <Component onClick={() => doSomething()} />
548
+
549
+ // Children
550
+ <Component>
551
+ <p>Child content</p>
552
+ </Component>
133
553
  ```
134
554
 
135
- ### CSS Frameworks
136
- Choose your preferred styling:
137
- - **Custom CSS** - Built-in responsive styles
138
- - **Bootstrap 5** - Popular component framework
139
- - **Tailwind CSS** - Utility-first framework
555
+ ### JSX rules
556
+
557
+ ```js
558
+ // Use class instead of className
559
+ <div class="container">
140
560
 
141
- The CLI will automatically set up your chosen framework!
561
+ // Use onInput for text inputs (not onChange)
562
+ <input onInput={(e) => setValue(e.target.value)} />
142
563
 
143
- ### Auto-Import
144
- - Create files in `pages/`, `components/`, or `api/`
145
- - Dev server automatically detects them
146
- - Refresh browser to see changes
564
+ // Self-closing tags need /
565
+ <input type="text" />
566
+ <br />
147
567
 
148
- ## 📚 Documentation
568
+ // Expressions in {}
569
+ <p>{count > 0 ? 'positive' : 'zero'}</p>
149
570
 
150
- - **[Next.js Comparison](docs/NEXTJS-COMPARISON.md)** - How it compares to Next.js
151
- - **[Getting Started](docs/GETTING-STARTED.md)** - Complete setup guide
152
- - **[Auto-Registration](docs/AUTO-REGISTRATION.md)** - How pages auto-register
153
- - **[API Routes](docs/API-ROUTES.md)** - Server-side API endpoints (like Next.js!)
154
- - **[Auto-Import](docs/AUTO-IMPORT.md)** - Auto-import system details
155
- - **[Dev Server](docs/DEV-SERVER.md)** - Live reload and development
156
- - **[How It Works](docs/HOW-IT-WORKS.md)** - System architecture
157
- - **[Troubleshooting](docs/TROUBLESHOOTING.md)** - Fix common issues
571
+ // Lists
572
+ {items.map(item => <li key={item.id}>{item.name}</li>)}
573
+
574
+ // Conditional rendering
575
+ {isLoggedIn && <Dashboard />}
576
+ {error ? <Error msg={error} /> : <Content />}
577
+ ```
158
578
 
159
- ## 🛠️ Commands
579
+ ---
580
+
581
+ ## Database
582
+
583
+ ### MongoDB with Mongoose
160
584
 
161
585
  ```bash
162
- npm run dev # Start dev server with auto-import
163
- npm run build # Generate imports manually
586
+ npm install mongoose
587
+ ```
588
+
589
+ ```js
590
+ // lib/db.js
591
+ import mongoose from 'mongoose';
592
+
593
+ let isConnected = false;
594
+
595
+ export default async function connectDB() {
596
+ if (isConnected) return;
597
+ await mongoose.connect(process.env.MONGODB_URI);
598
+ isConnected = true;
599
+ console.log('✅ MongoDB connected');
600
+ }
164
601
  ```
165
602
 
166
- ## 🎯 Key Concepts
603
+ ```js
604
+ // models/User.js
605
+ import mongoose from 'mongoose';
167
606
 
168
- ### Pages
169
- - Files in `pages/` become routes
170
- - Name functions with "Page" suffix (e.g., `AboutPage`)
171
- - Auto-registers as route (e.g., `#/about`)
172
- - Optional: Use `registerPage("custom-name", Component)` for custom routes
607
+ const userSchema = new mongoose.Schema({
608
+ name: { type: String, required: true },
609
+ email: { type: String, required: true, unique: true },
610
+ password: { type: String, required: true },
611
+ role: { type: String, enum: ['user', 'admin'], default: 'user' }
612
+ }, { timestamps: true });
173
613
 
174
- ### Components
175
- - Reusable UI components
176
- - Use JSX syntax with `/** @jsx h */`
177
- - Import automatically
614
+ export default mongoose.models.User || mongoose.model('User', userSchema);
615
+ ```
178
616
 
179
- ### API Routes
180
- - Files in `api/` become API endpoints
181
- - Use `registerApiRoute("path", handler)`
182
- - Access via `fetchApi('/api/path')`
617
+ ```js
618
+ // api/users.js
619
+ const { NextResponse } = require('../modules/next-response');
620
+ const connectDB = require('../lib/db');
621
+ const User = require('../models/User');
183
622
 
184
- ### State
185
- - Use `useState(initialValue)` like React
186
- - Returns `[value, setValue]`
187
- - Triggers re-render on change
623
+ async function GET(request) {
624
+ await connectDB();
188
625
 
189
- ## 🔥 Hot Tips
626
+ const { searchParams } = new URL(request.url);
627
+ const email = searchParams.get('email');
190
628
 
191
- 1. **Dev server must be running** for auto-import to work
192
- 2. **Refresh browser** after creating new files
193
- 3. **Use `/** @jsx h */`** at the top of JSX files
194
- 4. **Route names are case-sensitive** - `#/home` not `#/Home`
629
+ if (email) {
630
+ const user = await User.findOne({ email }).select('-password');
631
+ if (!user) return NextResponse.json({ error: 'User not found' }, { status: 404 });
632
+ return NextResponse.json(user);
633
+ }
195
634
 
196
- ## 📦 What's in Each Folder
635
+ const users = await User.find().select('-password');
636
+ return NextResponse.json(users);
637
+ }
638
+
639
+ module.exports = { GET };
640
+ ```
197
641
 
198
- - **`modules/`** - Core framework code (don't modify unless extending)
199
- - **`scripts/`** - Build tools (don't modify)
200
- - **`docs/`** - Documentation (read these!)
201
- - **`api/`** - Your API routes (add your endpoints here)
202
- - **`components/`** - Your components (add reusable UI here)
203
- - **`pages/`** - Your pages (add new pages here)
642
+ ### Environment variables
204
643
 
205
- ## 🎉 You're Ready!
644
+ Create a `.env` file in your project root:
645
+
646
+ ```bash
647
+ MONGODB_URI=mongodb://localhost:27017/myapp
648
+ JWT_SECRET=your_secret_key
649
+ API_KEY=your_api_key
650
+ ```
651
+
652
+ Access in API routes:
653
+
654
+ ```js
655
+ const uri = process.env.MONGODB_URI;
656
+ const secret = process.env.JWT_SECRET;
657
+ ```
658
+
659
+ > **Note:** `.env` files are not loaded automatically. Install `dotenv` and add `require('dotenv').config()` at the top of `scripts/dev-server.js`, or set variables in your terminal before running `npm run dev`.
660
+
661
+ ---
662
+
663
+ ## Calling APIs from Pages
664
+
665
+ ```js
666
+ // Simple fetch
667
+ const response = await fetch('/api/users');
668
+ const users = await response.json();
669
+
670
+ // POST request
671
+ const response = await fetch('/api/users', {
672
+ method: 'POST',
673
+ headers: { 'Content-Type': 'application/json' },
674
+ body: JSON.stringify({ name: 'Aziz', email: 'aziz@example.com' })
675
+ });
676
+ const result = await response.json();
677
+
678
+ // With error handling
679
+ async function createUser(data) {
680
+ try {
681
+ const res = await fetch('/api/createUser', {
682
+ method: 'POST',
683
+ headers: { 'Content-Type': 'application/json' },
684
+ body: JSON.stringify(data)
685
+ });
686
+
687
+ const result = await res.json();
688
+
689
+ if (!res.ok) {
690
+ throw new Error(result.error || 'Request failed');
691
+ }
692
+
693
+ return result;
694
+ } catch (err) {
695
+ console.error(err);
696
+ throw err;
697
+ }
698
+ }
699
+ ```
700
+
701
+ ### Full login example
702
+
703
+ ```js
704
+ export default function Page() {
705
+ const [email, setEmail] = useState('');
706
+ const [password, setPassword] = useState('');
707
+ const [error, setError] = useState('');
708
+ const [loading, setLoading] = useState(false);
709
+
710
+ const handleLogin = async (e) => {
711
+ e.preventDefault();
712
+ setLoading(true);
713
+ setError('');
714
+
715
+ try {
716
+ const res = await fetch('/api/loginUser', {
717
+ method: 'POST',
718
+ headers: { 'Content-Type': 'application/json' },
719
+ body: JSON.stringify({ email, password })
720
+ });
721
+
722
+ const result = await res.json();
723
+
724
+ if (!res.ok) {
725
+ setError(result.error);
726
+ return;
727
+ }
728
+
729
+ localStorage.setItem('user', JSON.stringify(result));
730
+ navigate(result.role === 'admin' ? '/admin' : '/dashboard');
731
+
732
+ } catch (err) {
733
+ setError('Something went wrong. Try again.');
734
+ } finally {
735
+ setLoading(false);
736
+ }
737
+ };
738
+
739
+ return (
740
+ <div style={{ maxWidth: '400px', margin: '80px auto', padding: '0 16px' }}>
741
+ <h1>Login</h1>
742
+ <form onSubmit={handleLogin}>
743
+ <input
744
+ type="email"
745
+ value={email}
746
+ onInput={(e) => setEmail(e.target.value)}
747
+ placeholder="Email"
748
+ required
749
+ />
750
+ <input
751
+ type="password"
752
+ value={password}
753
+ onInput={(e) => setPassword(e.target.value)}
754
+ placeholder="Password"
755
+ required
756
+ />
757
+ {error && <p style={{ color: 'red' }}>{error}</p>}
758
+ <button type="submit" class="btn btn-primary" disabled={loading}>
759
+ {loading ? 'Logging in...' : 'Login'}
760
+ </button>
761
+ </form>
762
+ </div>
763
+ );
764
+ }
765
+ ```
766
+
767
+ ---
768
+
769
+ ## Styling
770
+
771
+ ### globals.css
772
+
773
+ Edit `styles/globals.css` for your global styles. Built-in utility classes:
774
+
775
+ ```css
776
+ /* Cards */
777
+ .card { background: white; border-radius: 10px; padding: 24px; box-shadow: 0 2px 8px rgba(0,0,0,0.08); margin-bottom: 20px; }
778
+
779
+ /* Buttons */
780
+ .btn { display: inline-block; padding: 10px 22px; border: none; border-radius: 8px; cursor: pointer; }
781
+ .btn-primary { background: #61dafb; color: #282c34; font-weight: bold; }
782
+ .btn-danger { background: #ff6b6b; color: white; }
783
+ .btn-grey { background: #ccc; color: #333; }
784
+
785
+ /* Counter */
786
+ .count-display { font-size: 64px; font-weight: bold; text-align: center; }
787
+ .counter-actions { display: flex; gap: 12px; justify-content: center; }
788
+ ```
789
+
790
+ ### Inline styles
791
+
792
+ ```js
793
+ <div style={{ padding: '20px', color: 'red', fontSize: '16px' }}>
794
+ Hello
795
+ </div>
796
+ ```
797
+
798
+ ### Tailwind CSS
799
+
800
+ When creating your app, choose Tailwind CSS in the setup wizard:
801
+
802
+ ```bash
803
+ npx create-aziz-app my-app
804
+ # Choose: Tailwind CSS
805
+ ```
806
+
807
+ Or add it manually to `index.html`:
808
+
809
+ ```html
810
+ <script src="https://cdn.tailwindcss.com"></script>
811
+ ```
812
+
813
+ Then use Tailwind classes directly:
814
+
815
+ ```js
816
+ <div class="flex items-center gap-4 p-6 bg-white rounded-lg shadow">
817
+ <h1 class="text-2xl font-bold text-gray-800">Hello</h1>
818
+ </div>
819
+ ```
820
+
821
+ ---
822
+
823
+ ## Dev Server
206
824
 
207
- Start the dev server and start building:
208
825
  ```bash
209
826
  npm run dev
210
827
  ```
211
828
 
212
- Then open `http://localhost:3000/` and start creating!
829
+ The dev server:
830
+ - Serves your app at `http://localhost:3000`
831
+ - Watches `app/`, `api/`, `components/`, `lib/`, `models/`, `styles/` for changes
832
+ - Reloads the browser automatically on save (WebSocket live reload)
833
+ - Resolves bare imports from `node_modules`
834
+ - Loads API routes from `api/`
835
+ - Hot-reloads API routes when changed
836
+
837
+ ### Custom port
838
+
839
+ ```bash
840
+ PORT=4000 npm run dev
841
+ ```
842
+
843
+ Or set it during project creation:
844
+
845
+ ```bash
846
+ npx create-aziz-app my-app
847
+ # Enter port: 4000
848
+ ```
849
+
850
+ ### Live reload indicator
851
+
852
+ A small indicator appears in the bottom-right corner:
853
+
854
+ - 🟢 **Live Reload** — connected, watching for changes
855
+ - 🔵 **Reloading...** — change detected, refreshing
856
+ - 🟠 **Disconnected** — reconnecting...
857
+
858
+ Click it to manually reload.
859
+
860
+ ---
861
+
862
+ ## Comparison with Next.js
863
+
864
+ | Feature | Aziz.js | Next.js |
865
+ |---------|---------|---------|
866
+ | File-based routing | ✅ | ✅ |
867
+ | `page.js` convention | ✅ | ✅ |
868
+ | `layout.js` convention | ✅ | ✅ |
869
+ | Dynamic routes `[slug]` | ✅ | ✅ |
870
+ | Catch-all `[...slug]` | ✅ | ✅ |
871
+ | API routes | ✅ | ✅ |
872
+ | `NextResponse` | ✅ | ✅ |
873
+ | Named HTTP exports | ✅ | ✅ |
874
+ | React hooks | ✅ | ✅ |
875
+ | ES module imports | ✅ | ✅ |
876
+ | `@/` path alias | ✅ | ✅ |
877
+ | Live reload | ✅ | ✅ |
878
+ | SSR / SSG | ❌ | ✅ |
879
+ | Image optimization | ❌ | ✅ |
880
+ | TypeScript | ❌ | ✅ |
881
+ | Bundle size | **~50KB** | ~400KB+ |
882
+ | Dependencies | **0** | 20+ |
883
+ | Startup time | **< 1s** | 10–30s |
884
+
885
+ ---
886
+
887
+ ## FAQ
888
+
889
+ **Do I need to register pages manually?**
890
+ No. Just create `app/your-route/page.js` and it becomes a route automatically.
891
+
892
+ **Can I use npm packages?**
893
+ Yes. Run `npm install package-name` and import it normally:
894
+ ```js
895
+ import mongoose from 'mongoose';
896
+ ```
897
+
898
+ **Where do I put shared utilities?**
899
+ In `lib/`:
900
+ ```js
901
+ // lib/utils.js
902
+ export function formatDate(date) {
903
+ return new Date(date).toLocaleDateString();
904
+ }
905
+ ```
906
+
907
+ **How do I share state between pages?**
908
+ Use `useLocalStorage` for persistence, or create a context:
909
+ ```js
910
+ const AuthContext = createContext(null);
911
+ ```
912
+
913
+ **Can I use this in production?**
914
+ Aziz.js is designed for development and learning. For production apps with SEO requirements, consider Next.js. For simple SPAs and internal tools, Aziz.js works great.
915
+
916
+ **How do I add authentication?**
917
+ ```js
918
+ // api/login.js
919
+ const { NextResponse } = require('../modules/next-response');
920
+ const jwt = require('jsonwebtoken'); // npm install jsonwebtoken
921
+
922
+ async function POST(request) {
923
+ const { email, password } = await request.json();
924
+ // verify credentials...
925
+ const token = jwt.sign({ userId: user._id }, process.env.JWT_SECRET);
926
+ return NextResponse.json({ token });
927
+ }
928
+
929
+ module.exports = { POST };
930
+ ```
931
+
932
+ ---
933
+
934
+ ## License
935
+
936
+ MIT