create-aziz-app 3.1.1 → 3.1.3
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 +658 -207
- package/bin/create-aziz-app.js +302 -351
- package/package.json +1 -1
- package/template/README.md +14 -279
- package/template/_framework/api.js +219 -219
- package/template/_framework/boot.js +33 -33
- package/template/_framework/hooks.js +367 -291
- package/template/_framework/next-response.js +128 -128
- package/template/_framework/route-match.js +145 -145
- package/template/_framework/router.js +465 -259
- package/template/_framework/runtime.js +264 -264
- package/template/app/layout.js +3 -5
- package/template/app/page.js +9 -32
- package/template/docs/01-getting-started.md +151 -151
- package/template/docs/02-project-structure.md +109 -109
- package/template/docs/03-pages-and-layouts.md +140 -140
- package/template/docs/04-routing.md +120 -120
- package/template/docs/05-hooks.md +169 -169
- package/template/docs/06-api-routes.md +210 -210
- package/template/docs/07-api-client.md +151 -151
- package/template/docs/08-styling.md +94 -94
- package/template/docs/09-imports-and-modules.md +97 -97
- package/template/docs/10-database-and-models.md +154 -154
- package/template/docs/11-authentication.md +171 -171
- package/template/docs/12-production-and-deployment.md +121 -121
- package/template/docs/13-internals.md +179 -179
- package/template/docs/README.md +67 -67
- package/template/index.html +20 -20
- package/template/package.json +16 -16
- package/template/scripts/dev-server.js +493 -381
- package/template/scripts/lib/api-router.js +525 -525
- package/template/scripts/lib/js-transform.js +213 -141
- package/template/scripts/lib/module-resolver.js +132 -132
package/package.json
CHANGED
package/template/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# ⚡ Aziz.js
|
|
2
2
|
|
|
3
|
-
A lightweight Next.js clone with file-based routing, React hooks,
|
|
3
|
+
A lightweight Next.js clone with file-based routing, React hooks, and ES module imports — **zero dependencies, instant startup**.
|
|
4
4
|
|
|
5
5
|
```
|
|
6
6
|
Next.js: ~400KB + 20 dependencies + 10s startup
|
|
@@ -12,8 +12,7 @@ Aziz.js: ~50KB + 0 dependencies + <1s startup
|
|
|
12
12
|
## Quick Start
|
|
13
13
|
|
|
14
14
|
```bash
|
|
15
|
-
|
|
16
|
-
cd my-app
|
|
15
|
+
npm install
|
|
17
16
|
npm run dev
|
|
18
17
|
```
|
|
19
18
|
|
|
@@ -28,30 +27,15 @@ my-app/
|
|
|
28
27
|
├── index.html ← entry point (don't touch)
|
|
29
28
|
│
|
|
30
29
|
├── app/ ← your pages and layouts
|
|
31
|
-
│ ├── layout.js ← root layout (
|
|
32
|
-
│
|
|
33
|
-
│ ├── about/
|
|
34
|
-
│ │ └── page.js ← route: /about
|
|
35
|
-
│ └── blog/
|
|
36
|
-
│ └── [slug]/
|
|
37
|
-
│ └── page.js ← route: /blog/:slug (dynamic)
|
|
30
|
+
│ ├── layout.js ← root layout (wraps every page)
|
|
31
|
+
│ └── page.js ← route: /
|
|
38
32
|
│
|
|
39
|
-
├──
|
|
40
|
-
│
|
|
41
|
-
│ └── hello.js ← route: /api/hello
|
|
33
|
+
├── styles/
|
|
34
|
+
│ └── globals.css ← global styles
|
|
42
35
|
│
|
|
43
|
-
├──
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
│
|
|
47
|
-
├── lib/ ← utilities, database connections
|
|
48
|
-
│ └── db.js
|
|
49
|
-
│
|
|
50
|
-
├── models/ ← data models
|
|
51
|
-
│ └── User.js
|
|
52
|
-
│
|
|
53
|
-
└── styles/
|
|
54
|
-
└── globals.css
|
|
36
|
+
├── _framework/ ← runtime, hooks, router (don't touch)
|
|
37
|
+
├── scripts/ ← dev server + live reload (don't touch)
|
|
38
|
+
└── docs/ ← full documentation
|
|
55
39
|
```
|
|
56
40
|
|
|
57
41
|
---
|
|
@@ -88,7 +72,6 @@ Just create the file — no registration needed:
|
|
|
88
72
|
|
|
89
73
|
```bash
|
|
90
74
|
mkdir app/dashboard
|
|
91
|
-
touch app/dashboard/page.js
|
|
92
75
|
```
|
|
93
76
|
|
|
94
77
|
```js
|
|
@@ -106,15 +89,10 @@ export default function Page() {
|
|
|
106
89
|
|
|
107
90
|
```js
|
|
108
91
|
// app/layout.js
|
|
109
|
-
import Navbar from '/components/Navbar.js';
|
|
110
|
-
import Footer from '/components/Footer.js';
|
|
111
|
-
|
|
112
92
|
export default function Layout({ children }) {
|
|
113
93
|
return (
|
|
114
94
|
<div>
|
|
115
|
-
<Navbar />
|
|
116
95
|
<main>{children}</main>
|
|
117
|
-
<Footer />
|
|
118
96
|
</div>
|
|
119
97
|
);
|
|
120
98
|
}
|
|
@@ -124,12 +102,9 @@ export default function Layout({ children }) {
|
|
|
124
102
|
|
|
125
103
|
```js
|
|
126
104
|
// app/dashboard/layout.js — wraps all /dashboard/* pages
|
|
127
|
-
import Sidebar from '/components/Sidebar.js';
|
|
128
|
-
|
|
129
105
|
export default function Layout({ children }) {
|
|
130
106
|
return (
|
|
131
107
|
<div style={{ display: 'flex' }}>
|
|
132
|
-
<Sidebar />
|
|
133
108
|
<div style={{ flex: 1 }}>{children}</div>
|
|
134
109
|
</div>
|
|
135
110
|
);
|
|
@@ -204,8 +179,6 @@ All hooks work exactly like React — **no imports needed**.
|
|
|
204
179
|
|
|
205
180
|
```js
|
|
206
181
|
const [count, setCount] = useState(0);
|
|
207
|
-
const [user, setUser] = useState(null);
|
|
208
|
-
const [items, setItems] = useState([]);
|
|
209
182
|
|
|
210
183
|
setCount(prev => prev + 1);
|
|
211
184
|
```
|
|
@@ -213,10 +186,6 @@ setCount(prev => prev + 1);
|
|
|
213
186
|
### useEffect
|
|
214
187
|
|
|
215
188
|
```js
|
|
216
|
-
useEffect(() => {
|
|
217
|
-
console.log('mounted');
|
|
218
|
-
}, []);
|
|
219
|
-
|
|
220
189
|
useEffect(() => {
|
|
221
190
|
document.title = `Count: ${count}`;
|
|
222
191
|
}, [count]);
|
|
@@ -260,14 +229,11 @@ const reducer = (state, action) => {
|
|
|
260
229
|
switch (action.type) {
|
|
261
230
|
case 'increment': return { count: state.count + 1 };
|
|
262
231
|
case 'decrement': return { count: state.count - 1 };
|
|
263
|
-
case 'reset': return { count: 0 };
|
|
264
232
|
default: return state;
|
|
265
233
|
}
|
|
266
234
|
};
|
|
267
235
|
|
|
268
236
|
const [state, dispatch] = useReducer(reducer, { count: 0 });
|
|
269
|
-
|
|
270
|
-
dispatch({ type: 'increment' });
|
|
271
237
|
```
|
|
272
238
|
|
|
273
239
|
### useContext
|
|
@@ -275,12 +241,10 @@ dispatch({ type: 'increment' });
|
|
|
275
241
|
```js
|
|
276
242
|
const ThemeContext = createContext('light');
|
|
277
243
|
|
|
278
|
-
// Provide value (in layout or parent)
|
|
279
244
|
<ThemeContext.Provider value="dark">
|
|
280
245
|
{children}
|
|
281
246
|
</ThemeContext.Provider>
|
|
282
247
|
|
|
283
|
-
// Consume anywhere
|
|
284
248
|
const theme = useContext(ThemeContext);
|
|
285
249
|
```
|
|
286
250
|
|
|
@@ -290,106 +254,21 @@ const theme = useContext(ThemeContext);
|
|
|
290
254
|
const [name, setName] = useLocalStorage('userName', '');
|
|
291
255
|
```
|
|
292
256
|
|
|
293
|
-
### useFetch
|
|
294
|
-
|
|
295
|
-
```js
|
|
296
|
-
const { data, loading, error } = useFetch('/api/users');
|
|
297
|
-
|
|
298
|
-
if (loading) return <p>Loading...</p>;
|
|
299
|
-
if (error) return <p>Error: {error}</p>;
|
|
300
|
-
|
|
301
|
-
return <pre>{JSON.stringify(data, null, 2)}</pre>;
|
|
302
|
-
```
|
|
303
|
-
|
|
304
|
-
---
|
|
305
|
-
|
|
306
|
-
## API Routes
|
|
307
|
-
|
|
308
|
-
API routes run on the **server** (Node.js). Every `.js` file in `api/` becomes an endpoint.
|
|
309
|
-
|
|
310
|
-
### Basic example
|
|
311
|
-
|
|
312
|
-
```js
|
|
313
|
-
// api/hello.js → GET /api/hello
|
|
314
|
-
const { NextResponse } = require('../_framework/next-response');
|
|
315
|
-
|
|
316
|
-
async function GET(request) {
|
|
317
|
-
const { searchParams } = new URL(request.url);
|
|
318
|
-
const name = searchParams.get('name') || 'World';
|
|
319
|
-
return NextResponse.json({ message: `Hello, ${name}!` });
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
module.exports = { GET };
|
|
323
|
-
```
|
|
324
|
-
|
|
325
|
-
### CRUD example
|
|
326
|
-
|
|
327
|
-
```js
|
|
328
|
-
// api/users.js → /api/users
|
|
329
|
-
const { NextResponse } = require('../_framework/next-response');
|
|
330
|
-
|
|
331
|
-
async function GET(request) {
|
|
332
|
-
const users = await User.find();
|
|
333
|
-
return NextResponse.json(users);
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
async function POST(request) {
|
|
337
|
-
const { name, email } = await request.json();
|
|
338
|
-
if (!name || !email) {
|
|
339
|
-
return NextResponse.json({ error: 'Name and email required' }, { status: 400 });
|
|
340
|
-
}
|
|
341
|
-
const user = await User.create({ name, email });
|
|
342
|
-
return NextResponse.json(user, { status: 201 });
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
async function DELETE(request) {
|
|
346
|
-
const { searchParams } = new URL(request.url);
|
|
347
|
-
await User.findByIdAndDelete(searchParams.get('id'));
|
|
348
|
-
return NextResponse.json({ message: 'Deleted' });
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
module.exports = { GET, POST, DELETE };
|
|
352
|
-
```
|
|
353
|
-
|
|
354
|
-
### NextResponse
|
|
355
|
-
|
|
356
|
-
```js
|
|
357
|
-
return NextResponse.json({ data: 'value' });
|
|
358
|
-
return NextResponse.json({ error: 'Not found' }, { status: 404 });
|
|
359
|
-
return NextResponse.redirect('/login');
|
|
360
|
-
return NextResponse.text('Hello');
|
|
361
|
-
```
|
|
362
|
-
|
|
363
257
|
---
|
|
364
258
|
|
|
365
259
|
## Imports
|
|
366
260
|
|
|
367
|
-
### Components and pages — no imports needed for JSX or hooks
|
|
368
|
-
|
|
369
|
-
```js
|
|
370
|
-
// app/dashboard/page.js
|
|
371
|
-
export default function Page() {
|
|
372
|
-
const [count, setCount] = useState(0); // hooks are global
|
|
373
|
-
return <h1>Count: {count}</h1>; // JSX works automatically
|
|
374
|
-
}
|
|
375
|
-
```
|
|
376
|
-
|
|
377
261
|
### Importing other files
|
|
378
262
|
|
|
379
263
|
```js
|
|
380
264
|
// Absolute path
|
|
381
|
-
import
|
|
382
|
-
import connectDB from '/lib/db.js';
|
|
383
|
-
import User from '/models/User.js';
|
|
265
|
+
import Button from '/components/Button.js';
|
|
384
266
|
|
|
385
267
|
// @/ alias (same as absolute)
|
|
386
|
-
import
|
|
387
|
-
import User from '@/models/User';
|
|
268
|
+
import Button from '@/components/Button';
|
|
388
269
|
|
|
389
|
-
// npm packages (install first: npm install
|
|
390
|
-
import
|
|
391
|
-
import bcrypt from 'bcryptjs';
|
|
392
|
-
import jwt from 'jsonwebtoken';
|
|
270
|
+
// npm packages (install first: npm install lodash)
|
|
271
|
+
import _ from 'lodash';
|
|
393
272
|
```
|
|
394
273
|
|
|
395
274
|
The dev server resolves bare imports from `node_modules` automatically — no bundler config needed.
|
|
@@ -442,137 +321,6 @@ import Button from '/components/Button.js';
|
|
|
442
321
|
|
|
443
322
|
---
|
|
444
323
|
|
|
445
|
-
## Database
|
|
446
|
-
|
|
447
|
-
### MongoDB with Mongoose
|
|
448
|
-
|
|
449
|
-
```bash
|
|
450
|
-
npm install mongoose
|
|
451
|
-
```
|
|
452
|
-
|
|
453
|
-
```js
|
|
454
|
-
// lib/db.js
|
|
455
|
-
import mongoose from 'mongoose';
|
|
456
|
-
|
|
457
|
-
let isConnected = false;
|
|
458
|
-
|
|
459
|
-
export default async function connectDB() {
|
|
460
|
-
if (isConnected) return;
|
|
461
|
-
await mongoose.connect(process.env.MONGODB_URI);
|
|
462
|
-
isConnected = true;
|
|
463
|
-
}
|
|
464
|
-
```
|
|
465
|
-
|
|
466
|
-
```js
|
|
467
|
-
// models/User.js
|
|
468
|
-
import mongoose from 'mongoose';
|
|
469
|
-
|
|
470
|
-
const userSchema = new mongoose.Schema({
|
|
471
|
-
name: { type: String, required: true },
|
|
472
|
-
email: { type: String, required: true, unique: true },
|
|
473
|
-
password: { type: String, required: true },
|
|
474
|
-
}, { timestamps: true });
|
|
475
|
-
|
|
476
|
-
export default mongoose.models.User || mongoose.model('User', userSchema);
|
|
477
|
-
```
|
|
478
|
-
|
|
479
|
-
### Environment variables
|
|
480
|
-
|
|
481
|
-
Create `.env` in your project root:
|
|
482
|
-
|
|
483
|
-
```bash
|
|
484
|
-
MONGODB_URI=mongodb://localhost:27017/myapp
|
|
485
|
-
JWT_SECRET=your_secret_key
|
|
486
|
-
```
|
|
487
|
-
|
|
488
|
-
> Install `dotenv` and add `require('dotenv').config()` at the top of `scripts/dev-server.js` to load `.env` automatically.
|
|
489
|
-
|
|
490
|
-
---
|
|
491
|
-
|
|
492
|
-
## Calling APIs from Pages
|
|
493
|
-
|
|
494
|
-
```js
|
|
495
|
-
// GET
|
|
496
|
-
const res = await fetch('/api/users');
|
|
497
|
-
const users = await res.json();
|
|
498
|
-
|
|
499
|
-
// POST
|
|
500
|
-
const res = await fetch('/api/users', {
|
|
501
|
-
method: 'POST',
|
|
502
|
-
headers: { 'Content-Type': 'application/json' },
|
|
503
|
-
body: JSON.stringify({ name: 'Aziz', email: 'aziz@example.com' })
|
|
504
|
-
});
|
|
505
|
-
const result = await res.json();
|
|
506
|
-
```
|
|
507
|
-
|
|
508
|
-
### Full login example
|
|
509
|
-
|
|
510
|
-
```js
|
|
511
|
-
export default function Page() {
|
|
512
|
-
const [email, setEmail] = useState('');
|
|
513
|
-
const [password, setPassword] = useState('');
|
|
514
|
-
const [error, setError] = useState('');
|
|
515
|
-
const [loading, setLoading] = useState(false);
|
|
516
|
-
|
|
517
|
-
const handleLogin = async (e) => {
|
|
518
|
-
e.preventDefault();
|
|
519
|
-
setLoading(true);
|
|
520
|
-
setError('');
|
|
521
|
-
|
|
522
|
-
try {
|
|
523
|
-
const res = await fetch('/api/loginUser', {
|
|
524
|
-
method: 'POST',
|
|
525
|
-
headers: { 'Content-Type': 'application/json' },
|
|
526
|
-
body: JSON.stringify({ email, password })
|
|
527
|
-
});
|
|
528
|
-
|
|
529
|
-
const result = await res.json();
|
|
530
|
-
|
|
531
|
-
if (!res.ok) {
|
|
532
|
-
setError(result.error);
|
|
533
|
-
return;
|
|
534
|
-
}
|
|
535
|
-
|
|
536
|
-
localStorage.setItem('user', JSON.stringify(result));
|
|
537
|
-
navigate(result.role === 'admin' ? '/admin' : '/dashboard');
|
|
538
|
-
|
|
539
|
-
} catch (err) {
|
|
540
|
-
setError('Something went wrong. Try again.');
|
|
541
|
-
} finally {
|
|
542
|
-
setLoading(false);
|
|
543
|
-
}
|
|
544
|
-
};
|
|
545
|
-
|
|
546
|
-
return (
|
|
547
|
-
<div style={{ maxWidth: '400px', margin: '80px auto', padding: '0 16px' }}>
|
|
548
|
-
<h1>Login</h1>
|
|
549
|
-
<form onSubmit={handleLogin}>
|
|
550
|
-
<input
|
|
551
|
-
type="email"
|
|
552
|
-
placeholder="Email"
|
|
553
|
-
value={email}
|
|
554
|
-
onInput={(e) => setEmail(e.target.value)}
|
|
555
|
-
required
|
|
556
|
-
/>
|
|
557
|
-
<input
|
|
558
|
-
type="password"
|
|
559
|
-
placeholder="Password"
|
|
560
|
-
value={password}
|
|
561
|
-
onInput={(e) => setPassword(e.target.value)}
|
|
562
|
-
required
|
|
563
|
-
/>
|
|
564
|
-
{error && <p style={{ color: 'red' }}>{error}</p>}
|
|
565
|
-
<button type="submit" class="btn btn-primary" disabled={loading}>
|
|
566
|
-
{loading ? 'Logging in...' : 'Login'}
|
|
567
|
-
</button>
|
|
568
|
-
</form>
|
|
569
|
-
</div>
|
|
570
|
-
);
|
|
571
|
-
}
|
|
572
|
-
```
|
|
573
|
-
|
|
574
|
-
---
|
|
575
|
-
|
|
576
324
|
## Styling
|
|
577
325
|
|
|
578
326
|
### globals.css
|
|
@@ -597,25 +345,15 @@ Edit `styles/globals.css` for global styles. Built-in utility classes:
|
|
|
597
345
|
|
|
598
346
|
### Tailwind CSS
|
|
599
347
|
|
|
600
|
-
Tailwind
|
|
348
|
+
If you scaffolded with Tailwind, it is loaded via CDN with `primary` and `dark` colors pre-configured:
|
|
601
349
|
|
|
602
350
|
```js
|
|
603
351
|
// Use Tailwind classes directly in any file
|
|
604
352
|
<div class="flex items-center gap-4 p-6 bg-white rounded-lg shadow">
|
|
605
353
|
<h1 class="text-2xl font-bold text-dark">Hello</h1>
|
|
606
|
-
<button class="bg-primary text-dark font-bold px-4 py-2 rounded-lg">
|
|
607
|
-
Click me
|
|
608
|
-
</button>
|
|
609
354
|
</div>
|
|
610
355
|
```
|
|
611
356
|
|
|
612
|
-
Custom colors available out of the box:
|
|
613
|
-
|
|
614
|
-
| Class | Value |
|
|
615
|
-
|-------|-------|
|
|
616
|
-
| `bg-primary` / `text-primary` | `#61dafb` (cyan) |
|
|
617
|
-
| `bg-dark` / `text-dark` | `#282c34` (dark) |
|
|
618
|
-
|
|
619
357
|
To extend the config, edit the `tailwind.config` block in `index.html`.
|
|
620
358
|
|
|
621
359
|
---
|
|
@@ -629,7 +367,6 @@ npm run dev
|
|
|
629
367
|
- Serves your app at `http://localhost:3000`
|
|
630
368
|
- Watches all source folders and live-reloads on save
|
|
631
369
|
- Resolves bare imports from `node_modules`
|
|
632
|
-
- Hot-reloads API routes when changed
|
|
633
370
|
|
|
634
371
|
```bash
|
|
635
372
|
# Custom port
|
|
@@ -647,8 +384,6 @@ PORT=4000 npm run dev
|
|
|
647
384
|
| `layout.js` convention | ✅ | ✅ |
|
|
648
385
|
| Dynamic routes `[slug]` | ✅ | ✅ |
|
|
649
386
|
| Catch-all `[...slug]` | ✅ | ✅ |
|
|
650
|
-
| API routes | ✅ | ✅ |
|
|
651
|
-
| `NextResponse` | ✅ | ✅ |
|
|
652
387
|
| React hooks | ✅ | ✅ |
|
|
653
388
|
| No imports needed in pages | ✅ | ❌ |
|
|
654
389
|
| ES module imports | ✅ | ✅ |
|