create-aziz-app 2.0.4 → 2.0.6
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/bin/create-aziz-app.js +312 -0
- package/package.json +1 -1
- package/template/modules/router.js +12 -2
- package/template/pages/Home.jsx +9 -8
- package/template/pages/test.jsx +10 -11
- package/template/scripts/dev-server.js +46 -5
package/bin/create-aziz-app.js
CHANGED
|
@@ -309,6 +309,9 @@ function Footer() {
|
|
|
309
309
|
`;
|
|
310
310
|
fs.writeFileSync(footerPath, footerContent);
|
|
311
311
|
}
|
|
312
|
+
|
|
313
|
+
// Update all pages
|
|
314
|
+
updatePagesForBootstrap(targetDir);
|
|
312
315
|
}
|
|
313
316
|
|
|
314
317
|
// Update components for Tailwind
|
|
@@ -374,6 +377,315 @@ function Footer() {
|
|
|
374
377
|
`;
|
|
375
378
|
fs.writeFileSync(footerPath, footerContent);
|
|
376
379
|
}
|
|
380
|
+
|
|
381
|
+
// Update all pages
|
|
382
|
+
updatePagesForTailwind(targetDir);
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
// Update all pages for Bootstrap
|
|
386
|
+
function updatePagesForBootstrap(targetDir) {
|
|
387
|
+
const pagesDir = path.join(targetDir, 'pages');
|
|
388
|
+
if (!fs.existsSync(pagesDir)) return;
|
|
389
|
+
|
|
390
|
+
// Update Home.jsx
|
|
391
|
+
const homePath = path.join(pagesDir, 'Home.jsx');
|
|
392
|
+
if (fs.existsSync(homePath)) {
|
|
393
|
+
fs.writeFileSync(homePath, getBootstrapHomePage());
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
// Update test.jsx
|
|
397
|
+
const testPath = path.join(pagesDir, 'test.jsx');
|
|
398
|
+
if (fs.existsSync(testPath)) {
|
|
399
|
+
fs.writeFileSync(testPath, getBootstrapTestPage());
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// About and Contact pages are simple, they work with any framework
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
// Update all pages for Tailwind
|
|
406
|
+
function updatePagesForTailwind(targetDir) {
|
|
407
|
+
const pagesDir = path.join(targetDir, 'pages');
|
|
408
|
+
if (!fs.existsSync(pagesDir)) return;
|
|
409
|
+
|
|
410
|
+
// Update Home.jsx
|
|
411
|
+
const homePath = path.join(pagesDir, 'Home.jsx');
|
|
412
|
+
if (fs.existsSync(homePath)) {
|
|
413
|
+
fs.writeFileSync(homePath, getTailwindHomePage());
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
// Update test.jsx
|
|
417
|
+
const testPath = path.join(pagesDir, 'test.jsx');
|
|
418
|
+
if (fs.existsSync(testPath)) {
|
|
419
|
+
fs.writeFileSync(testPath, getTailwindTestPage());
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
// Bootstrap Home Page
|
|
424
|
+
function getBootstrapHomePage() {
|
|
425
|
+
return `/** @jsx h */
|
|
426
|
+
|
|
427
|
+
registerPage("home", HomePage);
|
|
428
|
+
|
|
429
|
+
function HomePage() {
|
|
430
|
+
return (
|
|
431
|
+
<div class="container py-5">
|
|
432
|
+
<h1 class="display-4 mb-4">Welcome Home 👋</h1>
|
|
433
|
+
|
|
434
|
+
<div class="card mb-4">
|
|
435
|
+
<div class="card-body">
|
|
436
|
+
<h2 class="card-title">Global State Counter</h2>
|
|
437
|
+
<p class="card-text">This uses the global state. Click the buttons to update it.</p>
|
|
438
|
+
|
|
439
|
+
<div class="text-center my-4">
|
|
440
|
+
<h1 class="display-1 fw-bold text-primary">{state.count}</h1>
|
|
441
|
+
</div>
|
|
442
|
+
|
|
443
|
+
<div class="d-flex gap-2 justify-content-center">
|
|
444
|
+
<button class="btn btn-danger" onClick={() => setState({ count: state.count - 1 })}>−</button>
|
|
445
|
+
<button class="btn btn-primary" onClick={() => setState({ count: state.count + 1 })}>+</button>
|
|
446
|
+
<button class="btn btn-secondary" onClick={() => setState({ count: 0 })}>Reset</button>
|
|
447
|
+
</div>
|
|
448
|
+
</div>
|
|
449
|
+
</div>
|
|
450
|
+
|
|
451
|
+
<div class="card">
|
|
452
|
+
<div class="card-body">
|
|
453
|
+
<h2 class="card-title">File-based Routing</h2>
|
|
454
|
+
<p class="card-text">
|
|
455
|
+
Each file in <strong>pages/</strong> is a route — just like Next.js.
|
|
456
|
+
Add a new file, run the build script, and it's a new page.
|
|
457
|
+
</p>
|
|
458
|
+
<div class="d-flex gap-2">
|
|
459
|
+
<button class="btn btn-primary" onClick={() => navigate("test")}>
|
|
460
|
+
Go to Test Page →
|
|
461
|
+
</button>
|
|
462
|
+
<button class="btn btn-outline-primary" onClick={() => navigate("about")}>
|
|
463
|
+
Go to About →
|
|
464
|
+
</button>
|
|
465
|
+
</div>
|
|
466
|
+
</div>
|
|
467
|
+
</div>
|
|
468
|
+
</div>
|
|
469
|
+
);
|
|
470
|
+
}
|
|
471
|
+
`;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
// Tailwind Home Page
|
|
475
|
+
function getTailwindHomePage() {
|
|
476
|
+
return `/** @jsx h */
|
|
477
|
+
|
|
478
|
+
registerPage("home", HomePage);
|
|
479
|
+
|
|
480
|
+
function HomePage() {
|
|
481
|
+
return (
|
|
482
|
+
<div class="container mx-auto py-10 px-4">
|
|
483
|
+
<h1 class="text-4xl font-bold mb-6 text-gray-800">Welcome Home 👋</h1>
|
|
484
|
+
|
|
485
|
+
<div class="bg-white rounded-lg shadow-md p-6 mb-6">
|
|
486
|
+
<h2 class="text-2xl font-bold mb-3 text-gray-800">Global State Counter</h2>
|
|
487
|
+
<p class="text-gray-600 mb-4">This uses the global state. Click the buttons to update it.</p>
|
|
488
|
+
|
|
489
|
+
<div class="text-center my-6">
|
|
490
|
+
<h1 class="text-7xl font-bold text-primary">{state.count}</h1>
|
|
491
|
+
</div>
|
|
492
|
+
|
|
493
|
+
<div class="flex gap-3 justify-center">
|
|
494
|
+
<button class="px-6 py-2 bg-red-500 text-white rounded-lg hover:bg-red-600 transition" onClick={() => setState({ count: state.count - 1 })}>−</button>
|
|
495
|
+
<button class="px-6 py-2 bg-primary text-dark font-bold rounded-lg hover:opacity-80 transition" onClick={() => setState({ count: state.count + 1 })}>+</button>
|
|
496
|
+
<button class="px-6 py-2 bg-gray-400 text-white rounded-lg hover:bg-gray-500 transition" onClick={() => setState({ count: 0 })}>Reset</button>
|
|
497
|
+
</div>
|
|
498
|
+
</div>
|
|
499
|
+
|
|
500
|
+
<div class="bg-white rounded-lg shadow-md p-6">
|
|
501
|
+
<h2 class="text-2xl font-bold mb-3 text-gray-800">File-based Routing</h2>
|
|
502
|
+
<p class="text-gray-600 mb-4">
|
|
503
|
+
Each file in <strong>pages/</strong> is a route — just like Next.js.
|
|
504
|
+
Add a new file, run the build script, and it's a new page.
|
|
505
|
+
</p>
|
|
506
|
+
<div class="flex gap-3">
|
|
507
|
+
<button class="px-6 py-2 bg-primary text-dark font-bold rounded-lg hover:opacity-80 transition" onClick={() => navigate("test")}>
|
|
508
|
+
Go to Test Page →
|
|
509
|
+
</button>
|
|
510
|
+
<button class="px-6 py-2 border-2 border-primary text-primary rounded-lg hover:bg-primary hover:text-dark transition" onClick={() => navigate("about")}>
|
|
511
|
+
Go to About →
|
|
512
|
+
</button>
|
|
513
|
+
</div>
|
|
514
|
+
</div>
|
|
515
|
+
</div>
|
|
516
|
+
);
|
|
517
|
+
}
|
|
518
|
+
`;
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
// Bootstrap Test Page
|
|
522
|
+
function getBootstrapTestPage() {
|
|
523
|
+
return `/** @jsx h */
|
|
524
|
+
|
|
525
|
+
registerPage("test", TestPage);
|
|
526
|
+
|
|
527
|
+
function TestPage() {
|
|
528
|
+
const [count, setCount] = useState(0);
|
|
529
|
+
const [name, setName] = useState('');
|
|
530
|
+
const [email, setEmail] = useState('');
|
|
531
|
+
|
|
532
|
+
const handleSubmit = (e) => {
|
|
533
|
+
e.preventDefault();
|
|
534
|
+
alert(\`Form submitted!\\nName: \${name}\\nEmail: \${email}\\nCount: \${count}\`);
|
|
535
|
+
};
|
|
536
|
+
|
|
537
|
+
return (
|
|
538
|
+
<div class="container py-5">
|
|
539
|
+
<h1 class="display-4 mb-4">Test Page 🧪</h1>
|
|
540
|
+
|
|
541
|
+
<div class="card mb-4">
|
|
542
|
+
<div class="card-body">
|
|
543
|
+
<h2 class="card-title">Counter Example</h2>
|
|
544
|
+
<p class="card-text">This demonstrates the state management system.</p>
|
|
545
|
+
|
|
546
|
+
<div class="text-center my-4">
|
|
547
|
+
<h1 class="display-1 fw-bold text-primary">{count}</h1>
|
|
548
|
+
</div>
|
|
549
|
+
<div class="d-flex gap-2 justify-content-center">
|
|
550
|
+
<button class="btn btn-primary" onClick={() => setCount(count + 1)}>
|
|
551
|
+
Increment
|
|
552
|
+
</button>
|
|
553
|
+
<button class="btn btn-danger" onClick={() => setCount(0)}>
|
|
554
|
+
Reset
|
|
555
|
+
</button>
|
|
556
|
+
</div>
|
|
557
|
+
</div>
|
|
558
|
+
</div>
|
|
559
|
+
|
|
560
|
+
<div class="card mb-4">
|
|
561
|
+
<div class="card-body">
|
|
562
|
+
<h2 class="card-title">Form Example</h2>
|
|
563
|
+
<p class="card-text">Try the form with state management.</p>
|
|
564
|
+
|
|
565
|
+
<form onSubmit={handleSubmit}>
|
|
566
|
+
<div class="mb-3">
|
|
567
|
+
<label class="form-label">Name:</label>
|
|
568
|
+
<input
|
|
569
|
+
type="text"
|
|
570
|
+
class="form-control"
|
|
571
|
+
value={name}
|
|
572
|
+
onInput={(e) => setName(e.target.value)}
|
|
573
|
+
placeholder="Enter your name"
|
|
574
|
+
/>
|
|
575
|
+
</div>
|
|
576
|
+
|
|
577
|
+
<div class="mb-3">
|
|
578
|
+
<label class="form-label">Email:</label>
|
|
579
|
+
<input
|
|
580
|
+
type="email"
|
|
581
|
+
class="form-control"
|
|
582
|
+
value={email}
|
|
583
|
+
onInput={(e) => setEmail(e.target.value)}
|
|
584
|
+
placeholder="Enter your email"
|
|
585
|
+
/>
|
|
586
|
+
</div>
|
|
587
|
+
|
|
588
|
+
<button type="submit" class="btn btn-primary">
|
|
589
|
+
Submit Form
|
|
590
|
+
</button>
|
|
591
|
+
</form>
|
|
592
|
+
</div>
|
|
593
|
+
</div>
|
|
594
|
+
|
|
595
|
+
<div class="card">
|
|
596
|
+
<div class="card-body">
|
|
597
|
+
<h2 class="card-title">State Information</h2>
|
|
598
|
+
<p class="mb-2">Current count: <strong class="text-primary">{count}</strong></p>
|
|
599
|
+
<p class="mb-2">Current name: <strong class="text-primary">{name || 'Not set'}</strong></p>
|
|
600
|
+
<p class="mb-0">Current email: <strong class="text-primary">{email || 'Not set'}</strong></p>
|
|
601
|
+
</div>
|
|
602
|
+
</div>
|
|
603
|
+
</div>
|
|
604
|
+
);
|
|
605
|
+
}
|
|
606
|
+
`;
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
// Tailwind Test Page
|
|
610
|
+
function getTailwindTestPage() {
|
|
611
|
+
return `/** @jsx h */
|
|
612
|
+
|
|
613
|
+
registerPage("test", TestPage);
|
|
614
|
+
|
|
615
|
+
function TestPage() {
|
|
616
|
+
const [count, setCount] = useState(0);
|
|
617
|
+
const [name, setName] = useState('');
|
|
618
|
+
const [email, setEmail] = useState('');
|
|
619
|
+
|
|
620
|
+
const handleSubmit = (e) => {
|
|
621
|
+
e.preventDefault();
|
|
622
|
+
alert(\`Form submitted!\\nName: \${name}\\nEmail: \${email}\\nCount: \${count}\`);
|
|
623
|
+
};
|
|
624
|
+
|
|
625
|
+
return (
|
|
626
|
+
<div class="container mx-auto py-10 px-4">
|
|
627
|
+
<h1 class="text-4xl font-bold mb-6 text-gray-800">Test Page 🧪</h1>
|
|
628
|
+
|
|
629
|
+
<div class="bg-white rounded-lg shadow-md p-6 mb-6">
|
|
630
|
+
<h2 class="text-2xl font-bold mb-3 text-gray-800">Counter Example</h2>
|
|
631
|
+
<p class="text-gray-600 mb-4">This demonstrates the state management system.</p>
|
|
632
|
+
|
|
633
|
+
<div class="text-center my-6">
|
|
634
|
+
<h1 class="text-7xl font-bold text-primary">{count}</h1>
|
|
635
|
+
</div>
|
|
636
|
+
<div class="flex gap-3 justify-center">
|
|
637
|
+
<button class="px-6 py-2 bg-primary text-dark font-bold rounded-lg hover:opacity-80 transition" onClick={() => setCount(count + 1)}>
|
|
638
|
+
Increment
|
|
639
|
+
</button>
|
|
640
|
+
<button class="px-6 py-2 bg-red-500 text-white rounded-lg hover:bg-red-600 transition" onClick={() => setCount(0)}>
|
|
641
|
+
Reset
|
|
642
|
+
</button>
|
|
643
|
+
</div>
|
|
644
|
+
</div>
|
|
645
|
+
|
|
646
|
+
<div class="bg-white rounded-lg shadow-md p-6 mb-6">
|
|
647
|
+
<h2 class="text-2xl font-bold mb-3 text-gray-800">Form Example</h2>
|
|
648
|
+
<p class="text-gray-600 mb-4">Try the form with state management.</p>
|
|
649
|
+
|
|
650
|
+
<form onSubmit={handleSubmit} class="space-y-4">
|
|
651
|
+
<div>
|
|
652
|
+
<label class="block text-sm font-medium text-gray-700 mb-1">Name:</label>
|
|
653
|
+
<input
|
|
654
|
+
type="text"
|
|
655
|
+
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary focus:border-primary outline-none transition"
|
|
656
|
+
value={name}
|
|
657
|
+
onInput={(e) => setName(e.target.value)}
|
|
658
|
+
placeholder="Enter your name"
|
|
659
|
+
/>
|
|
660
|
+
</div>
|
|
661
|
+
|
|
662
|
+
<div>
|
|
663
|
+
<label class="block text-sm font-medium text-gray-700 mb-1">Email:</label>
|
|
664
|
+
<input
|
|
665
|
+
type="email"
|
|
666
|
+
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary focus:border-primary outline-none transition"
|
|
667
|
+
value={email}
|
|
668
|
+
onInput={(e) => setEmail(e.target.value)}
|
|
669
|
+
placeholder="Enter your email"
|
|
670
|
+
/>
|
|
671
|
+
</div>
|
|
672
|
+
|
|
673
|
+
<button type="submit" class="px-6 py-2 bg-primary text-dark font-bold rounded-lg hover:opacity-80 transition">
|
|
674
|
+
Submit Form
|
|
675
|
+
</button>
|
|
676
|
+
</form>
|
|
677
|
+
</div>
|
|
678
|
+
|
|
679
|
+
<div class="bg-white rounded-lg shadow-md p-6">
|
|
680
|
+
<h2 class="text-2xl font-bold mb-3 text-gray-800">State Information</h2>
|
|
681
|
+
<p class="mb-2 text-gray-700">Current count: <strong class="text-primary">{count}</strong></p>
|
|
682
|
+
<p class="mb-2 text-gray-700">Current name: <strong class="text-primary">{name || 'Not set'}</strong></p>
|
|
683
|
+
<p class="mb-0 text-gray-700">Current email: <strong class="text-primary">{email || 'Not set'}</strong></p>
|
|
684
|
+
</div>
|
|
685
|
+
</div>
|
|
686
|
+
);
|
|
687
|
+
}
|
|
688
|
+
`;
|
|
377
689
|
}
|
|
378
690
|
|
|
379
691
|
// Run main function
|
package/package.json
CHANGED
|
@@ -150,6 +150,13 @@ function renderShell() {
|
|
|
150
150
|
footer.appendChild(Footer());
|
|
151
151
|
}
|
|
152
152
|
|
|
153
|
+
// Re-render shell when route changes (for navbar active state)
|
|
154
|
+
function updateShell() {
|
|
155
|
+
const navbar = document.getElementById("navbar");
|
|
156
|
+
navbar.innerHTML = "";
|
|
157
|
+
navbar.appendChild(Navbar());
|
|
158
|
+
}
|
|
159
|
+
|
|
153
160
|
// 404 page — shown when no route matches
|
|
154
161
|
function NotFoundPage() {
|
|
155
162
|
return (
|
|
@@ -170,8 +177,11 @@ function startApp() {
|
|
|
170
177
|
renderShell();
|
|
171
178
|
renderPage();
|
|
172
179
|
|
|
173
|
-
// Re-render the page whenever the hash changes (back/forward navigation)
|
|
174
|
-
window.addEventListener("hashchange",
|
|
180
|
+
// Re-render the page and navbar whenever the hash changes (back/forward navigation)
|
|
181
|
+
window.addEventListener("hashchange", () => {
|
|
182
|
+
updateShell(); // Update navbar active state
|
|
183
|
+
renderPage();
|
|
184
|
+
});
|
|
175
185
|
}
|
|
176
186
|
|
|
177
187
|
// Export to global scope
|
package/template/pages/Home.jsx
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
/** @jsx h */
|
|
2
2
|
|
|
3
|
-
// Register this page at route "home" → "#/"
|
|
4
3
|
registerPage("home", HomePage);
|
|
5
4
|
|
|
6
5
|
function HomePage() {
|
|
@@ -25,14 +24,16 @@ function HomePage() {
|
|
|
25
24
|
<h2>File-based Routing</h2>
|
|
26
25
|
<p>
|
|
27
26
|
Each file in <strong>pages/</strong> is a route — just like Next.js.
|
|
28
|
-
Add a new file,
|
|
27
|
+
Add a new file, run the build script, and it's a new page.
|
|
29
28
|
</p>
|
|
30
|
-
<
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
29
|
+
<div style={{ display: 'flex', gap: '12px' }}>
|
|
30
|
+
<button class="btn btn-primary" onClick={() => navigate("test")}>
|
|
31
|
+
Go to Test Page →
|
|
32
|
+
</button>
|
|
33
|
+
<button class="btn btn-primary" onClick={() => navigate("about")}>
|
|
34
|
+
Go to About →
|
|
35
|
+
</button>
|
|
36
|
+
</div>
|
|
36
37
|
</div>
|
|
37
38
|
</div>
|
|
38
39
|
);
|
package/template/pages/test.jsx
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
/** @jsx h */
|
|
2
2
|
|
|
3
|
-
// Register this page at route "test" → "#/test"
|
|
4
3
|
registerPage("test", TestPage);
|
|
5
4
|
|
|
6
5
|
function TestPage() {
|
|
@@ -19,7 +18,7 @@ function TestPage() {
|
|
|
19
18
|
|
|
20
19
|
<div class="card">
|
|
21
20
|
<h2>Counter Example</h2>
|
|
22
|
-
<p>This demonstrates the
|
|
21
|
+
<p>This demonstrates the state management system.</p>
|
|
23
22
|
|
|
24
23
|
<div class="count-display">{count}</div>
|
|
25
24
|
<div class="counter-actions">
|
|
@@ -37,15 +36,6 @@ function TestPage() {
|
|
|
37
36
|
<p>Try the form with state management.</p>
|
|
38
37
|
|
|
39
38
|
<form onSubmit={handleSubmit}>
|
|
40
|
-
<div>
|
|
41
|
-
<label>Email:</label>
|
|
42
|
-
<input
|
|
43
|
-
type="email"
|
|
44
|
-
value={email}
|
|
45
|
-
onInput={(e) => setEmail(e.target.value)}
|
|
46
|
-
placeholder="Enter your email"
|
|
47
|
-
/>
|
|
48
|
-
</div>
|
|
49
39
|
<div>
|
|
50
40
|
<label>Name:</label>
|
|
51
41
|
<input
|
|
@@ -56,6 +46,15 @@ function TestPage() {
|
|
|
56
46
|
/>
|
|
57
47
|
</div>
|
|
58
48
|
|
|
49
|
+
<div>
|
|
50
|
+
<label>Email:</label>
|
|
51
|
+
<input
|
|
52
|
+
type="email"
|
|
53
|
+
value={email}
|
|
54
|
+
onInput={(e) => setEmail(e.target.value)}
|
|
55
|
+
placeholder="Enter your email"
|
|
56
|
+
/>
|
|
57
|
+
</div>
|
|
59
58
|
|
|
60
59
|
<button type="submit" class="btn btn-primary">
|
|
61
60
|
Submit Form
|
|
@@ -35,18 +35,59 @@ function notifyClients() {
|
|
|
35
35
|
// Live reload script to inject
|
|
36
36
|
const liveReloadScript = `
|
|
37
37
|
<script>
|
|
38
|
-
//
|
|
38
|
+
// Hot Module Replacement (HMR) - Smart reload
|
|
39
39
|
const evtSource = new EventSource('/live-reload');
|
|
40
|
+
let isReloading = false;
|
|
41
|
+
|
|
40
42
|
evtSource.onmessage = (event) => {
|
|
41
|
-
if (event.data === 'reload') {
|
|
42
|
-
|
|
43
|
-
|
|
43
|
+
if (event.data === 'reload' && !isReloading) {
|
|
44
|
+
isReloading = true;
|
|
45
|
+
console.log('🔄 Changes detected, hot reloading...');
|
|
46
|
+
|
|
47
|
+
// Save current state
|
|
48
|
+
const currentPath = window.location.hash;
|
|
49
|
+
const scrollPos = window.scrollY;
|
|
50
|
+
|
|
51
|
+
// Reload only changed scripts
|
|
52
|
+
const scripts = document.querySelectorAll('script[type="text/babel"]');
|
|
53
|
+
let reloadCount = 0;
|
|
54
|
+
|
|
55
|
+
scripts.forEach((script, index) => {
|
|
56
|
+
if (script.src && !script.src.includes('babel.min.js')) {
|
|
57
|
+
const newScript = document.createElement('script');
|
|
58
|
+
newScript.type = 'text/babel';
|
|
59
|
+
newScript.src = script.src + '?t=' + Date.now();
|
|
60
|
+
|
|
61
|
+
newScript.onload = () => {
|
|
62
|
+
reloadCount++;
|
|
63
|
+
if (reloadCount === scripts.length - 1) {
|
|
64
|
+
// All scripts reloaded, re-render
|
|
65
|
+
setTimeout(() => {
|
|
66
|
+
if (typeof renderShell === 'function') renderShell();
|
|
67
|
+
if (typeof renderPage === 'function') renderPage();
|
|
68
|
+
window.scrollTo(0, scrollPos);
|
|
69
|
+
console.log('✅ Hot reload complete');
|
|
70
|
+
isReloading = false;
|
|
71
|
+
}, 100);
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
script.parentNode.replaceChild(newScript, script);
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
// Fallback: if no scripts to reload, just refresh
|
|
80
|
+
if (scripts.length <= 1) {
|
|
81
|
+
location.reload();
|
|
82
|
+
}
|
|
44
83
|
}
|
|
45
84
|
};
|
|
85
|
+
|
|
46
86
|
evtSource.onerror = () => {
|
|
47
87
|
console.log('⚠️ Live reload disconnected');
|
|
48
88
|
};
|
|
49
|
-
|
|
89
|
+
|
|
90
|
+
console.log('✅ Hot reload connected');
|
|
50
91
|
</script>
|
|
51
92
|
`;
|
|
52
93
|
|