create-aziz-app 3.0.10 → 3.0.11

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 CHANGED
@@ -22,7 +22,7 @@ Aziz.js gives you the Next.js developer experience without the weight:
22
22
  | API routes | ✅ | ✅ |
23
23
  | `NextResponse` | ✅ | ✅ |
24
24
  | React hooks | ✅ | ✅ |
25
- | ES module imports | ✅ | ✅ |
25
+ | No imports needed in pages | ✅ | ❌ |
26
26
  | `@/` alias | ✅ | ✅ |
27
27
  | Live reload | ✅ | ✅ |
28
28
  | SSR / SSG | ❌ | ✅ |
@@ -50,7 +50,7 @@ The CLI will ask you:
50
50
 
51
51
  ```
52
52
  my-app/
53
- ├── index.html ← entry point
53
+ ├── index.html
54
54
  ├── app/
55
55
  │ ├── layout.js ← root layout
56
56
  │ ├── page.js ← route: /
@@ -76,11 +76,10 @@ my-app/
76
76
 
77
77
  ## Pages
78
78
 
79
+ No imports needed — JSX and all hooks just work.
80
+
79
81
  ```js
80
82
  // app/about/page.js → /about
81
- /** @jsx h */
82
- import { h } from '/_framework/runtime.js';
83
-
84
83
  export default function Page() {
85
84
  const [count, setCount] = useState(0);
86
85
 
@@ -100,8 +99,6 @@ export default function Page() {
100
99
 
101
100
  ```js
102
101
  // app/layout.js → wraps every page
103
- /** @jsx h */
104
- import { h } from '/_framework/runtime.js';
105
102
  import Navbar from '/components/Navbar.js';
106
103
 
107
104
  export default function Layout({ children }) {
@@ -120,18 +117,14 @@ export default function Layout({ children }) {
120
117
 
121
118
  ```js
122
119
  // api/users.js → /api/users
123
- const { NextResponse } = require('../modules/next-response');
120
+ const { NextResponse } = require('../_framework/next-response');
124
121
 
125
122
  async function GET(request) {
126
- const { searchParams } = new URL(request.url);
127
- const id = searchParams.get('id');
128
- // fetch from DB...
129
123
  return NextResponse.json({ users: [] });
130
124
  }
131
125
 
132
126
  async function POST(request) {
133
127
  const { name, email } = await request.json();
134
- // save to DB...
135
128
  return NextResponse.json({ created: true }, { status: 201 });
136
129
  }
137
130
 
@@ -140,39 +133,15 @@ module.exports = { GET, POST };
140
133
 
141
134
  ---
142
135
 
143
- ## Imports
144
-
145
- ```js
146
- // Framework
147
- import { h } from '/_framework/runtime.js';
148
- import { navigate } from '/_framework/router.js';
149
-
150
- // Absolute paths
151
- import Navbar from '/components/Navbar.js';
152
-
153
- // @/ alias
154
- import connectDB from '@/lib/db';
155
- import User from '@/models/User';
156
-
157
- // npm packages (install first, then import)
158
- import mongoose from 'mongoose';
159
- import bcrypt from 'bcryptjs';
160
- import jwt from 'jsonwebtoken';
161
- ```
162
-
163
- ---
136
+ ## Hooks
164
137
 
165
- ## React Hooks
166
-
167
- All hooks work exactly like React — no imports needed in pages:
138
+ All React hooks are available globally — no imports needed:
168
139
 
169
140
  ```js
170
- const [count, setCount] = useState(0);
171
- const [user, setUser] = useState(null);
141
+ const [count, setCount] = useState(0);
142
+ const [user, setUser] = useState(null);
172
143
 
173
- useEffect(() => {
174
- fetchUser().then(setUser);
175
- }, []);
144
+ useEffect(() => { fetchUser().then(setUser); }, []);
176
145
 
177
146
  const doubled = useMemo(() => count * 2, [count]);
178
147
  const ref = useRef(null);
@@ -191,30 +160,41 @@ const { data, loading, error } = useFetch('/api/users');
191
160
  ## Navigation
192
161
 
193
162
  ```js
194
- import { navigate, Link, useRouter, useParams, useSearchParams } from '/_framework/router.js';
195
-
196
163
  // Programmatic
197
164
  navigate('/about');
198
165
 
199
- // Component
166
+ // Link component
200
167
  <Link href="/about">About</Link>
201
168
 
202
- // Hook
169
+ // Hooks
203
170
  const { pathname, push, back } = useRouter();
204
-
205
- // Dynamic route params (/blog/[slug])
206
171
  const { slug } = useParams();
172
+ const q = useSearchParams().get('q');
173
+ ```
174
+
175
+ ---
176
+
177
+ ## Imports
207
178
 
208
- // Query string (/search?q=hello)
209
- const searchParams = useSearchParams();
210
- const q = searchParams.get('q');
179
+ ```js
180
+ // Absolute paths
181
+ import Navbar from '/components/Navbar.js';
182
+ import connectDB from '/lib/db.js';
183
+
184
+ // @/ alias
185
+ import User from '@/models/User';
186
+
187
+ // npm packages (install first, then import normally)
188
+ import mongoose from 'mongoose';
189
+ import bcrypt from 'bcryptjs';
190
+ import jwt from 'jsonwebtoken';
211
191
  ```
212
192
 
213
193
  ---
214
194
 
215
195
  ## Full docs
216
196
 
217
- See [README.md](template/README.md) inside your generated project for the complete guide.
197
+ See the [full README](template/README.md) for complete guides on hooks, API routes, database, authentication, and more.
218
198
 
219
199
  ---
220
200
 
@@ -224,4 +204,4 @@ See [README.md](template/README.md) inside your generated project for the comple
224
204
 
225
205
  ## License
226
206
 
227
- AZIZ
207
+ MIT
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-aziz-app",
3
- "version": "3.0.10",
3
+ "version": "3.0.11",
4
4
  "description": "Create Aziz.js apps — lightweight Next.js clone with file-based routing, React hooks, and API routes",
5
5
  "keywords": [
6
6
  "aziz.js",
@@ -58,13 +58,10 @@ my-app/
58
58
 
59
59
  ## Pages
60
60
 
61
- Every `page.js` inside `app/` becomes a route. Export a default function called `Page`.
61
+ Every `page.js` inside `app/` becomes a route. Export a default function — no imports needed.
62
62
 
63
63
  ```js
64
64
  // app/about/page.js → route: /about
65
- /** @jsx h */
66
- import { h } from '/_framework/runtime.js';
67
-
68
65
  export default function Page() {
69
66
  return (
70
67
  <div>
@@ -87,19 +84,15 @@ export default function Page() {
87
84
 
88
85
  ### Creating a new page
89
86
 
90
- Just create the file — no registration, no imports to add:
87
+ Just create the file — no registration needed:
91
88
 
92
89
  ```bash
93
- # Creates route /dashboard
94
90
  mkdir app/dashboard
95
91
  touch app/dashboard/page.js
96
92
  ```
97
93
 
98
94
  ```js
99
- // app/dashboard/page.js
100
- /** @jsx h */
101
- import { h } from '/_framework/runtime.js';
102
-
95
+ // app/dashboard/page.js → route: /dashboard
103
96
  export default function Page() {
104
97
  return <h1>Dashboard</h1>;
105
98
  }
@@ -109,12 +102,10 @@ export default function Page() {
109
102
 
110
103
  ## Layouts
111
104
 
112
- `layout.js` wraps all pages at the same level and below. The root `app/layout.js` wraps every page in your app.
105
+ `layout.js` wraps all pages at the same level and below. The root `app/layout.js` wraps every page.
113
106
 
114
107
  ```js
115
108
  // app/layout.js
116
- /** @jsx h */
117
- import { h } from '/_framework/runtime.js';
118
109
  import Navbar from '/components/Navbar.js';
119
110
  import Footer from '/components/Footer.js';
120
111
 
@@ -133,8 +124,6 @@ export default function Layout({ children }) {
133
124
 
134
125
  ```js
135
126
  // app/dashboard/layout.js — wraps all /dashboard/* pages
136
- /** @jsx h */
137
- import { h } from '/_framework/runtime.js';
138
127
  import Sidebar from '/components/Sidebar.js';
139
128
 
140
129
  export default function Layout({ children }) {
@@ -154,8 +143,6 @@ export default function Layout({ children }) {
154
143
  ### navigate()
155
144
 
156
145
  ```js
157
- import { navigate } from '/_framework/router.js';
158
-
159
146
  navigate('/about');
160
147
  navigate('/blog/my-post');
161
148
  navigate('/');
@@ -164,8 +151,6 @@ navigate('/');
164
151
  ### Link component
165
152
 
166
153
  ```js
167
- import { Link } from '/_framework/router.js';
168
-
169
154
  <Link href="/about">About</Link>
170
155
  <Link href="/blog/hello" className="nav-link">Blog Post</Link>
171
156
  ```
@@ -173,8 +158,6 @@ import { Link } from '/_framework/router.js';
173
158
  ### useRouter hook
174
159
 
175
160
  ```js
176
- import { useRouter } from '/_framework/router.js';
177
-
178
161
  export default function Page() {
179
162
  const router = useRouter();
180
163
 
@@ -192,8 +175,6 @@ export default function Page() {
192
175
 
193
176
  ```js
194
177
  // app/blog/[slug]/page.js
195
- import { useParams } from '/_framework/router.js';
196
-
197
178
  export default function Page() {
198
179
  const { slug } = useParams();
199
180
  return <h1>Post: {slug}</h1>;
@@ -204,8 +185,6 @@ export default function Page() {
204
185
 
205
186
  ```js
206
187
  // URL: /search?q=hello&page=2
207
- import { useSearchParams } from '/_framework/router.js';
208
-
209
188
  export default function Page() {
210
189
  const searchParams = useSearchParams();
211
190
  const query = searchParams.get('q'); // "hello"
@@ -219,7 +198,7 @@ export default function Page() {
219
198
 
220
199
  ## React Hooks
221
200
 
222
- All hooks work exactly like React — no imports needed in pages.
201
+ All hooks work exactly like React — **no imports needed**.
223
202
 
224
203
  ### useState
225
204
 
@@ -228,24 +207,20 @@ const [count, setCount] = useState(0);
228
207
  const [user, setUser] = useState(null);
229
208
  const [items, setItems] = useState([]);
230
209
 
231
- // Functional update
232
210
  setCount(prev => prev + 1);
233
211
  ```
234
212
 
235
213
  ### useEffect
236
214
 
237
215
  ```js
238
- // Run on mount
239
216
  useEffect(() => {
240
217
  console.log('mounted');
241
218
  }, []);
242
219
 
243
- // Run when value changes
244
220
  useEffect(() => {
245
221
  document.title = `Count: ${count}`;
246
222
  }, [count]);
247
223
 
248
- // Cleanup
249
224
  useEffect(() => {
250
225
  const timer = setInterval(() => tick(), 1000);
251
226
  return () => clearInterval(timer);
@@ -255,7 +230,7 @@ useEffect(() => {
255
230
  ### useMemo
256
231
 
257
232
  ```js
258
- const expensiveResult = useMemo(() => {
233
+ const total = useMemo(() => {
259
234
  return items.filter(i => i.active).length;
260
235
  }, [items]);
261
236
  ```
@@ -273,10 +248,8 @@ const handleClick = useCallback(() => {
273
248
  ```js
274
249
  const inputRef = useRef(null);
275
250
 
276
- // In JSX
277
251
  <input ref={inputRef} type="text" />
278
252
 
279
- // Access DOM element
280
253
  inputRef.current.focus();
281
254
  ```
282
255
 
@@ -295,13 +268,11 @@ const reducer = (state, action) => {
295
268
  const [state, dispatch] = useReducer(reducer, { count: 0 });
296
269
 
297
270
  dispatch({ type: 'increment' });
298
- dispatch({ type: 'reset' });
299
271
  ```
300
272
 
301
273
  ### useContext
302
274
 
303
275
  ```js
304
- // Create context
305
276
  const ThemeContext = createContext('light');
306
277
 
307
278
  // Provide value (in layout or parent)
@@ -309,14 +280,13 @@ const ThemeContext = createContext('light');
309
280
  {children}
310
281
  </ThemeContext.Provider>
311
282
 
312
- // Consume in any child
283
+ // Consume anywhere
313
284
  const theme = useContext(ThemeContext);
314
285
  ```
315
286
 
316
287
  ### useLocalStorage
317
288
 
318
289
  ```js
319
- // Persists across page refreshes
320
290
  const [name, setName] = useLocalStorage('userName', '');
321
291
  ```
322
292
 
@@ -341,12 +311,11 @@ API routes run on the **server** (Node.js). Every `.js` file in `api/` becomes a
341
311
 
342
312
  ```js
343
313
  // api/hello.js → GET /api/hello
344
- const { NextResponse } = require('../modules/next-response');
314
+ const { NextResponse } = require('../_framework/next-response');
345
315
 
346
316
  async function GET(request) {
347
317
  const { searchParams } = new URL(request.url);
348
318
  const name = searchParams.get('name') || 'World';
349
-
350
319
  return NextResponse.json({ message: `Hello, ${name}!` });
351
320
  }
352
321
 
@@ -357,139 +326,70 @@ module.exports = { GET };
357
326
 
358
327
  ```js
359
328
  // api/users.js → /api/users
360
- const { NextResponse } = require('../modules/next-response');
329
+ const { NextResponse } = require('../_framework/next-response');
361
330
 
362
331
  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
332
  const users = await User.find();
373
333
  return NextResponse.json(users);
374
334
  }
375
335
 
376
336
  async function POST(request) {
377
- const body = await request.json();
378
- const { name, email } = body;
379
-
337
+ const { name, email } = await request.json();
380
338
  if (!name || !email) {
381
339
  return NextResponse.json({ error: 'Name and email required' }, { status: 400 });
382
340
  }
383
-
384
341
  const user = await User.create({ name, email });
385
342
  return NextResponse.json(user, { status: 201 });
386
343
  }
387
344
 
388
345
  async function DELETE(request) {
389
346
  const { searchParams } = new URL(request.url);
390
- const id = searchParams.get('id');
391
-
392
- await User.findByIdAndDelete(id);
347
+ await User.findByIdAndDelete(searchParams.get('id'));
393
348
  return NextResponse.json({ message: 'Deleted' });
394
349
  }
395
350
 
396
351
  module.exports = { GET, POST, DELETE };
397
352
  ```
398
353
 
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
354
  ### NextResponse
419
355
 
420
356
  ```js
421
- // JSON response
422
357
  return NextResponse.json({ data: 'value' });
423
-
424
- // With status code
425
358
  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
359
  return NextResponse.redirect('/login');
435
-
436
- // Plain text
437
360
  return NextResponse.text('Hello');
438
361
  ```
439
362
 
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
363
  ---
454
364
 
455
365
  ## Imports
456
366
 
457
- Use ES module `import` statements anywhere. The dev server resolves everything automatically.
458
-
459
- ### Framework imports
367
+ ### Components and pages — no imports needed for JSX or hooks
460
368
 
461
369
  ```js
462
- import { h } from '/_framework/runtime.js';
463
- import { navigate, Link, useRouter } from '/_framework/router.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
+ }
464
375
  ```
465
376
 
466
- ### Absolute path imports
377
+ ### Importing other files
467
378
 
468
379
  ```js
469
- import Navbar from '/components/Navbar.js';
380
+ // Absolute path
381
+ import Navbar from '/components/Navbar.js';
470
382
  import connectDB from '/lib/db.js';
471
- import User from '/models/User.js';
472
- ```
473
-
474
- ### @/ alias (same as absolute)
383
+ import User from '/models/User.js';
475
384
 
476
- ```js
385
+ // @/ alias (same as absolute)
477
386
  import connectDB from '@/lib/db';
478
387
  import User from '@/models/User';
479
- import Button from '@/components/Button';
480
- ```
481
388
 
482
- ### npm packages (bare imports)
483
-
484
- ```js
485
- // Install first: npm install mongoose
389
+ // npm packages (install first: npm install mongoose)
486
390
  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';
391
+ import bcrypt from 'bcryptjs';
392
+ import jwt from 'jsonwebtoken';
493
393
  ```
494
394
 
495
395
  The dev server resolves bare imports from `node_modules` automatically — no bundler config needed.
@@ -498,19 +398,13 @@ The dev server resolves bare imports from `node_modules` automatically — no bu
498
398
 
499
399
  ## Components
500
400
 
501
- Components are just functions that return JSX. Always add `/** @jsx h */` at the top.
401
+ Components are just functions that return JSX — no pragma or imports needed.
502
402
 
503
403
  ```js
504
404
  // components/Button.js
505
- /** @jsx h */
506
- import { h } from '/_framework/runtime.js';
507
-
508
405
  export default function Button({ onClick, children, variant = 'primary' }) {
509
406
  return (
510
- <button
511
- class={`btn btn-${variant}`}
512
- onClick={onClick}
513
- >
407
+ <button class={`btn btn-${variant}`} onClick={onClick}>
514
408
  {children}
515
409
  </button>
516
410
  );
@@ -521,35 +415,7 @@ export default function Button({ onClick, children, variant = 'primary' }) {
521
415
  // Using the component
522
416
  import Button from '/components/Button.js';
523
417
 
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>
418
+ <Button onClick={() => alert('hi')} variant="danger">Delete</Button>
553
419
  ```
554
420
 
555
421
  ### JSX rules
@@ -563,7 +429,6 @@ import Button from '/components/Button.js';
563
429
 
564
430
  // Self-closing tags need /
565
431
  <input type="text" />
566
- <br />
567
432
 
568
433
  // Expressions in {}
569
434
  <p>{count > 0 ? 'positive' : 'zero'}</p>
@@ -573,7 +438,6 @@ import Button from '/components/Button.js';
573
438
 
574
439
  // Conditional rendering
575
440
  {isLoggedIn && <Dashboard />}
576
- {error ? <Error msg={error} /> : <Content />}
577
441
  ```
578
442
 
579
443
  ---
@@ -596,7 +460,6 @@ export default async function connectDB() {
596
460
  if (isConnected) return;
597
461
  await mongoose.connect(process.env.MONGODB_URI);
598
462
  isConnected = true;
599
- console.log('✅ MongoDB connected');
600
463
  }
601
464
  ```
602
465
 
@@ -605,97 +468,41 @@ export default async function connectDB() {
605
468
  import mongoose from 'mongoose';
606
469
 
607
470
  const userSchema = new mongoose.Schema({
608
- name: { type: String, required: true },
609
- email: { type: String, required: true, unique: true },
471
+ name: { type: String, required: true },
472
+ email: { type: String, required: true, unique: true },
610
473
  password: { type: String, required: true },
611
- role: { type: String, enum: ['user', 'admin'], default: 'user' }
612
474
  }, { timestamps: true });
613
475
 
614
476
  export default mongoose.models.User || mongoose.model('User', userSchema);
615
477
  ```
616
478
 
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');
622
-
623
- async function GET(request) {
624
- await connectDB();
625
-
626
- const { searchParams } = new URL(request.url);
627
- const email = searchParams.get('email');
628
-
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
- }
634
-
635
- const users = await User.find().select('-password');
636
- return NextResponse.json(users);
637
- }
638
-
639
- module.exports = { GET };
640
- ```
641
-
642
479
  ### Environment variables
643
480
 
644
- Create a `.env` file in your project root:
481
+ Create `.env` in your project root:
645
482
 
646
483
  ```bash
647
484
  MONGODB_URI=mongodb://localhost:27017/myapp
648
485
  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
486
  ```
658
487
 
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`.
488
+ > Install `dotenv` and add `require('dotenv').config()` at the top of `scripts/dev-server.js` to load `.env` automatically.
660
489
 
661
490
  ---
662
491
 
663
492
  ## Calling APIs from Pages
664
493
 
665
494
  ```js
666
- // Simple fetch
667
- const response = await fetch('/api/users');
668
- const users = await response.json();
495
+ // GET
496
+ const res = await fetch('/api/users');
497
+ const users = await res.json();
669
498
 
670
- // POST request
671
- const response = await fetch('/api/users', {
499
+ // POST
500
+ const res = await fetch('/api/users', {
672
501
  method: 'POST',
673
502
  headers: { 'Content-Type': 'application/json' },
674
503
  body: JSON.stringify({ name: 'Aziz', email: 'aziz@example.com' })
675
504
  });
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
- }
505
+ const result = await res.json();
699
506
  ```
700
507
 
701
508
  ### Full login example
@@ -742,16 +549,16 @@ export default function Page() {
742
549
  <form onSubmit={handleLogin}>
743
550
  <input
744
551
  type="email"
552
+ placeholder="Email"
745
553
  value={email}
746
554
  onInput={(e) => setEmail(e.target.value)}
747
- placeholder="Email"
748
555
  required
749
556
  />
750
557
  <input
751
558
  type="password"
559
+ placeholder="Password"
752
560
  value={password}
753
561
  onInput={(e) => setPassword(e.target.value)}
754
- placeholder="Password"
755
562
  required
756
563
  />
757
564
  {error && <p style={{ color: 'red' }}>{error}</p>}
@@ -770,21 +577,14 @@ export default function Page() {
770
577
 
771
578
  ### globals.css
772
579
 
773
- Edit `styles/globals.css` for your global styles. Built-in utility classes:
580
+ Edit `styles/globals.css` for global styles. Built-in utility classes:
774
581
 
775
582
  ```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 */
583
+ .card { background: white; border-radius: 10px; padding: 24px; box-shadow: 0 2px 8px rgba(0,0,0,0.08); margin-bottom: 20px; }
780
584
  .btn { display: inline-block; padding: 10px 22px; border: none; border-radius: 8px; cursor: pointer; }
781
585
  .btn-primary { background: #61dafb; color: #282c34; font-weight: bold; }
782
586
  .btn-danger { background: #ff6b6b; color: white; }
783
587
  .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
588
  ```
789
589
 
790
590
  ### Inline styles
@@ -797,27 +597,12 @@ Edit `styles/globals.css` for your global styles. Built-in utility classes:
797
597
 
798
598
  ### Tailwind CSS
799
599
 
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`:
600
+ Choose Tailwind during project creation, or add it manually to `index.html`:
808
601
 
809
602
  ```html
810
603
  <script src="https://cdn.tailwindcss.com"></script>
811
604
  ```
812
605
 
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
606
  ---
822
607
 
823
608
  ## Dev Server
@@ -826,37 +611,16 @@ Then use Tailwind classes directly:
826
611
  npm run dev
827
612
  ```
828
613
 
829
- The dev server:
830
614
  - 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)
615
+ - Watches all source folders and live-reloads on save
833
616
  - Resolves bare imports from `node_modules`
834
- - Loads API routes from `api/`
835
617
  - Hot-reloads API routes when changed
836
618
 
837
- ### Custom port
838
-
839
619
  ```bash
620
+ # Custom port
840
621
  PORT=4000 npm run dev
841
622
  ```
842
623
 
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
624
  ---
861
625
 
862
626
  ## Comparison with Next.js
@@ -870,13 +634,12 @@ Click it to manually reload.
870
634
  | Catch-all `[...slug]` | ✅ | ✅ |
871
635
  | API routes | ✅ | ✅ |
872
636
  | `NextResponse` | ✅ | ✅ |
873
- | Named HTTP exports | ✅ | ✅ |
874
637
  | React hooks | ✅ | ✅ |
638
+ | No imports needed in pages | ✅ | ❌ |
875
639
  | ES module imports | ✅ | ✅ |
876
640
  | `@/` path alias | ✅ | ✅ |
877
641
  | Live reload | ✅ | ✅ |
878
642
  | SSR / SSG | ❌ | ✅ |
879
- | Image optimization | ❌ | ✅ |
880
643
  | TypeScript | ❌ | ✅ |
881
644
  | Bundle size | **~50KB** | ~400KB+ |
882
645
  | Dependencies | **0** | 20+ |
@@ -884,53 +647,6 @@ Click it to manually reload.
884
647
 
885
648
  ---
886
649
 
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
650
  ## License
935
651
 
936
652
  MIT
@@ -1,6 +1,3 @@
1
- /** @jsx h */
2
- import { h } from '/_framework/runtime.js';
3
-
4
1
  // About page — route: /about
5
2
  export default function Page() {
6
3
  return (
@@ -1,7 +1,6 @@
1
- /** @jsx h */
2
- import { h } from '/_framework/runtime.js';
3
1
  import Navbar from '/components/Navbar.js';
4
2
  import Footer from '/components/Footer.js';
3
+
5
4
  // Root layout — wraps every page (like Next.js app/layout.js)
6
5
  export default function Layout({ children }) {
7
6
  return (
@@ -15,7 +14,6 @@ export default function Layout({ children }) {
15
14
  );
16
15
  }
17
16
 
18
- // Optional: export metadata
19
17
  export const metadata = {
20
18
  title: 'My App',
21
19
  description: 'Built with Aziz.js'
@@ -1,6 +1,3 @@
1
- /** @jsx h */
2
- import { h } from '/_framework/runtime.js';
3
-
4
1
  // Home page — route: /
5
2
  export default function Page() {
6
3
  const [count, setCount] = useState(0);
@@ -40,7 +37,7 @@ export default function Page() {
40
37
  <h2>Import Anything</h2>
41
38
  <p>
42
39
  Use <code>import</code> statements just like Next.js.
43
- The dev server resolves bare imports from <code>node_modules</code>.
40
+ The dev server resolves bare imports from <code>node_modules</code> automatically.
44
41
  </p>
45
42
  <pre style={{ background: '#282c34', color: '#61dafb', padding: '16px', borderRadius: '8px', overflow: 'auto', fontSize: '13px' }}>
46
43
  {`import mongoose from 'mongoose';
@@ -1,11 +1,8 @@
1
- /** @jsx h */
2
- import { h } from '/_framework/runtime.js';
3
-
4
1
  // Test page — route: /test
5
2
  export default function Page() {
6
- const [count, setCount] = useState(0);
7
- const [name, setName] = useState('');
8
- const [email, setEmail] = useState('');
3
+ const [count, setCount] = useState(0);
4
+ const [name, setName] = useState('');
5
+ const [email, setEmail] = useState('');
9
6
 
10
7
  const handleSubmit = (e) => {
11
8
  e.preventDefault();
@@ -30,15 +27,15 @@ export default function Page() {
30
27
  <form onSubmit={handleSubmit}>
31
28
  <input
32
29
  type="text"
30
+ placeholder="Your name"
33
31
  value={name}
34
32
  onInput={(e) => setName(e.target.value)}
35
- placeholder="Your name"
36
33
  />
37
34
  <input
38
35
  type="email"
36
+ placeholder="Your email"
39
37
  value={email}
40
38
  onInput={(e) => setEmail(e.target.value)}
41
- placeholder="Your email"
42
39
  />
43
40
  <button type="submit" class="btn btn-primary">Submit</button>
44
41
  </form>
@@ -1,6 +1,3 @@
1
- /** @jsx h */
2
- import { h } from '/_framework/runtime.js';
3
-
4
1
  export default function Footer() {
5
2
  return (
6
3
  <footer>
@@ -1,15 +1,12 @@
1
- /** @jsx h */
2
- import { h } from '/_framework/runtime.js';
3
-
4
- // navigate and useRouter are globals set by boot.js
1
+ // navigate and useRouter are globals — no imports needed
5
2
  export default function Navbar() {
6
3
  const { pathname } = useRouter();
7
4
 
8
5
  const links = [
9
- { href: '/', label: 'Home' },
10
- { href: '/about', label: 'About' },
11
- { href: '/test', label: 'Test' },
12
- { href: '/contact', label: 'Contact' },
6
+ { href: '/', label: 'Home' },
7
+ { href: '/about', label: 'About' },
8
+ { href: '/test', label: 'Test' },
9
+ { href: '/contact', label: 'Contact' },
13
10
  ];
14
11
 
15
12
  return (