create-aziz-app 3.1.2 → 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.
Files changed (33) hide show
  1. package/README.md +658 -207
  2. package/bin/create-aziz-app.js +302 -302
  3. package/package.json +1 -1
  4. package/template/README.md +402 -402
  5. package/template/_framework/api.js +219 -219
  6. package/template/_framework/boot.js +33 -33
  7. package/template/_framework/hooks.js +367 -291
  8. package/template/_framework/next-response.js +128 -128
  9. package/template/_framework/route-match.js +145 -145
  10. package/template/_framework/router.js +465 -259
  11. package/template/_framework/runtime.js +264 -264
  12. package/template/app/layout.js +18 -18
  13. package/template/app/page.js +33 -33
  14. package/template/docs/01-getting-started.md +151 -151
  15. package/template/docs/02-project-structure.md +109 -109
  16. package/template/docs/03-pages-and-layouts.md +140 -140
  17. package/template/docs/04-routing.md +120 -120
  18. package/template/docs/05-hooks.md +169 -169
  19. package/template/docs/06-api-routes.md +210 -210
  20. package/template/docs/07-api-client.md +151 -151
  21. package/template/docs/08-styling.md +94 -94
  22. package/template/docs/09-imports-and-modules.md +97 -97
  23. package/template/docs/10-database-and-models.md +154 -154
  24. package/template/docs/11-authentication.md +171 -171
  25. package/template/docs/12-production-and-deployment.md +121 -121
  26. package/template/docs/13-internals.md +179 -179
  27. package/template/docs/README.md +67 -67
  28. package/template/index.html +20 -20
  29. package/template/package.json +16 -16
  30. package/template/scripts/dev-server.js +493 -381
  31. package/template/scripts/lib/api-router.js +525 -525
  32. package/template/scripts/lib/js-transform.js +213 -195
  33. package/template/scripts/lib/module-resolver.js +132 -132
