create-aziz-app 2.0.7 → 2.0.8
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 +1 -1
- package/template/README.md +22 -6
- package/template/app.html +1 -0
- package/template/docs/AUTO-REGISTRATION.md +248 -0
- package/template/docs/DEV-SERVER.md +98 -0
- package/template/modules/router.js +28 -5
- package/template/pages/About.jsx +17 -2
- package/template/pages/ApiDemo.jsx +1 -1
- package/template/pages/Contact.jsx +1 -3
- package/template/pages/Example.jsx +59 -0
- package/template/pages/Home.jsx +1 -2
- package/template/pages/test.jsx +1 -2
- package/template/scripts/dev-server.js +99 -17
package/package.json
CHANGED
package/template/README.md
CHANGED
|
@@ -72,8 +72,7 @@ Just create files in the appropriate folders - they're automatically imported!
|
|
|
72
72
|
// pages/Profile.jsx
|
|
73
73
|
/** @jsx h */
|
|
74
74
|
|
|
75
|
-
|
|
76
|
-
|
|
75
|
+
// Auto-registers as "#/profile" - no registerPage() needed!
|
|
77
76
|
function ProfilePage() {
|
|
78
77
|
const [name, setName] = useState('');
|
|
79
78
|
|
|
@@ -93,8 +92,19 @@ function ProfilePage() {
|
|
|
93
92
|
|
|
94
93
|
**Navigate to:** `http://localhost:3000/#/profile`
|
|
95
94
|
|
|
95
|
+
✨ **That's it!** No `registerPage()` call needed. Just name your function `YourNamePage()` and it auto-registers!
|
|
96
|
+
|
|
96
97
|
## ✨ Features
|
|
97
98
|
|
|
99
|
+
### Auto-Registration ⚡
|
|
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
|
+
|
|
98
108
|
### State Management
|
|
99
109
|
```javascript
|
|
100
110
|
const [count, setCount] = useState(0);
|
|
@@ -103,8 +113,11 @@ const [name, setName] = useState('');
|
|
|
103
113
|
|
|
104
114
|
### Routing
|
|
105
115
|
```javascript
|
|
106
|
-
//
|
|
107
|
-
|
|
116
|
+
// Auto-registers based on function name
|
|
117
|
+
function HomePage() { } // → #/home
|
|
118
|
+
|
|
119
|
+
// Or manually register for custom names
|
|
120
|
+
registerPage("user-profile", UserProfilePage);
|
|
108
121
|
|
|
109
122
|
// Navigate
|
|
110
123
|
navigate("about");
|
|
@@ -138,8 +151,10 @@ The CLI will automatically set up your chosen framework!
|
|
|
138
151
|
## 📚 Documentation
|
|
139
152
|
|
|
140
153
|
- **[Getting Started](docs/GETTING-STARTED.md)** - Complete setup guide
|
|
154
|
+
- **[Auto-Registration](docs/AUTO-REGISTRATION.md)** - How pages auto-register
|
|
141
155
|
- **[API Guide](docs/API-GUIDE.md)** - How to create API routes
|
|
142
156
|
- **[Auto-Import](docs/AUTO-IMPORT.md)** - Auto-import system details
|
|
157
|
+
- **[Dev Server](docs/DEV-SERVER.md)** - Live reload and development
|
|
143
158
|
- **[Quick Start](docs/QUICK-START.md)** - Quick examples
|
|
144
159
|
|
|
145
160
|
## 🛠️ Commands
|
|
@@ -153,8 +168,9 @@ npm run build # Generate imports manually
|
|
|
153
168
|
|
|
154
169
|
### Pages
|
|
155
170
|
- Files in `pages/` become routes
|
|
156
|
-
-
|
|
157
|
-
-
|
|
171
|
+
- Name functions with "Page" suffix (e.g., `AboutPage`)
|
|
172
|
+
- Auto-registers as route (e.g., `#/about`)
|
|
173
|
+
- Optional: Use `registerPage("custom-name", Component)` for custom routes
|
|
158
174
|
|
|
159
175
|
### Components
|
|
160
176
|
- Reusable UI components
|
package/template/app.html
CHANGED
|
@@ -40,6 +40,7 @@
|
|
|
40
40
|
<script type="text/babel" src="pages/About.jsx"></script>
|
|
41
41
|
<script type="text/babel" src="pages/ApiDemo.jsx"></script>
|
|
42
42
|
<script type="text/babel" src="pages/Contact.jsx"></script>
|
|
43
|
+
<script type="text/babel" src="pages/Example.jsx"></script>
|
|
43
44
|
<script type="text/babel" src="pages/Home.jsx"></script>
|
|
44
45
|
<script type="text/babel" src="pages/test.jsx"></script>
|
|
45
46
|
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
# Auto-Registration Guide
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Pages automatically register themselves based on their function name. No need to call `registerPage()` manually!
|
|
6
|
+
|
|
7
|
+
## How It Works
|
|
8
|
+
|
|
9
|
+
### ✨ Automatic Registration
|
|
10
|
+
|
|
11
|
+
Just name your page function with "Page" at the end:
|
|
12
|
+
|
|
13
|
+
```jsx
|
|
14
|
+
/** @jsx h */
|
|
15
|
+
|
|
16
|
+
// That's it! Automatically becomes route "#/example"
|
|
17
|
+
function ExamplePage() {
|
|
18
|
+
return (
|
|
19
|
+
<div>
|
|
20
|
+
<h1>Example Page</h1>
|
|
21
|
+
<p>This page auto-registered!</p>
|
|
22
|
+
</div>
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### Function Name → Route Mapping
|
|
28
|
+
|
|
29
|
+
The system converts your function name to a route:
|
|
30
|
+
|
|
31
|
+
| Function Name | Auto Route | URL |
|
|
32
|
+
|--------------|------------|-----|
|
|
33
|
+
| `HomePage()` | `home` | `#/home` |
|
|
34
|
+
| `AboutPage()` | `about` | `#/about` |
|
|
35
|
+
| `ContactPage()` | `contact` | `#/contact` |
|
|
36
|
+
| `UserProfilePage()` | `userprofile` | `#/userprofile` |
|
|
37
|
+
| `MyAwesomePage()` | `myawesome` | `#/myawesome` |
|
|
38
|
+
|
|
39
|
+
**Rule:** Remove "Page" suffix and convert to lowercase.
|
|
40
|
+
|
|
41
|
+
## Manual Registration (Optional)
|
|
42
|
+
|
|
43
|
+
You can still manually register for custom route names:
|
|
44
|
+
|
|
45
|
+
```jsx
|
|
46
|
+
/** @jsx h */
|
|
47
|
+
|
|
48
|
+
// Custom route name with dashes or different naming
|
|
49
|
+
registerPage("user-profile", UserProfilePage);
|
|
50
|
+
|
|
51
|
+
function UserProfilePage() {
|
|
52
|
+
return <div><h1>User Profile</h1></div>;
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### When to Use Manual Registration
|
|
57
|
+
|
|
58
|
+
- **Custom route names** with dashes: `"api-demo"`, `"user-settings"`
|
|
59
|
+
- **Multiple routes** pointing to same component
|
|
60
|
+
- **Override auto-registration** with different name
|
|
61
|
+
|
|
62
|
+
## Examples
|
|
63
|
+
|
|
64
|
+
### Example 1: Simple Auto Page
|
|
65
|
+
|
|
66
|
+
```jsx
|
|
67
|
+
/** @jsx h */
|
|
68
|
+
|
|
69
|
+
function ProductsPage() {
|
|
70
|
+
return (
|
|
71
|
+
<div>
|
|
72
|
+
<h1>Products</h1>
|
|
73
|
+
<p>Browse our products</p>
|
|
74
|
+
</div>
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Access at: `#/products`
|
|
80
|
+
|
|
81
|
+
### Example 2: With State
|
|
82
|
+
|
|
83
|
+
```jsx
|
|
84
|
+
/** @jsx h */
|
|
85
|
+
|
|
86
|
+
function DashboardPage() {
|
|
87
|
+
const [count, setCount] = useState(0);
|
|
88
|
+
|
|
89
|
+
return (
|
|
90
|
+
<div>
|
|
91
|
+
<h1>Dashboard</h1>
|
|
92
|
+
<p>Count: {count}</p>
|
|
93
|
+
<button onClick={() => setCount(count + 1)}>
|
|
94
|
+
Increment
|
|
95
|
+
</button>
|
|
96
|
+
</div>
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Access at: `#/dashboard`
|
|
102
|
+
|
|
103
|
+
### Example 3: Manual Registration
|
|
104
|
+
|
|
105
|
+
```jsx
|
|
106
|
+
/** @jsx h */
|
|
107
|
+
|
|
108
|
+
// Want route "#/user-settings" instead of "#/usersettings"
|
|
109
|
+
registerPage("user-settings", UserSettingsPage);
|
|
110
|
+
|
|
111
|
+
function UserSettingsPage() {
|
|
112
|
+
return (
|
|
113
|
+
<div>
|
|
114
|
+
<h1>User Settings</h1>
|
|
115
|
+
</div>
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Access at: `#/user-settings`
|
|
121
|
+
|
|
122
|
+
## Creating a New Page
|
|
123
|
+
|
|
124
|
+
### Step 1: Create the file
|
|
125
|
+
|
|
126
|
+
Create `pages/MyNewPage.jsx`:
|
|
127
|
+
|
|
128
|
+
```jsx
|
|
129
|
+
/** @jsx h */
|
|
130
|
+
|
|
131
|
+
function MyNewPage() {
|
|
132
|
+
return (
|
|
133
|
+
<div>
|
|
134
|
+
<h1>My New Page</h1>
|
|
135
|
+
<div class="card">
|
|
136
|
+
<p>This is my new page!</p>
|
|
137
|
+
</div>
|
|
138
|
+
</div>
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Step 2: That's it!
|
|
144
|
+
|
|
145
|
+
The dev server will:
|
|
146
|
+
1. Detect the new file
|
|
147
|
+
2. Auto-generate the import in `app.html`
|
|
148
|
+
3. Auto-register the route as `#/mynew`
|
|
149
|
+
4. Reload the browser
|
|
150
|
+
|
|
151
|
+
Navigate to `#/mynew` and your page appears!
|
|
152
|
+
|
|
153
|
+
## Debugging
|
|
154
|
+
|
|
155
|
+
### Check Auto-Registration
|
|
156
|
+
|
|
157
|
+
Open browser console when the app starts. You'll see:
|
|
158
|
+
|
|
159
|
+
```
|
|
160
|
+
📄 Auto-registered: home → HomePage()
|
|
161
|
+
📄 Auto-registered: about → AboutPage()
|
|
162
|
+
📄 Auto-registered: contact → ContactPage()
|
|
163
|
+
📄 Auto-registered: mynew → MyNewPage()
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Page Not Found?
|
|
167
|
+
|
|
168
|
+
1. **Check function name** - Must end with "Page"
|
|
169
|
+
2. **Check file is loaded** - Look in `app.html` for the script tag
|
|
170
|
+
3. **Check console** - Look for auto-registration message
|
|
171
|
+
4. **Try manual registration** - Use `registerPage("route", ComponentPage)`
|
|
172
|
+
|
|
173
|
+
## Best Practices
|
|
174
|
+
|
|
175
|
+
### ✅ Do This
|
|
176
|
+
|
|
177
|
+
```jsx
|
|
178
|
+
// Clear, descriptive names
|
|
179
|
+
function HomePage() { }
|
|
180
|
+
function AboutPage() { }
|
|
181
|
+
function ContactPage() { }
|
|
182
|
+
function UserProfilePage() { }
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### ❌ Avoid This
|
|
186
|
+
|
|
187
|
+
```jsx
|
|
188
|
+
// Won't auto-register (missing "Page" suffix)
|
|
189
|
+
function Home() { }
|
|
190
|
+
function About() { }
|
|
191
|
+
|
|
192
|
+
// Will create weird routes
|
|
193
|
+
function Page() { } // route: "" (empty)
|
|
194
|
+
function MyPage() { } // route: "my" (too generic)
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
## Migration Guide
|
|
198
|
+
|
|
199
|
+
### Old Way (Still Works)
|
|
200
|
+
|
|
201
|
+
```jsx
|
|
202
|
+
/** @jsx h */
|
|
203
|
+
|
|
204
|
+
registerPage("about", AboutPage);
|
|
205
|
+
|
|
206
|
+
function AboutPage() {
|
|
207
|
+
return <div><h1>About</h1></div>;
|
|
208
|
+
}
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### New Way (Simpler)
|
|
212
|
+
|
|
213
|
+
```jsx
|
|
214
|
+
/** @jsx h */
|
|
215
|
+
|
|
216
|
+
function AboutPage() {
|
|
217
|
+
return <div><h1>About</h1></div>;
|
|
218
|
+
}
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
Both work! The new way is just less code.
|
|
222
|
+
|
|
223
|
+
## Advanced: Multiple Routes
|
|
224
|
+
|
|
225
|
+
Point multiple routes to the same component:
|
|
226
|
+
|
|
227
|
+
```jsx
|
|
228
|
+
/** @jsx h */
|
|
229
|
+
|
|
230
|
+
// Auto-registers as "dashboard"
|
|
231
|
+
function DashboardPage() {
|
|
232
|
+
return <div><h1>Dashboard</h1></div>;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// Also register as "home" and "index"
|
|
236
|
+
registerPage("home", DashboardPage);
|
|
237
|
+
registerPage("index", DashboardPage);
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
Now `#/dashboard`, `#/home`, and `#/index` all show the same page!
|
|
241
|
+
|
|
242
|
+
## Summary
|
|
243
|
+
|
|
244
|
+
- **Function name ends with "Page"** → Auto-registers
|
|
245
|
+
- **Route name** = function name without "Page", lowercase
|
|
246
|
+
- **Manual registration** still available for custom names
|
|
247
|
+
- **Dev server** handles everything automatically
|
|
248
|
+
- **Zero configuration** needed for basic pages
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# Dev Server Guide
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
The dev server provides a smooth development experience with live reload, automatic import generation, and file watching.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
### 🔄 Live Reload
|
|
10
|
+
- **Automatic browser refresh** when you save files
|
|
11
|
+
- **Visual indicator** in bottom-right corner shows connection status
|
|
12
|
+
- **Smart caching** - forces cache clear on reload to always show latest changes
|
|
13
|
+
- **CSS hot reload** - instant updates without regenerating imports
|
|
14
|
+
|
|
15
|
+
### 👀 File Watching
|
|
16
|
+
The dev server watches these directories:
|
|
17
|
+
- `api/` - API route files
|
|
18
|
+
- `components/` - React-like components
|
|
19
|
+
- `pages/` - Page components
|
|
20
|
+
- `modules/` - Core system modules
|
|
21
|
+
- `styles/` - CSS files
|
|
22
|
+
|
|
23
|
+
### 🚀 Auto Import Generation
|
|
24
|
+
- Automatically generates script tags in `app.html`
|
|
25
|
+
- Runs on startup and whenever JS/JSX files change
|
|
26
|
+
- No need to manually add imports
|
|
27
|
+
|
|
28
|
+
### 🎯 Smart Port Selection
|
|
29
|
+
- Defaults to port 3000
|
|
30
|
+
- Automatically finds next available port if 3000 is busy
|
|
31
|
+
- Shows the actual URL in console
|
|
32
|
+
|
|
33
|
+
## Usage
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
npm run dev
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Then open the URL shown in console (usually `http://localhost:3000/`)
|
|
40
|
+
|
|
41
|
+
## Visual Indicators
|
|
42
|
+
|
|
43
|
+
The live reload indicator in the bottom-right corner shows:
|
|
44
|
+
- 🔌 **Connecting...** - Initial connection
|
|
45
|
+
- ✅ **Live Reload Active** - Connected and watching (fades after 2s)
|
|
46
|
+
- 🔄 **Reloading...** - Changes detected, refreshing page
|
|
47
|
+
- ⚠️ **Reconnecting...** - Connection lost, attempting to reconnect
|
|
48
|
+
|
|
49
|
+
Hover over the indicator to make it fully visible.
|
|
50
|
+
|
|
51
|
+
## How It Works
|
|
52
|
+
|
|
53
|
+
1. **Server starts** and generates initial imports
|
|
54
|
+
2. **Browser connects** via Server-Sent Events (SSE)
|
|
55
|
+
3. **File watcher** detects changes in watched directories
|
|
56
|
+
4. **Debouncing** prevents multiple rapid reloads (300ms for CSS, 500ms for JS)
|
|
57
|
+
5. **Import regeneration** (for JS/JSX changes only)
|
|
58
|
+
6. **Browser notification** via SSE
|
|
59
|
+
7. **Page reload** with cache busting
|
|
60
|
+
|
|
61
|
+
## Cache Control
|
|
62
|
+
|
|
63
|
+
The dev server sends these headers to prevent caching:
|
|
64
|
+
```
|
|
65
|
+
Cache-Control: no-cache, no-store, must-revalidate
|
|
66
|
+
Pragma: no-cache
|
|
67
|
+
Expires: 0
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
This ensures you always see the latest changes without needing Ctrl+Shift+R.
|
|
71
|
+
|
|
72
|
+
## Troubleshooting
|
|
73
|
+
|
|
74
|
+
### Changes not showing?
|
|
75
|
+
1. Check the visual indicator - is it green?
|
|
76
|
+
2. Open browser console - look for "✅ Live reload connected"
|
|
77
|
+
3. Check terminal - does it show "🔄 Notifying X browser(s) to reload..."?
|
|
78
|
+
4. Try hard refresh once: Ctrl+Shift+R (Windows) or Cmd+Shift+R (Mac)
|
|
79
|
+
|
|
80
|
+
### Port already in use?
|
|
81
|
+
The server will automatically try the next port (3001, 3002, etc.)
|
|
82
|
+
|
|
83
|
+
### Live reload disconnected?
|
|
84
|
+
The page will automatically try to reconnect after 2 seconds.
|
|
85
|
+
|
|
86
|
+
## Performance
|
|
87
|
+
|
|
88
|
+
- **Debouncing** prevents reload spam when saving multiple files
|
|
89
|
+
- **CSS-only changes** skip import regeneration for faster updates
|
|
90
|
+
- **SSE connection** is lightweight and efficient
|
|
91
|
+
- **Multiple browsers** can connect simultaneously
|
|
92
|
+
|
|
93
|
+
## Development Tips
|
|
94
|
+
|
|
95
|
+
1. Keep the terminal visible to see file change notifications
|
|
96
|
+
2. The visual indicator helps confirm live reload is working
|
|
97
|
+
3. CSS changes are faster than JS changes (no import regeneration)
|
|
98
|
+
4. Multiple browser tabs will all reload simultaneously
|
|
@@ -56,17 +56,35 @@ function h(tag, props, ...children) {
|
|
|
56
56
|
// "#/contact" → Contact page
|
|
57
57
|
//
|
|
58
58
|
// To add a new page:
|
|
59
|
-
// 1. Create pages/YourPage.jsx
|
|
60
|
-
// 2.
|
|
61
|
-
// 3.
|
|
59
|
+
// 1. Create pages/YourPage.jsx with a function like AboutPage()
|
|
60
|
+
// 2. The page will automatically be registered!
|
|
61
|
+
// 3. Optional: Call registerPage("about", AboutPage) for custom route names
|
|
62
62
|
// ============================================================
|
|
63
63
|
const routes = {};
|
|
64
64
|
|
|
65
65
|
// registerPage("about", AboutPage) — called by each page file
|
|
66
|
+
// Now optional! Pages auto-register based on function name
|
|
66
67
|
function registerPage(path, component) {
|
|
67
68
|
routes[path] = component;
|
|
68
69
|
}
|
|
69
70
|
|
|
71
|
+
// Auto-register pages from global scope
|
|
72
|
+
// Looks for functions ending with "Page" (e.g., AboutPage, HomePage)
|
|
73
|
+
function autoRegisterPages() {
|
|
74
|
+
for (let key in window) {
|
|
75
|
+
if (key.endsWith('Page') && typeof window[key] === 'function') {
|
|
76
|
+
// Convert "AboutPage" → "about", "HomePage" → "home"
|
|
77
|
+
const routeName = key.replace('Page', '').toLowerCase();
|
|
78
|
+
|
|
79
|
+
// Only register if not already registered
|
|
80
|
+
if (!routes[routeName]) {
|
|
81
|
+
routes[routeName] = window[key];
|
|
82
|
+
console.log(`📄 Auto-registered: ${routeName} → ${key}()`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
70
88
|
function getCurrentPath() {
|
|
71
89
|
// Remove the "#/" prefix → "about", "contact", or "" for home
|
|
72
90
|
return window.location.hash.replace("#/", "") || "home";
|
|
@@ -162,8 +180,10 @@ function NotFoundPage() {
|
|
|
162
180
|
return (
|
|
163
181
|
<div class="not-found">
|
|
164
182
|
<h1>404</h1>
|
|
165
|
-
<p>
|
|
166
|
-
<button class="btn btn-primary" onClick={() => navigate("home")}>
|
|
183
|
+
<p>Oops! The page you're looking for doesn't exist.</p>
|
|
184
|
+
<button class="btn btn-primary" onClick={() => navigate("home")}>
|
|
185
|
+
Go Home
|
|
186
|
+
</button>
|
|
167
187
|
</div>
|
|
168
188
|
);
|
|
169
189
|
}
|
|
@@ -174,6 +194,9 @@ function NotFoundPage() {
|
|
|
174
194
|
// Called once after all scripts are loaded
|
|
175
195
|
// ============================================================
|
|
176
196
|
function startApp() {
|
|
197
|
+
// Auto-register any pages that weren't manually registered
|
|
198
|
+
autoRegisterPages();
|
|
199
|
+
|
|
177
200
|
renderShell();
|
|
178
201
|
renderPage();
|
|
179
202
|
|
package/template/pages/About.jsx
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/** @jsx h */
|
|
2
2
|
|
|
3
|
-
//
|
|
4
|
-
registerPage("about", AboutPage);
|
|
3
|
+
// Optional: You can still manually register if you want a custom route name
|
|
4
|
+
// registerPage("about", AboutPage);
|
|
5
5
|
|
|
6
|
+
// Or just define the function and it auto-registers as "about"
|
|
6
7
|
function AboutPage() {
|
|
7
8
|
return (
|
|
8
9
|
<div>
|
|
@@ -28,6 +29,20 @@ function AboutPage() {
|
|
|
28
29
|
Go to Contact →
|
|
29
30
|
</button>
|
|
30
31
|
</div>
|
|
32
|
+
|
|
33
|
+
<div class="card">
|
|
34
|
+
<h2>✨ Auto-Registration</h2>
|
|
35
|
+
<p>
|
|
36
|
+
This page works without calling <code>registerPage()</code>!
|
|
37
|
+
Just name your function <code>YourNamePage()</code> and it automatically
|
|
38
|
+
becomes a route.
|
|
39
|
+
</p>
|
|
40
|
+
<ul style={{ lineHeight: '1.8', marginLeft: '20px' }}>
|
|
41
|
+
<li><code>HomePage()</code> → <code>#/home</code></li>
|
|
42
|
+
<li><code>AboutPage()</code> → <code>#/about</code></li>
|
|
43
|
+
<li><code>ContactPage()</code> → <code>#/contact</code></li>
|
|
44
|
+
</ul>
|
|
45
|
+
</div>
|
|
31
46
|
</div>
|
|
32
47
|
);
|
|
33
48
|
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/** @jsx h */
|
|
2
|
+
|
|
3
|
+
// That's it! No registerPage() needed.
|
|
4
|
+
// This automatically becomes route "#/example"
|
|
5
|
+
function ExamplePage() {
|
|
6
|
+
const [message, setMessage] = useState('Hello from Example Page! 🎉');
|
|
7
|
+
|
|
8
|
+
return (
|
|
9
|
+
<div>
|
|
10
|
+
<h1>Example Page</h1>
|
|
11
|
+
|
|
12
|
+
<div class="card">
|
|
13
|
+
<h2>✨ Auto-Registration Demo</h2>
|
|
14
|
+
<p>
|
|
15
|
+
This page was created without calling <code>registerPage()</code>.
|
|
16
|
+
Just define a function ending with "Page" and it works!
|
|
17
|
+
</p>
|
|
18
|
+
|
|
19
|
+
<div style={{
|
|
20
|
+
background: '#f0f0f0',
|
|
21
|
+
padding: '16px',
|
|
22
|
+
borderRadius: '8px',
|
|
23
|
+
fontFamily: 'monospace',
|
|
24
|
+
fontSize: '14px'
|
|
25
|
+
}}>
|
|
26
|
+
<strong>Function name:</strong> ExamplePage()<br/>
|
|
27
|
+
<strong>Auto route:</strong> #/example<br/>
|
|
28
|
+
<strong>URL:</strong> {window.location.href}
|
|
29
|
+
</div>
|
|
30
|
+
</div>
|
|
31
|
+
|
|
32
|
+
<div class="card">
|
|
33
|
+
<h2>State Management Works Too</h2>
|
|
34
|
+
<p>{message}</p>
|
|
35
|
+
<button
|
|
36
|
+
class="btn btn-primary"
|
|
37
|
+
onClick={() => setMessage('State updated! ✅')}
|
|
38
|
+
>
|
|
39
|
+
Update Message
|
|
40
|
+
</button>
|
|
41
|
+
</div>
|
|
42
|
+
|
|
43
|
+
<div class="card">
|
|
44
|
+
<h2>Navigation</h2>
|
|
45
|
+
<div style={{ display: 'flex', gap: '12px' }}>
|
|
46
|
+
<button class="btn btn-primary" onClick={() => navigate("home")}>
|
|
47
|
+
Home
|
|
48
|
+
</button>
|
|
49
|
+
<button class="btn btn-primary" onClick={() => navigate("about")}>
|
|
50
|
+
About
|
|
51
|
+
</button>
|
|
52
|
+
<button class="btn btn-primary" onClick={() => navigate("test")}>
|
|
53
|
+
Test
|
|
54
|
+
</button>
|
|
55
|
+
</div>
|
|
56
|
+
</div>
|
|
57
|
+
</div>
|
|
58
|
+
);
|
|
59
|
+
}
|
package/template/pages/Home.jsx
CHANGED
package/template/pages/test.jsx
CHANGED
|
@@ -26,7 +26,8 @@ function generateImports() {
|
|
|
26
26
|
|
|
27
27
|
// Notify all clients to reload
|
|
28
28
|
function notifyClients() {
|
|
29
|
-
|
|
29
|
+
const timestamp = new Date().toLocaleTimeString();
|
|
30
|
+
console.log(`🔄 [${timestamp}] Notifying ${clients.length} browser(s) to reload...`);
|
|
30
31
|
clients.forEach(client => {
|
|
31
32
|
client.write('data: reload\n\n');
|
|
32
33
|
});
|
|
@@ -35,18 +36,74 @@ function notifyClients() {
|
|
|
35
36
|
// Live reload script to inject
|
|
36
37
|
const liveReloadScript = `
|
|
37
38
|
<script>
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
39
|
+
(function() {
|
|
40
|
+
// Create visual indicator
|
|
41
|
+
const indicator = document.createElement('div');
|
|
42
|
+
indicator.id = 'live-reload-indicator';
|
|
43
|
+
indicator.style.cssText = \`
|
|
44
|
+
position: fixed;
|
|
45
|
+
bottom: 20px;
|
|
46
|
+
right: 20px;
|
|
47
|
+
background: #4caf50;
|
|
48
|
+
color: white;
|
|
49
|
+
padding: 8px 16px;
|
|
50
|
+
border-radius: 20px;
|
|
51
|
+
font-size: 12px;
|
|
52
|
+
font-family: monospace;
|
|
53
|
+
z-index: 9999;
|
|
54
|
+
box-shadow: 0 2px 8px rgba(0,0,0,0.2);
|
|
55
|
+
transition: all 0.3s;
|
|
56
|
+
\`;
|
|
57
|
+
indicator.textContent = '🔌 Connecting...';
|
|
58
|
+
document.body.appendChild(indicator);
|
|
59
|
+
|
|
60
|
+
// Live reload client
|
|
61
|
+
console.log('🔌 Connecting to live reload...');
|
|
62
|
+
const evtSource = new EventSource('/live-reload');
|
|
63
|
+
|
|
64
|
+
evtSource.onopen = () => {
|
|
65
|
+
console.log('✅ Live reload connected');
|
|
66
|
+
indicator.style.background = '#4caf50';
|
|
67
|
+
indicator.textContent = '✅ Live Reload Active';
|
|
68
|
+
// Hide after 2 seconds
|
|
69
|
+
setTimeout(() => {
|
|
70
|
+
indicator.style.opacity = '0.3';
|
|
71
|
+
}, 2000);
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
evtSource.onmessage = (event) => {
|
|
75
|
+
if (event.data === 'reload') {
|
|
76
|
+
console.log('🔄 Changes detected, reloading...');
|
|
77
|
+
indicator.style.opacity = '1';
|
|
78
|
+
indicator.style.background = '#2196f3';
|
|
79
|
+
indicator.textContent = '🔄 Reloading...';
|
|
80
|
+
// Force reload and clear cache
|
|
81
|
+
setTimeout(() => {
|
|
82
|
+
window.location.reload(true);
|
|
83
|
+
}, 100);
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
evtSource.onerror = (err) => {
|
|
88
|
+
console.log('⚠️ Live reload disconnected, retrying...');
|
|
89
|
+
indicator.style.background = '#ff9800';
|
|
90
|
+
indicator.style.opacity = '1';
|
|
91
|
+
indicator.textContent = '⚠️ Reconnecting...';
|
|
92
|
+
evtSource.close();
|
|
93
|
+
// Retry connection after 2 seconds
|
|
94
|
+
setTimeout(() => {
|
|
95
|
+
window.location.reload();
|
|
96
|
+
}, 2000);
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
// Show indicator on hover
|
|
100
|
+
indicator.addEventListener('mouseenter', () => {
|
|
101
|
+
indicator.style.opacity = '1';
|
|
102
|
+
});
|
|
103
|
+
indicator.addEventListener('mouseleave', () => {
|
|
104
|
+
indicator.style.opacity = '0.3';
|
|
105
|
+
});
|
|
106
|
+
})();
|
|
50
107
|
</script>
|
|
51
108
|
`;
|
|
52
109
|
|
|
@@ -118,7 +175,13 @@ function createServer(port) {
|
|
|
118
175
|
content = content.toString().replace('</body>', liveReloadScript + '</body>');
|
|
119
176
|
}
|
|
120
177
|
|
|
121
|
-
|
|
178
|
+
// Add cache control headers to prevent caching during development
|
|
179
|
+
res.writeHead(200, {
|
|
180
|
+
'Content-Type': contentType,
|
|
181
|
+
'Cache-Control': 'no-cache, no-store, must-revalidate',
|
|
182
|
+
'Pragma': 'no-cache',
|
|
183
|
+
'Expires': '0'
|
|
184
|
+
});
|
|
122
185
|
res.end(content, 'utf-8');
|
|
123
186
|
}
|
|
124
187
|
});
|
|
@@ -143,16 +206,35 @@ function startServer(port) {
|
|
|
143
206
|
}
|
|
144
207
|
|
|
145
208
|
// Watch directories
|
|
146
|
-
const watchDirs = ['api', 'components', 'pages', 'modules'];
|
|
209
|
+
const watchDirs = ['api', 'components', 'pages', 'modules', 'styles'];
|
|
210
|
+
|
|
211
|
+
// Debounce to prevent multiple rapid reloads
|
|
212
|
+
let reloadTimeout = null;
|
|
147
213
|
|
|
148
214
|
console.log('👀 Watching for changes in:');
|
|
149
215
|
watchDirs.forEach(dir => {
|
|
150
216
|
if (fs.existsSync(dir)) {
|
|
151
217
|
console.log(` - ${dir}/`);
|
|
152
218
|
fs.watch(dir, { recursive: false }, (eventType, filename) => {
|
|
153
|
-
if (filename && (filename.endsWith('.js') || filename.endsWith('.jsx'))) {
|
|
219
|
+
if (filename && (filename.endsWith('.js') || filename.endsWith('.jsx') || filename.endsWith('.css'))) {
|
|
154
220
|
console.log(`\n📝 Detected change: ${dir}/${filename}`);
|
|
155
|
-
|
|
221
|
+
|
|
222
|
+
// Clear existing timeout
|
|
223
|
+
if (reloadTimeout) {
|
|
224
|
+
clearTimeout(reloadTimeout);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// For CSS changes, just reload without regenerating imports
|
|
228
|
+
if (filename.endsWith('.css')) {
|
|
229
|
+
reloadTimeout = setTimeout(() => {
|
|
230
|
+
notifyClients();
|
|
231
|
+
}, 300);
|
|
232
|
+
} else {
|
|
233
|
+
// For JS/JSX changes, regenerate imports
|
|
234
|
+
reloadTimeout = setTimeout(() => {
|
|
235
|
+
generateImports();
|
|
236
|
+
}, 500);
|
|
237
|
+
}
|
|
156
238
|
}
|
|
157
239
|
});
|
|
158
240
|
}
|