create-aziz-app 2.0.11 → 2.0.13
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/package.json +3 -2
- package/template/README.md +26 -28
- package/template/api/hello.js +19 -7
- package/template/api/users.js +133 -40
- package/template/app.html +21 -25
- package/template/components/Navbar.jsx +7 -6
- package/template/docs/API-ROUTES.md +538 -0
- package/template/docs/NEXTJS-COMPARISON.md +473 -0
- package/template/modules/api.js +20 -124
- package/template/modules/state.js +225 -31
- package/template/pages/HooksDemo.jsx +194 -0
- package/template/scripts/dev-server.js +170 -1
- package/template/scripts/generate-imports.js +0 -10
package/package.json
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-aziz-app",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.13",
|
|
4
4
|
"description": "A React-like framework with state management, routing, and API routes - Create apps with auto-import, live reload, and Next.js-like features",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react",
|
|
7
|
+
"full-stack",
|
|
7
8
|
"framework",
|
|
8
9
|
"cli",
|
|
9
10
|
"create-app",
|
|
@@ -12,7 +13,7 @@
|
|
|
12
13
|
"api-routes",
|
|
13
14
|
"live-reload"
|
|
14
15
|
],
|
|
15
|
-
"license": "
|
|
16
|
+
"license": "AZIZ",
|
|
16
17
|
"author": "Syed Muhammad Aziz Ahmed",
|
|
17
18
|
"type": "commonjs",
|
|
18
19
|
"files": [
|
package/template/README.md
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
|
-
# Aziz App -
|
|
1
|
+
# Aziz App - Lightweight Next.js Clone
|
|
2
2
|
|
|
3
|
-
A
|
|
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**!
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
Next.js: ~400KB + 20 dependencies
|
|
7
|
+
Aziz App: ~50KB + 0 dependencies
|
|
8
|
+
```
|
|
4
9
|
|
|
5
10
|
## 📁 Project Structure
|
|
6
11
|
|
|
@@ -96,39 +101,31 @@ function ProfilePage() {
|
|
|
96
101
|
|
|
97
102
|
## ✨ Features
|
|
98
103
|
|
|
99
|
-
###
|
|
100
|
-
```javascript
|
|
101
|
-
// Just name your function with "Page" suffix
|
|
102
|
-
function AboutPage() {
|
|
103
|
-
return <div><h1>About</h1></div>;
|
|
104
|
-
}
|
|
105
|
-
// Automatically becomes route "#/about"
|
|
106
|
-
```
|
|
107
|
-
|
|
108
|
-
### State Management
|
|
104
|
+
### React Hooks (Identical to Next.js!)
|
|
109
105
|
```javascript
|
|
110
106
|
const [count, setCount] = useState(0);
|
|
111
107
|
const [name, setName] = useState('');
|
|
112
|
-
```
|
|
113
108
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
function HomePage() { } // → #/home
|
|
109
|
+
useEffect(() => {
|
|
110
|
+
console.log('Mounted!');
|
|
111
|
+
}, []);
|
|
118
112
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
navigate("about");
|
|
113
|
+
const memoized = useMemo(() => expensive(), [dep]);
|
|
114
|
+
const callback = useCallback(() => action(), [dep]);
|
|
115
|
+
const ref = useRef(null);
|
|
116
|
+
const [state, dispatch] = useReducer(reducer, initial);
|
|
124
117
|
```
|
|
125
118
|
|
|
119
|
+
**All hooks work exactly like React/Next.js!**
|
|
120
|
+
|
|
126
121
|
### API Routes
|
|
127
122
|
```javascript
|
|
128
|
-
// api/todos.js
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
});
|
|
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: [] });
|
|
127
|
+
}
|
|
128
|
+
};
|
|
132
129
|
|
|
133
130
|
// Use in components
|
|
134
131
|
const response = await fetchApi('/api/todos');
|
|
@@ -150,13 +147,14 @@ The CLI will automatically set up your chosen framework!
|
|
|
150
147
|
|
|
151
148
|
## 📚 Documentation
|
|
152
149
|
|
|
150
|
+
- **[Next.js Comparison](docs/NEXTJS-COMPARISON.md)** - How it compares to Next.js
|
|
153
151
|
- **[Getting Started](docs/GETTING-STARTED.md)** - Complete setup guide
|
|
154
152
|
- **[Auto-Registration](docs/AUTO-REGISTRATION.md)** - How pages auto-register
|
|
155
|
-
- **[API
|
|
153
|
+
- **[API Routes](docs/API-ROUTES.md)** - Server-side API endpoints (like Next.js!)
|
|
156
154
|
- **[Auto-Import](docs/AUTO-IMPORT.md)** - Auto-import system details
|
|
157
155
|
- **[Dev Server](docs/DEV-SERVER.md)** - Live reload and development
|
|
156
|
+
- **[How It Works](docs/HOW-IT-WORKS.md)** - System architecture
|
|
158
157
|
- **[Troubleshooting](docs/TROUBLESHOOTING.md)** - Fix common issues
|
|
159
|
-
- **[Quick Start](docs/QUICK-START.md)** - Quick examples
|
|
160
158
|
|
|
161
159
|
## 🛠️ Commands
|
|
162
160
|
|
package/template/api/hello.js
CHANGED
|
@@ -1,14 +1,26 @@
|
|
|
1
|
-
|
|
1
|
+
// API Route: /api/hello
|
|
2
|
+
// Simple Next.js-style API route
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
|
|
4
|
+
export default async function handler(req, res) {
|
|
5
|
+
const { method, query } = req;
|
|
5
6
|
|
|
6
|
-
|
|
7
|
-
|
|
7
|
+
if (method !== 'GET') {
|
|
8
|
+
res.setHeader('Allow', ['GET']);
|
|
9
|
+
return res.status(405).json({
|
|
10
|
+
error: 'Method not allowed',
|
|
11
|
+
message: `Method ${method} is not allowed. Use GET instead.`
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const name = query.name || 'World';
|
|
8
16
|
|
|
9
17
|
return res.status(200).json({
|
|
10
18
|
message: `Hello, ${name}!`,
|
|
11
19
|
timestamp: new Date().toISOString(),
|
|
12
|
-
method:
|
|
20
|
+
method: method,
|
|
21
|
+
query: query
|
|
13
22
|
});
|
|
14
|
-
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// CommonJS export for Node.js compatibility
|
|
26
|
+
module.exports = handler;
|
package/template/api/users.js
CHANGED
|
@@ -1,62 +1,155 @@
|
|
|
1
|
-
|
|
1
|
+
// API Route: /api/users
|
|
2
|
+
// Next.js-style API route handler
|
|
2
3
|
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
{ id: 1, name: 'Aziz Ahmed', email: 'aziz@example.com' },
|
|
9
|
-
{ id: 2, name: 'John Doe', email: 'john@example.com' },
|
|
10
|
-
{ id: 3, name: 'Jane Smith', email: 'jane@example.com' }
|
|
4
|
+
// Mock database (in production, use a real database)
|
|
5
|
+
let users = [
|
|
6
|
+
{ id: 1, name: 'Aziz Ahmed', email: 'aziz@example.com', createdAt: new Date().toISOString() },
|
|
7
|
+
{ id: 2, name: 'John Doe', email: 'john@example.com', createdAt: new Date().toISOString() },
|
|
8
|
+
{ id: 3, name: 'Jane Smith', email: 'jane@example.com', createdAt: new Date().toISOString() }
|
|
11
9
|
];
|
|
12
10
|
|
|
13
|
-
//
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
11
|
+
// Next.js-style default export
|
|
12
|
+
export default async function handler(req, res) {
|
|
13
|
+
const { method, query, body } = req;
|
|
14
|
+
|
|
15
|
+
switch (method) {
|
|
17
16
|
case 'GET':
|
|
18
|
-
//
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
17
|
+
// GET /api/users - Get all users
|
|
18
|
+
// GET /api/users?id=1 - Get specific user
|
|
19
|
+
if (query.id) {
|
|
20
|
+
const user = users.find(u => u.id === parseInt(query.id));
|
|
21
|
+
if (!user) {
|
|
22
|
+
return res.status(404).json({
|
|
23
|
+
error: 'User not found',
|
|
24
|
+
message: `No user found with id ${query.id}`
|
|
25
|
+
});
|
|
25
26
|
}
|
|
27
|
+
return res.status(200).json(user);
|
|
26
28
|
}
|
|
27
|
-
|
|
29
|
+
|
|
30
|
+
// Return all users
|
|
31
|
+
return res.status(200).json({
|
|
32
|
+
users,
|
|
33
|
+
total: users.length,
|
|
34
|
+
timestamp: new Date().toISOString()
|
|
35
|
+
});
|
|
28
36
|
|
|
29
37
|
case 'POST':
|
|
30
|
-
// Create
|
|
38
|
+
// POST /api/users - Create new user
|
|
39
|
+
const { name, email } = body;
|
|
40
|
+
|
|
41
|
+
// Validation
|
|
42
|
+
if (!name || !email) {
|
|
43
|
+
return res.status(400).json({
|
|
44
|
+
error: 'Validation error',
|
|
45
|
+
message: 'Name and email are required',
|
|
46
|
+
fields: {
|
|
47
|
+
name: !name ? 'Name is required' : null,
|
|
48
|
+
email: !email ? 'Email is required' : null
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (!email.includes('@')) {
|
|
54
|
+
return res.status(400).json({
|
|
55
|
+
error: 'Validation error',
|
|
56
|
+
message: 'Invalid email format'
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Check if email already exists
|
|
61
|
+
if (users.find(u => u.email === email)) {
|
|
62
|
+
return res.status(409).json({
|
|
63
|
+
error: 'Conflict',
|
|
64
|
+
message: 'User with this email already exists'
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Create new user
|
|
31
69
|
const newUser = {
|
|
32
|
-
id: users.length + 1,
|
|
33
|
-
name
|
|
34
|
-
email
|
|
70
|
+
id: users.length > 0 ? Math.max(...users.map(u => u.id)) + 1 : 1,
|
|
71
|
+
name,
|
|
72
|
+
email,
|
|
73
|
+
createdAt: new Date().toISOString()
|
|
35
74
|
};
|
|
75
|
+
|
|
36
76
|
users.push(newUser);
|
|
37
|
-
|
|
77
|
+
|
|
78
|
+
return res.status(201).json({
|
|
79
|
+
message: 'User created successfully',
|
|
80
|
+
user: newUser
|
|
81
|
+
});
|
|
38
82
|
|
|
39
83
|
case 'PUT':
|
|
40
|
-
// Update
|
|
41
|
-
const userId =
|
|
84
|
+
// PUT /api/users?id=1 - Update user
|
|
85
|
+
const userId = query.id || body.id;
|
|
86
|
+
|
|
87
|
+
if (!userId) {
|
|
88
|
+
return res.status(400).json({
|
|
89
|
+
error: 'Bad request',
|
|
90
|
+
message: 'User ID is required'
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
|
|
42
94
|
const userIndex = users.findIndex(u => u.id === parseInt(userId));
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
return res.status(
|
|
95
|
+
|
|
96
|
+
if (userIndex === -1) {
|
|
97
|
+
return res.status(404).json({
|
|
98
|
+
error: 'User not found',
|
|
99
|
+
message: `No user found with id ${userId}`
|
|
100
|
+
});
|
|
46
101
|
}
|
|
47
|
-
|
|
102
|
+
|
|
103
|
+
// Update user
|
|
104
|
+
users[userIndex] = {
|
|
105
|
+
...users[userIndex],
|
|
106
|
+
...body,
|
|
107
|
+
id: users[userIndex].id, // Prevent ID change
|
|
108
|
+
updatedAt: new Date().toISOString()
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
return res.status(200).json({
|
|
112
|
+
message: 'User updated successfully',
|
|
113
|
+
user: users[userIndex]
|
|
114
|
+
});
|
|
48
115
|
|
|
49
116
|
case 'DELETE':
|
|
50
|
-
// Delete
|
|
51
|
-
const deleteId =
|
|
117
|
+
// DELETE /api/users?id=1 - Delete user
|
|
118
|
+
const deleteId = query.id;
|
|
119
|
+
|
|
120
|
+
if (!deleteId) {
|
|
121
|
+
return res.status(400).json({
|
|
122
|
+
error: 'Bad request',
|
|
123
|
+
message: 'User ID is required'
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
|
|
52
127
|
const deleteIndex = users.findIndex(u => u.id === parseInt(deleteId));
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
return res.status(
|
|
128
|
+
|
|
129
|
+
if (deleteIndex === -1) {
|
|
130
|
+
return res.status(404).json({
|
|
131
|
+
error: 'User not found',
|
|
132
|
+
message: `No user found with id ${deleteId}`
|
|
133
|
+
});
|
|
56
134
|
}
|
|
57
|
-
|
|
135
|
+
|
|
136
|
+
const deletedUser = users.splice(deleteIndex, 1)[0];
|
|
137
|
+
|
|
138
|
+
return res.status(200).json({
|
|
139
|
+
message: 'User deleted successfully',
|
|
140
|
+
user: deletedUser
|
|
141
|
+
});
|
|
58
142
|
|
|
59
143
|
default:
|
|
60
|
-
|
|
144
|
+
// Method not allowed
|
|
145
|
+
res.setHeader('Allow', ['GET', 'POST', 'PUT', 'DELETE']);
|
|
146
|
+
return res.status(405).json({
|
|
147
|
+
error: 'Method not allowed',
|
|
148
|
+
message: `Method ${method} is not allowed for this endpoint`,
|
|
149
|
+
allowedMethods: ['GET', 'POST', 'PUT', 'DELETE']
|
|
150
|
+
});
|
|
61
151
|
}
|
|
62
|
-
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// CommonJS export for Node.js compatibility
|
|
155
|
+
module.exports = handler;
|
package/template/app.html
CHANGED
|
@@ -28,31 +28,27 @@
|
|
|
28
28
|
<!-- Footer is always visible -->
|
|
29
29
|
<div id="footer"></div>
|
|
30
30
|
|
|
31
|
-
<!-- Load core modules -->
|
|
32
|
-
<script type="text/babel" src="modules/router.js"></script>
|
|
33
|
-
<script type="text/babel" src="modules/state.js"></script>
|
|
34
|
-
<script type="text/babel" src="modules/api.js"></script>
|
|
35
|
-
|
|
36
|
-
<!-- Load
|
|
37
|
-
<script type="text/babel" src="
|
|
38
|
-
<script type="text/babel" src="
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
<script type="text/babel" src="
|
|
43
|
-
<script type="text/babel" src="
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
<script type="text/babel" src="pages/
|
|
47
|
-
<script type="text/babel" src="pages/
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
<script type="text/babel"
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
<!-- Start the app -->
|
|
54
|
-
<script type="text/babel">
|
|
55
|
-
startApp();
|
|
31
|
+
<!-- Load core modules -->
|
|
32
|
+
<script type="text/babel" src="modules/router.js"></script>
|
|
33
|
+
<script type="text/babel" src="modules/state.js"></script>
|
|
34
|
+
<script type="text/babel" src="modules/api.js"></script>
|
|
35
|
+
|
|
36
|
+
<!-- Load shared components -->
|
|
37
|
+
<script type="text/babel" src="components/Counter.jsx"></script>
|
|
38
|
+
<script type="text/babel" src="components/Footer.jsx"></script>
|
|
39
|
+
<script type="text/babel" src="components/Navbar.jsx"></script>
|
|
40
|
+
|
|
41
|
+
<!-- Load pages -->
|
|
42
|
+
<script type="text/babel" src="pages/About.jsx"></script>
|
|
43
|
+
<script type="text/babel" src="pages/ApiDemo.jsx"></script>
|
|
44
|
+
<script type="text/babel" src="pages/Contact.jsx"></script>
|
|
45
|
+
<script type="text/babel" src="pages/Example.jsx"></script>
|
|
46
|
+
<script type="text/babel" src="pages/Home.jsx"></script>
|
|
47
|
+
<script type="text/babel" src="pages/test.jsx"></script>
|
|
48
|
+
|
|
49
|
+
<!-- Start the app -->
|
|
50
|
+
<script type="text/babel">
|
|
51
|
+
startApp();
|
|
56
52
|
</script>
|
|
57
53
|
|
|
58
54
|
</body>
|
|
@@ -5,12 +5,13 @@ function Navbar() {
|
|
|
5
5
|
|
|
6
6
|
return (
|
|
7
7
|
<nav>
|
|
8
|
-
<span class="brand" onClick={() => navigate("home")}>⚡
|
|
9
|
-
<a href="#/home"
|
|
10
|
-
<a href="#/about"
|
|
11
|
-
<a href="#/
|
|
12
|
-
<a href="#/
|
|
13
|
-
<a href="#/api-demo"
|
|
8
|
+
<span class="brand" onClick={() => navigate("home")}>⚡ AzizApp</span>
|
|
9
|
+
<a href="#/home" class={path === "home" ? "active" : ""}>Home</a>
|
|
10
|
+
<a href="#/about" class={path === "about" ? "active" : ""}>About</a>
|
|
11
|
+
<a href="#/test" class={path === "test" ? "active" : ""}>Test</a>
|
|
12
|
+
<a href="#/hooks-demo" class={path === "hooks-demo" ? "active" : ""}>Hooks</a>
|
|
13
|
+
<a href="#/api-demo" class={path === "api-demo" ? "active" : ""}>API Demo</a>
|
|
14
|
+
<a href="#/contact" class={path === "contact" ? "active" : ""}>Contact</a>
|
|
14
15
|
</nav>
|
|
15
16
|
);
|
|
16
17
|
}
|