package/README.md CHANGED
@@ -1,207 +1,658 @@
1
- # ⚡ Aziz.js
2
-
3
- > A lightweight Next.js clone — file-based routing, React hooks, server-side API routes, ES module imports. **Zero dependencies. Instant startup.**
4
-
5
- ```bash
6
- npx create-aziz-app my-app
7
- ```
8
-
9
- ---
10
-
11
- ## What is this?
12
-
13
- Aziz.js gives you the Next.js developer experience without the weight:
14
-
15
- | | Aziz.js | Next.js |
16
- |--|---------|---------|
17
- | Bundle size | **~50KB** | ~400KB+ |
18
- | Dependencies | **0** | 20+ |
19
- | Startup time | **< 1s** | 10–30s |
20
- | `page.js` routing | ✅ | ✅ |
21
- | `layout.js` | ✅ | ✅ |
22
- | API routes | ✅ | ✅ |
23
- | `NextResponse` | ✅ | ✅ |
24
- | React hooks | ✅ | ✅ |
25
- | No imports needed in pages | ✅ | ❌ |
26
- | `@/` alias | ✅ | ✅ |
27
- | Live reload | ✅ | ✅ |
28
- | SSR / SSG | ❌ | ✅ |
29
-
30
- ---
31
-
32
- ## Getting Started
33
-
34
- ```bash
35
- npx create-aziz-app my-app
36
- cd my-app
37
- npm run dev
38
- ```
39
-
40
- The CLI will ask you:
41
- - **Project name**
42
- - **Port** (default: 3000)
43
- - **CSS framework** — None / Bootstrap / Tailwind
44
- - **Include examples?**
45
- - **Include docs?**
46
-
47
- ---
48
-
49
- ## Project Structure
50
-
51
- ```
52
- my-app/
53
- ├── index.html
54
- ├── app/
55
- │ ├── layout.js ← root layout
56
- │ ├── page.js ← route: /
57
- │ ├── about/
58
- │ │ └── page.js ← route: /about
59
- │ └── blog/
60
- │ └── [slug]/
61
- │ └── page.js ← route: /blog/:slug
62
- ├── api/
63
- │ └── users.js ← /api/users (server-side)
64
- ├── components/
65
- │ ├── Navbar.js
66
- │ └── Footer.js
67
- ├── lib/
68
- │ └── db.js
69
- ├── models/
70
- │ └── User.js
71
- └── styles/
72
- └── globals.css
73
- ```
74
-
75
- ---
76
-
77
- ## Pages
78
-
79
- No imports needed — JSX and all hooks just work.
80
-
81
- ```js
82
- // app/about/page.js → /about
83
- export default function Page() {
84
- const [count, setCount] = useState(0);
85
-
86
- return (
87
- <div>
88
- <h1>About</h1>
89
- <p>Count: {count}</p>
90
- <button onClick={() => setCount(c => c + 1)}>+</button>
91
- </div>
92
- );
93
- }
94
- ```
95
-
96
- ---
97
-
98
- ## Layouts
99
-
100
- ```js
101
- // app/layout.js → wraps every page
102
- import Navbar from '/components/Navbar.js';
103
-
104
- export default function Layout({ children }) {
105
- return (
106
- <div>
107
- <Navbar />
108
- <main>{children}</main>
109
- </div>
110
- );
111
- }
112
- ```
113
-
114
- ---
115
-
116
- ## API Routes
117
-
118
- ```js
119
- // api/users.js → /api/users
120
- const { NextResponse } = require('../_framework/next-response');
121
-
122
- async function GET(request) {
123
- return NextResponse.json({ users: [] });
124
- }
125
-
126
- async function POST(request) {
127
- const { name, email } = await request.json();
128
- return NextResponse.json({ created: true }, { status: 201 });
129
- }
130
-
131
- module.exports = { GET, POST };
132
- ```
133
-
134
- ---
135
-
136
- ## Hooks
137
-
138
- All React hooks are available globally — no imports needed:
139
-
140
- ```js
141
- const [count, setCount] = useState(0);
142
- const [user, setUser] = useState(null);
143
-
144
- useEffect(() => { fetchUser().then(setUser); }, []);
145
-
146
- const doubled = useMemo(() => count * 2, [count]);
147
- const ref = useRef(null);
148
-
149
- const [state, dispatch] = useReducer(reducer, initialState);
150
-
151
- const theme = useContext(ThemeContext);
152
-
153
- const [name, setName] = useLocalStorage('name', '');
154
-
155
- const { data, loading, error } = useFetch('/api/users');
156
- ```
157
-
158
- ---
159
-
160
- ## Navigation
161
-
162
- ```js
163
- // Programmatic
164
- navigate('/about');
165
-
166
- // Link component
167
- <Link href="/about">About</Link>
168
-
169
- // Hooks
170
- const { pathname, push, back } = useRouter();
171
- const { slug } = useParams();
172
- const q = useSearchParams().get('q');
173
- ```
174
-
175
- ---
176
-
177
- ## Imports
178
-
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';
191
- ```
192
-
193
- ---
194
-
195
- ## Full docs
196
-
197
- See the [full README](template/README.md) for complete guides on hooks, API routes, database, authentication, and more.
198
-
199
- ---
200
-
201
- ## Author
202
-
203
- **Syed Muhammad Aziz Ahmed**
204
-
205
- ## License
206
-
207
- MIT
1
+ # ⚡ Aziz.js
2
+
3
+ **A lightweight Next.js-shaped framework** — file-based routing, global React hooks, server-side API routes, and ES module imports. Zero runtime dependencies, no bundler, no build step.
4
+
5
+ ```bash
6
+ npx create-aziz-app my-app
7
+ ```
8
+
9
+ > **Heads-up before you start:** after scaffolding you must run `npm install` in the new folder. Aziz.js compiles JSX with `@babel/standalone`, and until that is installed every page will fail to load and the router will show its built-in 404. The dev server prints a banner telling you exactly this.
10
+
11
+ ---
12
+
13
+ ## Table of contents
14
+
15
+ - [What this actually is](#what-this-actually-is)
16
+ - [Quick start](#quick-start)
17
+ - [Measured numbers](#measured-numbers-how-they-were-taken)
18
+ - [Aziz.js vs Next.js](#azizjs-vs-nextjs)
19
+ - [What Aziz.js is good at](#what-azizjs-is-good-at)
20
+ - [What Next.js is good at](#what-nextjs-is-good-at--when-to-use-it-instead)
21
+ - [The full guide: frontend → backend](#the-full-guide-frontend--backend)
22
+ - [Phase 0 — Setup](#phase-0--setup)
23
+ - [Phase 1 — Frontend fundamentals](#phase-1--frontend-fundamentals)
24
+ - [Phase 2 — State and data](#phase-2--state-and-data)
25
+ - [Phase 3 — Backend](#phase-3--backend)
26
+ - [Phase 4 — Database](#phase-4--database)
27
+ - [Phase 5 — Authentication](#phase-5--authentication)
28
+ - [Phase 6 — Production](#phase-6--production)
29
+ - [API reference](#api-reference)
30
+ - [Security model — read this before deploying](#security-model--read-this-before-deploying)
31
+ - [Known limitations (read this)](#known-limitations-read-this)
32
+ - [Gotchas](#gotchas)
33
+ - [Troubleshooting](#troubleshooting)
34
+
35
+ ---
36
+
37
+ ## What this actually is
38
+
39
+ Aziz.js deliberately copies the **shape** of Next.js — `app/page.js` maps to `/`, `app/blog/[slug]/page.js` maps to `/blog/:slug`, `app/api/**/route.js` maps to `/api/**` — so the mental model transfers. But it implements that shape over a ~1,300-line custom runtime served straight to the browser as ES modules. There is no bundler, no compiler pipeline, no React dependency, and no server rendering.
40
+
41
+ It is a **client-side rendered (CSR) full-stack framework**. Everything renders in the browser after a ~13 KB gzip boot.
42
+
43
+ ## Quick start
44
+
45
+ ```bash
46
+ npx create-aziz-app my-app
47
+ cd my-app
48
+ npm install # ← required; see the heads-up above
49
+ npm run dev
50
+ ```
51
+
52
+ The CLI asks four things (these are the *actual* prompts in v3.1.2):
53
+
54
+ | Prompt | Default |
55
+ | --- | --- |
56
+ | 📁 Project name | `my-aziz-js-app` |
57
+ | 🌐 Dev server port | `3000` |
58
+ | Include documentation? | `Y` |
59
+ | 🎨 CSS Framework — 1 None / 2 Bootstrap / 3 Tailwind | `1` (none) |
60
+
61
+ Flags: `-y/--yes` (accept defaults), `--port <n>`, `--css none|bootstrap|tailwind`, `--no-docs`.
62
+
63
+ ### What you actually get
64
+
65
+ ```text
66
+ my-app/
67
+ ├── index.html
68
+ ├── package.json
69
+ ├── app/
70
+ │ ├── layout.js ← root layout (wraps every page)
71
+ │ └── page.js ← route: /
72
+ ├── styles/globals.css
73
+ ├── _framework/ ← the runtime (7 files, ~1,350 lines)
74
+ ├── scripts/dev-server.js
75
+ └── docs/ ← 14 markdown guides (unless --no-docs)
76
+ ```
77
+
78
+ That is the whole template. There are **no** `components/`, `lib/`, `models/`, `api/` folders, no example pages, and no `not-found.js` — you create those yourself, and the rest of this guide shows you how.
79
+
80
+ ---
81
+
82
+ ## Measured numbers (how they were taken)
83
+
84
+ Every figure below was measured against this repository at v3.1.2 on Node v24.16.0, Windows, rather than estimated.
85
+
86
+ | Metric | Aziz.js | Next.js | Method |
87
+ | --- | --- | --- | --- |
88
+ | Browser payload per page | **42.5 KB raw / 12.7 KB gzip** | varies by app | Sum of `boot.js`, `runtime.js`, `hooks.js`, `router.js`, `route-match.js`, `api.js`, gzipped with zlib |
89
+ | Total runtime source | **46.8 KB raw / 14.0 KB gzip** (7 files, 1,348 lines) | — | All of `_framework/` |
90
+ | Dev server launch → first HTTP response | **161 ms** median (158/160/161/165/209 over 5 runs) | not measured here | Spawn process, poll until `/` returns |
91
+ | Runtime dependencies | **0** | **6** direct (`postcss`, `@next/env`, `styled-jsx`, `@swc/helpers`, `caniuse-lite`, `baseline-browser-mapping`) | npm registry metadata for `next@16.4.2` |
92
+ | Required peers | none | `react` + `react-dom` | registry |
93
+ | Dev dependencies | 1 (`@babel/standalone`) | varies | `package.json` |
94
+ | Installed size | **36.7 MB** for `@babel/standalone` (build-time only) | **183.6 MB** for `next` alone, + 7.7 MB `react-dom`, + 174 KB `react` | `dist.unpackedSize`, npm registry |
95
+ | Node requirement | works on Node 24 (no `engines` gate) | **>= 20.9.0** | registry |
96
+ | Bundling / minification | **none** | Turbopack, SWC, code splitting | — |
97
+
98
+ Honest caveats about our own numbers:
99
+
100
+ - **42.5 KB is unminified.** Aziz.js never minifies, tree-shakes, or code-splits. Your own app code is also served as-is. Gzip brings that 42.5 KB down to 12.7 KB; Brotli would shave roughly another 10–15% on top, not half.
101
+ - **`@babel/standalone` is 36.7 MB on disk.** It is a dev-time-only dependency and never reaches the browser, but if "zero dependencies" mattered to you for disk footprint, it does not. It is also the entire reason `npm install` is mandatory.
102
+ - **`react-dom` is 7.7 MB unpacked** but ships far less to the browser; the 183.6 MB for `next` is mostly platform binaries and build tooling.
103
+
104
+ ---
105
+
106
+ ## Aziz.js vs Next.js
107
+
108
+ ### Capability comparison
109
+
110
+ | Capability | Aziz.js | Next.js |
111
+ | --- | --- | --- |
112
+ | File-based routing (`page.js`) | ✅ | ✅ |
113
+ | Layouts (`layout.js`) | ✅ | ✅ |
114
+ | Dynamic routes (`[slug]`) | ✅ | ✅ |
115
+ | Catch-all routes (`[...path]`) | ✅ | ✅ |
116
+ | API routes | ✅ both `api/x.js` and `app/api/**/route.js` | ✅ `app/api/**/route.js` |
117
+ | `NextResponse.json()` | ✅ | ✅ |
118
+ | Global hooks (no imports) | ✅ 11 hooks | ❌ must import from React |
119
+ | `Link` / `navigate()` / `useParams()` | ✅ | ✅ (requires import) |
120
+ | `@/` path alias | ✅ | ✅ (needs config) |
121
+ | WebSocket live reload | ✅ built in | ✅ Fast Refresh |
122
+ | Server-side rendering | ❌ **CSR only** | ✅ |
123
+ | Static generation (SSG) | ❌ | ✅ |
124
+ | React Server Components | ❌ | ✅ |
125
+ | Streaming / Suspense | ❌ | ✅ |
126
+ | TypeScript | ❌ **`.tsx` is silently ignored → 404** | ✅ first-class |
127
+ | Route prefetching | ❌ | ✅ |
128
+ | Image optimization (`next/image`) | ❌ | ✅ |
129
+ | Font optimization (`next/font`) | ❌ | ✅ |
130
+ | Metadata / OG image API | ⚠️ simple `metadata` export only | ✅ full API |
131
+ | Middleware / proxy | ❌ | ✅ |
132
+ | i18n routing | ❌ | ✅ built in |
133
+ | Edge runtime | ❌ | ✅ |
134
+ | Mature ecosystem & docs | ❌ small | ✅ enormous |
135
+ | Battle-tested at scale | ❌ | ✅ used in production by thousands |
136
+
137
+ ### The three numbers people actually care about
138
+
139
+ Only the Aziz.js column was measured in this repo; the Next.js column is characterised, not benchmarked.
140
+
141
+ | | Aziz.js | Next.js |
142
+ | --- | --- | --- |
143
+ | Time to first page render in dev | **~161 ms** (measured) | Not measured here — must boot a compiler (Turbopack/SWC) before serving |
144
+ | JS downloaded before your app is interactive | **12.7 KB gzip** (measured) | Not measured here — React + React DOM + router ship first |
145
+ | `node_modules` on disk | **36.7 MB** (measured, one dev tool) | **~190 MB+** (measured, `next` + `react` + `react-dom` unpacked) |
146
+
147
+ ---
148
+
149
+ ## What Aziz.js is good at
150
+
151
+ Be genuinely enthusiastic about these, because they are real:
152
+
153
+ 1. **Learning file-based routing without the ceremony.** You write `app/about/page.js` and it works. No `page.tsx`, no `'use client'` directive, no `import Link from 'next/link'`. Nothing to unlearn later — the conventions match Next.js exactly, so the skills transfer.
154
+ 2. **Instant feedback loop.** ~161 ms from `npm run dev` to a working server. No compile step, no bundle, no HMR handshake. Edit and reload.
155
+ 3. **Genuinely small client runtime.** 12.7 KB gzip to ship a router, a hooks implementation, a reconciler, and an API client.
156
+ 4. **Zero runtime dependencies.** No React, no scheduler, no history library. `node_modules` for the runtime is empty.
157
+ 5. **Readable source.** The entire browser runtime is ~1,350 lines across 7 files. When something breaks you can read the actual implementation instead of debugging a bundled dependency.
158
+ 6. **Real full-stack in one process.** API routes, a file watcher, live reload over WebSocket, and static serving from one ~380-line Node script with no framework underneath.
159
+ 7. **Good for prototypes, demos, internal tools, CLI-adjacent dashboards, and learning.**
160
+
161
+ ## What Next.js is good at — when to use it instead
162
+
163
+ Aziz.js genuinely does not compete here. Use Next.js when:
164
+
165
+ 1. **You need SEO or fast first paint.** Aziz.js ships an empty `<div id="root">` and renders in the browser. Search engine crawlers and slow devices see nothing until JS runs. This is the single biggest gap.
166
+ 2. **You need SSR, SSG, ISR, or React Server Components.** None exist in Aziz.js.
167
+ 3. **You need TypeScript.** `.tsx` is silently ignored by the route scanner — you get a 404 with no warning. Aziz.js is JS-only.
168
+ 4. **You need streaming/Suspense** for progressive rendering.
169
+ 5. **You need `next/image`, `next/font`, the Metadata API, or OG image generation.**
170
+ 6. **You need middleware, edge runtime, or i18n routing.**
171
+ 7. **You are building something large.** Route prefetching, code splitting, caching semantics, upgrade paths, and a hiring pool that already knows Next.js.
172
+ 8. **You need security patches.** Next.js ships coordinated CVE responses (e.g. the September 2026 release addressing nine vulnerabilities). Aziz.js has one author.
173
+
174
+ **The honest one-liner:** Aziz.js is a teaching tool and a fast prototype rig. Next.js is a production platform. They overlap on syntax, not on capability.
175
+
176
+ ---
177
+
178
+ ## The full guide: frontend → backend
179
+
180
+ ### Phase 0 — Setup
181
+
182
+ ```bash
183
+ npx create-aziz-app my-app
184
+ cd my-app
185
+ npm install
186
+ npm run dev
187
+ ```
188
+
189
+ Scripts:
190
+
191
+ | Command | Purpose |
192
+ | --- | --- |
193
+ | `npm run dev` | Dev server + WebSocket live reload |
194
+ | `npm run build` | Serves with production cache headers, live reload disabled |
195
+ | `npm start` | Same as `build` |
196
+
197
+ Change the port with the `PORT` environment variable:
198
+
199
+ ```bash
200
+ PORT=4000 npm run dev # macOS / Linux
201
+ $env:PORT=4000; npm run dev # Windows PowerShell
202
+ ```
203
+
204
+ If the port is busy the server automatically tries the next one and prints the URL it actually bound.
205
+
206
+ ### Phase 1 — Frontend fundamentals
207
+
208
+ **Pages.** Any `page.js` under `app/` becomes a route. No imports needed — JSX and all hooks are already global.
209
+
210
+ ```jsx
211
+ // app/about/page.js → /about
212
+ export default function Page() {
213
+ const [count, setCount] = useState(0);
214
+ return (
215
+ <div>
216
+ <h1>About</h1>
217
+ <p>Count: {count}</p>
218
+ <button onClick={() => setCount(c => c + 1)}>+</button>
219
+ </div>
220
+ );
221
+ }
222
+ ```
223
+
224
+ **Routing map:**
225
+
226
+ | File | URL |
227
+ | --- | --- |
228
+ | `app/page.js` | `/` |
229
+ | `app/about/page.js` | `/about` |
230
+ | `app/blog/[slug]/page.js` | `/blog/:slug` |
231
+ | `app/docs/[...path]/page.js` | `/docs/*` (one or more segments) |
232
+ | `app/not-found.js` | your custom 404 screen |
233
+ | `app/loading.js` | shown while this route's data loads |
234
+ | `app/error.js` | catches render errors in this route |
235
+
236
+ Directory names are **case-sensitive**. `app/MyPage/page.js` serves `/MyPage` only — `/mypage` will 404.
237
+
238
+ **Layouts** wrap every page beneath them:
239
+
240
+ ```jsx
241
+ // app/layout.js
242
+ import Navbar from '/components/Navbar.js';
243
+
244
+ export default function Layout({ children }) {
245
+ return (
246
+ <>
247
+ <Navbar />
248
+ <main>{children}</main>
249
+ </>
250
+ );
251
+ }
252
+
253
+ export const metadata = { title: 'My App', description: 'Built with Aziz.js' };
254
+ ```
255
+
256
+ A `metadata` export is honoured on layouts and pages. Only **`title`** and **`description`** are applied — layouts merge outermost-first and the page wins. Client-side only, so crawlers that do not execute JavaScript will not see it.
257
+
258
+ Nested `app/blog/layout.js` wraps only `/blog/*`. Layouts compose outermost-first, and the 404 screen also renders inside them.
259
+
260
+ **Components** are plain modules anywhere in the project. Use an absolute path or the `@/` alias:
261
+
262
+ ```jsx
263
+ import Navbar from '/components/Navbar.js';
264
+ import connectDB from '@/lib/db.js';
265
+ ```
266
+
267
+ **Navigation.** Everything below is a global — no `next/navigation` import needed.
268
+
269
+ ```jsx
270
+ // Declaring a link — client-side, the document never reloads
271
+ <Link href="/about">About</Link>
272
+ <Link href="/login" replace scroll={false}>Login</Link>
273
+
274
+ // Reading the current location
275
+ const pathname = usePathname(); // '/blog/hello'
276
+ const { slug } = useParams(); // { slug: 'hello' }
277
+ const q = useSearchParams().get('q');
278
+
279
+ // Navigating
280
+ navigate('/about'); // push
281
+ replace('/login'); // replace, no history entry
282
+ back(); forward(); refresh();
283
+
284
+ redirect('/dashboard'); // from a component or effect
285
+
286
+ const router = useRouter(); // { pathname, push, replace, back,
287
+ // forward, refresh, prefetch, params }
288
+ const nav = useNavigation(); // { isPending, state, ...useRouter() }
289
+
290
+ // useTransition is the real Next.js hook (there is no useNavigation in Next.js
291
+ // itself — this one is provided for convenience and Next.js-like ergonomics).
292
+ const [isPending, startTransition] = useTransition();
293
+ ```
294
+
295
+ `isPending` is `false` between transitions — Aziz.js routing is synchronous with no server round-trip to await. `prefetch()` is a safe no-op, kept for API parity (there is no prefetching to do). `startTransition` reports `isPending` while an **async** callback settles, so it composes with `useFetch` and data loading.
296
+
297
+ **Rendering your own 404 from a page** — call `notFound()`:
298
+
299
+ ```jsx
300
+ // app/posts/[slug]/page.js
301
+ export default function Page() {
302
+ const { slug } = useParams();
303
+ const post = findPost(slug);
304
+ if (!post) notFound(); // renders app/not-found.js
305
+ return <h1>{post.title}</h1>;
306
+ }
307
+ ```
308
+
309
+ **Custom 404.** Create `app/not-found.js` (or `app/404.js` — both names work):
310
+
311
+ ```jsx
312
+ export default function NotFound() {
313
+ return <div><h1>Page not found</h1><Link href="/">← Back to Home</Link></div>;
314
+ }
315
+ ```
316
+
317
+ **Loading UI.** Create `app/loading.js` and it is shown while the route's data is still in flight:
318
+
319
+ ```jsx
320
+ // app/loading.js
321
+ export default function Loading() {
322
+ return <div className="skeleton">Loading…</div>;
323
+ }
324
+ ```
325
+
326
+ Three things worth knowing, because they differ from Next.js:
327
+
328
+ 1. **It only appears if the route is slow.** Page modules are all imported at boot, so a navigation has no module-fetch window — data fetching is the only async part. `loading.js` appears only if requests are still in flight **200 ms** after the route renders, then the page replaces it. Fast routes never flash a spinner.
329
+ 2. **It inherits by segment,** exactly like layouts. `app/loading.js` covers every route; `app/blog/loading.js` overrides it for `/blog/*` only.
330
+ 3. **No file means no spinner.** To turn it off for a page, simply delete the nearest `loading.js`. Do not add a magic `'no loading'` comment — absence of the file *is* the opt-out, and it matches Next.js.
331
+
332
+ **Error boundary.** Create `app/error.js` and render failures stop white-screening the app:
333
+
334
+ ```jsx
335
+ // app/error.js — receives { error, reset }, same shape as Next.js
336
+ export default function ErrorBoundary({ error, reset }) {
337
+ return (
338
+ <div>
339
+ <h2>Something broke</h2>
340
+ <p>{error.message}</p>
341
+ <button onClick={reset}>Try again</button>
342
+ </div>
343
+ );
344
+ }
345
+ ```
346
+
347
+ It inherits by segment like `layout.js` and `loading.js`, so you can trap errors around one subtree without catching the whole app. Without an `error.js`, the error propagates and is logged — the framework does not silently swallow bugs.
348
+
349
+ ### Phase 2 — State and data
350
+
351
+ All 11 hooks are global — no imports:
352
+
353
+ | Hook | Purpose |
354
+ | --- | --- |
355
+ | `useState` | local state |
356
+ | `useReducer` | complex state |
357
+ | `useEffect` | side effects / subscriptions |
358
+ | `useMemo` / `useCallback` | memoization |
359
+ | `useRef` | mutable refs |
360
+ | `useContext` / `createContext` | context |
361
+ | `useLocalStorage` | state persisted to `localStorage` |
362
+ | `useFetch` | data fetching with loading/error (aliased as `useApi`) |
363
+
364
+ ```jsx
365
+ const [count, setCount] = useState(0);
366
+ const doubled = useMemo(() => count * 2, [count]);
367
+ const ref = useRef(null);
368
+ const [name, setName] = useLocalStorage('name', '');
369
+ ```
370
+
371
+ `useFetch(url, options)` returns `{ data, loading, error, status, refetch }`:
372
+
373
+ ```jsx
374
+ const { data, loading, error, status, refetch } = useFetch('/api/users');
375
+
376
+ if (loading) return <p>Loading…</p>;
377
+ if (error) return <p>{error}</p>; // error is a message string, not an Error
378
+ return <button onClick={refetch}>Retry — got {data.users.length}</button>;
379
+ ```
380
+
381
+ **Context:**
382
+
383
+ ```jsx
384
+ // components/Theme.js — createContext is global
385
+ export const ThemeContext = createContext('light');
386
+ ```
387
+
388
+ ```jsx
389
+ // app/page.js
390
+ const theme = useContext(ThemeContext);
391
+ ```
392
+
393
+ **The API client** (`window.api`) is available without imports:
394
+
395
+ ```js
396
+ const users = await api.get('/api/users');
397
+ await api.post('/api/users', { name: 'Aziz' });
398
+ ```
399
+
400
+ ### Phase 3 — Backend
401
+
402
+ API routes run in **Node**, not the browser. Two conventions are supported.
403
+
404
+ **Style A — classic `api/*.js` (CommonJS):**
405
+
406
+ ```js
407
+ // api/users.js → /api/users
408
+ const { NextResponse } = require('../_framework/next-response');
409
+
410
+ async function GET(request) {
411
+ return NextResponse.json({ users: [] });
412
+ }
413
+
414
+ async function POST(request) {
415
+ const { name, email } = await request.json();
416
+ return NextResponse.json({ created: true }, { status: 201 });
417
+ }
418
+
419
+ module.exports = { GET, POST };
420
+ ```
421
+
422
+ **Style B — Next-style `app/api/**/route.js` (ESM):**
423
+
424
+ ```js
425
+ // app/api/users/route.js → /api/users
426
+ import { NextResponse } from '../../../_framework/next-response.js';
427
+
428
+ export function GET() {
429
+ return NextResponse.json({ users: [] });
430
+ }
431
+ ```
432
+
433
+ > **Pick one module system per file.** Mixing `require()` with `export` fails: *"require is not defined in ES module scope"*.
434
+
435
+ **Dynamic API routes:**
436
+
437
+ ```js
438
+ // api/users/[id].js → /api/users/:id
439
+ const { NextResponse } = require('../_framework/next-response');
440
+
441
+ async function GET(request) {
442
+ return NextResponse.json({ id: request.params.id });
443
+ }
444
+ module.exports = { GET };
445
+ ```
446
+
447
+ Params live on `request.params` — there is no second argument to the handler. Catch-all folders (`api/files/[...path].js`) work the same way, with the value as an array.
448
+
449
+ **The `request` object** gives you `json()`, `text()`, `url`, `method`, `headers`, `cookies`, `query`, and `params`.
450
+
451
+ A handler may also return a plain object or array and it will be serialized as JSON.
452
+
453
+ Handlers you can export: `GET`, `POST`, `PUT`, `PATCH`, `DELETE`, `HEAD`, `OPTIONS`.
454
+
455
+ ### Phase 4 — Database
456
+
457
+ Server code under `lib/` and `models/` is `require`-able from API routes and is hot-reloaded on change.
458
+
459
+ ```js
460
+ // lib/db.js
461
+ const mongoose = require('mongoose');
462
+
463
+ let cached = null;
464
+ async function connectDB() {
465
+ if (cached) return cached;
466
+ cached = mongoose.connect(process.env.MONGO_URI);
467
+ return cached;
468
+ }
469
+
470
+ module.exports = { connectDB };
471
+ ```
472
+
473
+ ```js
474
+ // models/User.js
475
+ const mongoose = require('mongoose');
476
+ module.exports = mongoose.models.User || mongoose.model('User', new mongoose.Schema({
477
+ name: { type: String, required: true },
478
+ email: { type: String, required: true, unique: true }
479
+ }));
480
+ ```
481
+
482
+ ```js
483
+ // api/register.js
484
+ const bcrypt = require('bcryptjs');
485
+ const { connectDB } = require('../lib/db');
486
+ const User = require('../models/User');
487
+ const { NextResponse } = require('../_framework/next-response');
488
+
489
+ async function POST(request) {
490
+ await connectDB();
491
+ const { name, email, password } = await request.json();
492
+ const hash = await bcrypt.hash(password, 10);
493
+ const user = await User.create({ name, email, password: hash });
494
+ return NextResponse.json({ id: user.id }, { status: 201 });
495
+ }
496
+
497
+ module.exports = { POST };
498
+ ```
499
+
500
+ Any npm package works on the server — `npm install mongoose bcryptjs jsonwebtoken`, then import it normally. Client-side bare imports are rewritten to `/_modules/<pkg>` and served from `node_modules`.
501
+
502
+ ### Phase 5 — Authentication
503
+
504
+ ```js
505
+ // api/login.js
506
+ const jwt = require('jsonwebtoken');
507
+ const { NextResponse } = require('../_framework/next-response');
508
+
509
+ async function POST(request) {
510
+ const { email, password } = await request.json();
511
+ // …verify against your database…
512
+ const token = jwt.sign({ sub: user.id }, process.env.JWT_SECRET, { expiresIn: '7d' });
513
+ return NextResponse.json({ token });
514
+ }
515
+ ```
516
+
517
+ ```jsx
518
+ // app/dashboard/page.js
519
+ export default function Page() {
520
+ const [token, setToken] = useLocalStorage('token', '');
521
+ const { data, loading, error } = useFetch('/api/me');
522
+ if (!token) return <p>Please log in.</p>;
523
+ if (loading) return <p>Loading…</p>;
524
+ if (error) return <p>{error}</p>;
525
+ return <h1>Welcome, {data.name}</h1>;
526
+ }
527
+ ```
528
+
529
+ > **Do not use this for production auth.** API routes run unsandboxed Node with full filesystem access. There is no middleware layer, no CSRF protection, and no rate limiting. Add your own, or use Next.js with Auth.js.
530
+
531
+ ### Phase 6 — Production
532
+
533
+ ```bash
534
+ npm run build # production cache headers, live reload disabled
535
+ npm start
536
+ ```
537
+
538
+ `npm run build` is **not** a bundler. It does not minify, tree-shake, or code-split, and there is no build artifact — it starts the same Node server with production caching. Deploy as a long-running Node process and put a CDN in front of it. You must supply process-level concerns yourself: TLS, compression, rate limiting, logging, and monitoring.
539
+
540
+ ---
541
+
542
+ ## API reference
543
+
544
+ **Globals available in every page/component (no imports):**
545
+
546
+ `h`, `Fragment`, `api`, `Link`, `navigate`, `replace`, `back`, `forward`, `refresh`, `redirect`, `notFound`, `useRouter`, `usePathname`, `useParams`, `useSearchParams`, `useNavigation`, `useTransition`, `useState`, `useReducer`, `useEffect`, `useMemo`, `useCallback`, `useRef`, `useContext`, `createContext`, `useLocalStorage`, `useFetch`, `useApi`
547
+
548
+ ---
549
+
550
+ ## Security model — read this before deploying
551
+
552
+ Aziz.js has **no bundler**. Every module a page can import is served straight from disk as an ES module — that is exactly how `import User from '@/models/User'` works. It also means a file on disk is one HTTP request away, so the dev server enforces a boundary between *code the browser may import* and *everything else*.
553
+
554
+ **Never served** (HTTP 404, in both dev and production):
555
+
556
+ | Rule | Examples |
557
+ | --- | --- |
558
+ | Any dotfile or dot-directory | `.env`, `.env.local`, `.env.production`, `.git/config`, `.npmrc` |
559
+ | Project metadata | `package.json`, `package-lock.json`, `tsconfig.json`, `yarn.lock` |
560
+ | `node_modules/` | reachable only via `/_modules/<pkg>` |
561
+ | `server/` | your server-only modules |
562
+ | `data/` | flat-file persistence (sessions, users) |
563
+ | `*.server.js` / `*.server.mjs` / `*.server.jsx` | individually marked server-only |
564
+ | `scripts/` except `live-reload-client.js` | the dev server itself |
565
+
566
+ **Served normally:** anything under `app/`, `components/`, `models/`, `lib/`, `styles/`, `_framework/`, and `index.html`. `lib/` and `models/` are client-importable *by design*, so the framework cannot hide them.
567
+
568
+ > ### The one rule that matters
569
+ > **If a module is only ever used by an API route, move it into `server/` or rename it `*.server.mjs`.**
570
+ >
571
+ > ```js
572
+ > // BEFORE — reachable at /lib/auth-store.mjs
573
+ > export function createSession() { /* … */ }
574
+ > // AFTER — 404s
575
+ > export function createSession() { /* … */ }
576
+ > ```
577
+ > ```js
578
+ > // api/login.js
579
+ > import { createSession } from '../server/auth-store.mjs'; // or ../lib/auth-store.server.mjs
580
+ > ```
581
+ > A leaked `.env` hands over your database password and JWT secret to anyone who requests it. Treat this convention as mandatory, not stylistic.
582
+
583
+ **What the framework does not protect against.** API routes run unsandboxed Node with full filesystem access. There is no CSRF protection, no rate limiting, no auth middleware, and no input validation layer. Add your own before going to production.
584
+
585
+ **Import styles:**
586
+
587
+ | Style | Example | Resolves |
588
+ | --- | --- | --- |
589
+ | Absolute | `import X from '/components/X.js'` | project root |
590
+ | Alias | `import X from '@/models/X'` | project root |
591
+ | Relative | `import X from './X.js'` | relative to the file |
592
+ | Bare | `import mongoose from 'mongoose'` | `/_modules/mongoose` → `node_modules` |
593
+
594
+ **Dev-server routes:**
595
+
596
+ | Path | Purpose |
597
+ | --- | --- |
598
+ | `/_framework/routes.json` | the generated page/layout/not-found manifest |
599
+ | `/api/**` | your API routes |
600
+ | `/_modules/*` | bare node_modules imports |
601
+ | any extensionless path | SPA fallback → `index.html` |
602
+
603
+ ---
604
+
605
+ ## Known limitations (read this)
606
+
607
+ Stated plainly, because a framework README that only lists strengths is marketing, not documentation.
608
+
609
+ 1. **No server-side rendering.** The served HTML contains `<div id="root"></div>` and nothing else. Bad for SEO and slow first paint on poor connections.
610
+ 2. **No static generation**, no ISR, no incremental regeneration.
611
+ 3. **No React Server Components, no streaming, no Suspense.**
612
+ 4. **TypeScript is not supported.** `.ts`/`.tsx` files are ignored by the route scanner — the route simply 404s with no warning. JS only.
613
+ 5. **No bundler.** Nothing is minified, tree-shaken, or code-split. Large apps pay full cost on every page load.
614
+ 6. **No route prefetching.** Every navigation re-fetches and re-renders.
615
+ 7. **No image or font optimization.**
616
+ 8. **No middleware/proxy layer**, no edge runtime, no i18n routing.
617
+ 9. **No CSRF, rate limiting, or auth layer** — see [Security model](#security-model--read-this-before-deploying).
618
+ 10. **No test runner or build pipeline** included.
619
+ 11. **`@babel/standalone` is 36.7 MB** and is mandatory.
620
+ 12. **Single-maintainer project** with no security-response process.
621
+ 13. **Not battle-tested.** Use it for learning and prototypes; validate hard before production traffic.
622
+
623
+ ## Gotchas
624
+
625
+ - **`lib/` and `models/` are public.** They must stay client-importable, so anything server-only in them is reachable over HTTP. Move those modules to `server/` or name them `*.server.mjs` — see [Security model](#security-model--read-this-before-deploying).
626
+ - **`/app/page.js` returning your code is expected.** With no bundler, page modules *are* the browser payload. That is not a leak; it is only compiled JSX with no secrets. The real leaks were `.env` and server-only modules, and both are now blocked.
627
+ - **Server routes need relative imports.** Inside `api/**` and `app/api/**`, `import … from '/_framework/next-response.js'` fails — those files run in Node, not the browser. Use `require('../_framework/next-response')` or a correct relative path.
628
+ - **A named ESM import does work** for `NextResponse`; you do not need the `const { NextResponse } = defaultImport` dance:
629
+ ```js
630
+ import { NextResponse } from '../../_framework/next-response.js';
631
+ ```
632
+ - **Do not mix `require()` and `export`** in one API route file.
633
+ - **`.jsx` is supported for pages, layouts, API routes, `loading.js`, `error.js` and `404.js`.** The old manifest bug that hardcoded the `.js` path is fixed — the manifest now points at the real filename.
634
+ - **Directory names are case-sensitive.**
635
+ - **Catch-all routes must be the final segment** and require at least one segment.
636
+ - **Restart the dev server after `npm install`.** The Babel lookup happens once at process start and is never retried.
637
+ - **Pin `@babel/standalone` to `^7`.** Do not run a bare `npm install --save-dev @babel/standalone` on an existing project — that now resolves **v8**, whose default *automatic* JSX runtime conflicts with the classic `h()`/`Fragment` compilation this framework relies on. v3.1.2 works with either major, but the template pins `^7.0.0`; leave it alone unless you have tested it.
638
+ - **`useFetch` caches GET responses for 5 seconds.** Navigating away and back, or swapping `loading.js` out for a page, will not re-hit the API inside that window. Call `refetch()` to force it, or `clearFetchCache()` (global) to drop everything.
639
+ - **Known upstream issue on Windows:** Node's directory watcher can abort the whole process at startup with `Assertion failed: !_wcsnicmp(filename, dir, dirlen)` (from `src\win\fs-event.c`). It is a native assertion that `try/catch` cannot intercept. Measured on this machine: roughly **1 start in 8** on projects with nested subdirectories (e.g. `app/blog/[slug]`), and 0 in 5 on a flat project. It is **not** caused by `recursive: true` — a non-recursive watcher hits it too — so switching watcher strategy does not help. Just restart the dev server.
640
+
641
+ ## Troubleshooting
642
+
643
+ | Symptom | Cause | Fix |
644
+ | --- | --- | --- |
645
+ | Server dies instantly on Windows, `Assertion failed: !_wcsnicmp` | Node's native directory watcher (upstream bug) | Restart the dev server |
646
+ | 404 on **every** page | `npm install` was never run — JSX is served raw and the module import fails | `npm install`, then **restart** the dev server |
647
+ | 404 on one page only | File is not `page.js` (e.g. `index.js` or `page.tsx`) | Rename to `app/<route>/page.js` |
648
+ | 404 on a `server/`, `data/`, `.env` or `*.server.mjs` path | Working as intended — these are never served | Import them from an API route, not a page |
649
+ | A spinner flashes for a moment | A route crossed the 200 ms guard | Delete the nearest `loading.js` — absence is the opt-out |
650
+ | "JSX transform error" | Syntax error in a page or component | Fix the syntax; the message names the file |
651
+ | "Module not found" | Bare import not installed | `npm install <package>` |
652
+ | API route 404 | File not discovered, or `require`/`export` mixed | Check the `api/` or `app/api/` path and module style |
653
+ | Port already in use | The server auto-increments the port | Note the URL it prints, or set `PORT` |
654
+
655
+ ---
656
+
657
+ **Author:** Syed Muhammad Aziz Ahmed
658
+ **License:** MIT