frontend-hamroun 1.2.7 → 1.2.9
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/scripts/build-cli.js +242 -0
- package/templates/basic/tsconfig.node.json +10 -0
- package/templates/basic-app/src/App.tsx +126 -100
- package/templates/basic-app/src/main.tsx +2 -10
- package/templates/basic-app/tsconfig.json +0 -3
- package/templates/basic-app/tsconfig.node.json +10 -0
- package/templates/basic-app/vite.config.ts +4 -16
- package/templates/full-stack/tsconfig.node.json +10 -0
package/package.json
CHANGED
package/scripts/build-cli.js
CHANGED
@@ -491,3 +491,245 @@ fs.chmodSync(path.join(binDir, 'cli.cjs'), '755');
|
|
491
491
|
console.log('✅ Created CJS wrapper: bin/cli.cjs');
|
492
492
|
|
493
493
|
console.log('✅ CLI build process completed');
|
494
|
+
|
495
|
+
// Create a minimal basic template (update existing code)
|
496
|
+
function createBasicTemplate(templateDir) {
|
497
|
+
console.log(`📝 Creating minimal basic template at ${templateDir}`);
|
498
|
+
|
499
|
+
// Create package.json
|
500
|
+
const packageJson = {
|
501
|
+
"name": "frontend-hamroun-app",
|
502
|
+
"private": true,
|
503
|
+
"version": "0.1.0",
|
504
|
+
"type": "module",
|
505
|
+
"scripts": {
|
506
|
+
"dev": "vite",
|
507
|
+
"build": "tsc && vite build",
|
508
|
+
"preview": "vite preview"
|
509
|
+
},
|
510
|
+
"dependencies": {
|
511
|
+
"frontend-hamroun": "latest"
|
512
|
+
},
|
513
|
+
"devDependencies": {
|
514
|
+
"@types/node": "^20.10.0",
|
515
|
+
"typescript": "^5.3.2",
|
516
|
+
"vite": "^5.0.0",
|
517
|
+
"vite-plugin-node-polyfills": "^0.21.0"
|
518
|
+
}
|
519
|
+
};
|
520
|
+
|
521
|
+
fs.writeFileSync(
|
522
|
+
path.join(templateDir, 'package.json'),
|
523
|
+
JSON.stringify(packageJson, null, 2)
|
524
|
+
);
|
525
|
+
|
526
|
+
// Create index.html
|
527
|
+
fs.writeFileSync(
|
528
|
+
path.join(templateDir, 'index.html'),
|
529
|
+
`<!DOCTYPE html>
|
530
|
+
<html lang="en">
|
531
|
+
<head>
|
532
|
+
<meta charset="UTF-8">
|
533
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
534
|
+
<title>Frontend Hamroun App</title>
|
535
|
+
</head>
|
536
|
+
<body>
|
537
|
+
<div id="app"></div>
|
538
|
+
<script type="module" src="/src/main.ts"></script>
|
539
|
+
</body>
|
540
|
+
</html>`
|
541
|
+
);
|
542
|
+
|
543
|
+
// Create src directory
|
544
|
+
const srcDir = path.join(templateDir, 'src');
|
545
|
+
fs.mkdirSync(srcDir, { recursive: true });
|
546
|
+
|
547
|
+
// Create main.ts
|
548
|
+
fs.writeFileSync(
|
549
|
+
path.join(srcDir, 'main.ts'),
|
550
|
+
`import { render } from 'frontend-hamroun';
|
551
|
+
import { App } from './App';
|
552
|
+
|
553
|
+
document.addEventListener('DOMContentLoaded', () => {
|
554
|
+
const rootElement = document.getElementById('app');
|
555
|
+
if (rootElement) {
|
556
|
+
render(App({}), rootElement);
|
557
|
+
console.log('App rendered successfully');
|
558
|
+
}
|
559
|
+
});`
|
560
|
+
);
|
561
|
+
|
562
|
+
// Create App.ts (not App.tsx)
|
563
|
+
fs.writeFileSync(
|
564
|
+
path.join(srcDir, 'App.ts'),
|
565
|
+
`import { useState, useRef } from 'frontend-hamroun';
|
566
|
+
|
567
|
+
export function App(props) {
|
568
|
+
const [count, setCount] = useState(0);
|
569
|
+
const renderCount = useRef(0);
|
570
|
+
|
571
|
+
renderCount.current++;
|
572
|
+
|
573
|
+
return {
|
574
|
+
type: 'div',
|
575
|
+
props: {
|
576
|
+
style: {
|
577
|
+
fontFamily: 'Arial, sans-serif',
|
578
|
+
maxWidth: '600px',
|
579
|
+
margin: '0 auto',
|
580
|
+
padding: '2rem'
|
581
|
+
},
|
582
|
+
children: [
|
583
|
+
{
|
584
|
+
type: 'h1',
|
585
|
+
props: {
|
586
|
+
style: { textAlign: 'center' },
|
587
|
+
children: 'Frontend Hamroun App'
|
588
|
+
}
|
589
|
+
},
|
590
|
+
{
|
591
|
+
type: 'p',
|
592
|
+
props: {
|
593
|
+
style: { textAlign: 'center' },
|
594
|
+
children: \`Render count: \${renderCount.current}\`
|
595
|
+
}
|
596
|
+
},
|
597
|
+
{
|
598
|
+
type: 'div',
|
599
|
+
props: {
|
600
|
+
style: {
|
601
|
+
display: 'flex',
|
602
|
+
flexDirection: 'column',
|
603
|
+
alignItems: 'center',
|
604
|
+
padding: '1rem',
|
605
|
+
border: '1px solid #ccc',
|
606
|
+
borderRadius: '8px'
|
607
|
+
},
|
608
|
+
children: [
|
609
|
+
{
|
610
|
+
type: 'h2',
|
611
|
+
props: {
|
612
|
+
children: 'Counter Example'
|
613
|
+
}
|
614
|
+
},
|
615
|
+
{
|
616
|
+
type: 'p',
|
617
|
+
props: {
|
618
|
+
children: \`Count: \${count}\`
|
619
|
+
}
|
620
|
+
},
|
621
|
+
{
|
622
|
+
type: 'div',
|
623
|
+
props: {
|
624
|
+
style: {
|
625
|
+
display: 'flex',
|
626
|
+
gap: '8px'
|
627
|
+
},
|
628
|
+
children: [
|
629
|
+
{
|
630
|
+
type: 'button',
|
631
|
+
props: {
|
632
|
+
onClick: () => setCount(count - 1),
|
633
|
+
style: {
|
634
|
+
padding: '8px 16px',
|
635
|
+
backgroundColor: '#ff4d4d',
|
636
|
+
color: 'white',
|
637
|
+
border: 'none',
|
638
|
+
borderRadius: '4px',
|
639
|
+
cursor: 'pointer'
|
640
|
+
},
|
641
|
+
children: 'Decrement'
|
642
|
+
}
|
643
|
+
},
|
644
|
+
{
|
645
|
+
type: 'button',
|
646
|
+
props: {
|
647
|
+
onClick: () => setCount(count + 1),
|
648
|
+
style: {
|
649
|
+
padding: '8px 16px',
|
650
|
+
backgroundColor: '#4d79ff',
|
651
|
+
color: 'white',
|
652
|
+
border: 'none',
|
653
|
+
borderRadius: '4px',
|
654
|
+
cursor: 'pointer'
|
655
|
+
},
|
656
|
+
children: 'Increment'
|
657
|
+
}
|
658
|
+
}
|
659
|
+
]
|
660
|
+
}
|
661
|
+
}
|
662
|
+
]
|
663
|
+
}
|
664
|
+
}
|
665
|
+
]
|
666
|
+
}
|
667
|
+
};
|
668
|
+
}`
|
669
|
+
);
|
670
|
+
|
671
|
+
// Create vite.config.ts
|
672
|
+
fs.writeFileSync(
|
673
|
+
path.join(templateDir, 'vite.config.ts'),
|
674
|
+
`import { defineConfig } from 'vite';
|
675
|
+
import { nodePolyfills } from 'vite-plugin-node-polyfills';
|
676
|
+
|
677
|
+
export default defineConfig({
|
678
|
+
build: {
|
679
|
+
outDir: 'dist',
|
680
|
+
emptyOutDir: true
|
681
|
+
},
|
682
|
+
server: {
|
683
|
+
port: 3000,
|
684
|
+
open: true
|
685
|
+
},
|
686
|
+
plugins: [
|
687
|
+
nodePolyfills({
|
688
|
+
protocolImports: true,
|
689
|
+
}),
|
690
|
+
]
|
691
|
+
});`
|
692
|
+
);
|
693
|
+
|
694
|
+
// Create tsconfig.json
|
695
|
+
fs.writeFileSync(
|
696
|
+
path.join(templateDir, 'tsconfig.json'),
|
697
|
+
`{
|
698
|
+
"compilerOptions": {
|
699
|
+
"target": "ES2020",
|
700
|
+
"useDefineForClassFields": true,
|
701
|
+
"module": "ESNext",
|
702
|
+
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
703
|
+
"skipLibCheck": true,
|
704
|
+
"moduleResolution": "bundler",
|
705
|
+
"allowImportingTsExtensions": true,
|
706
|
+
"resolveJsonModule": true,
|
707
|
+
"isolatedModules": true,
|
708
|
+
"noEmit": true,
|
709
|
+
"strict": true,
|
710
|
+
"noUnusedLocals": true,
|
711
|
+
"noUnusedParameters": true,
|
712
|
+
"noFallthroughCasesInSwitch": true
|
713
|
+
},
|
714
|
+
"include": ["src"],
|
715
|
+
"references": [{ "path": "./tsconfig.node.json" }]
|
716
|
+
}`
|
717
|
+
);
|
718
|
+
|
719
|
+
// Create tsconfig.node.json
|
720
|
+
fs.writeFileSync(
|
721
|
+
path.join(templateDir, 'tsconfig.node.json'),
|
722
|
+
`{
|
723
|
+
"compilerOptions": {
|
724
|
+
"composite": true,
|
725
|
+
"skipLibCheck": true,
|
726
|
+
"module": "ESNext",
|
727
|
+
"moduleResolution": "bundler",
|
728
|
+
"allowSyntheticDefaultImports": true
|
729
|
+
},
|
730
|
+
"include": ["vite.config.ts"]
|
731
|
+
}`
|
732
|
+
);
|
733
|
+
|
734
|
+
console.log(`✅ Created minimal basic template at ${templateDir}`);
|
735
|
+
}
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import { useState, useEffect, useContext } from 'frontend-hamroun';
|
1
|
+
import { useState, useEffect, useContext, useRef } from 'frontend-hamroun';
|
2
2
|
import { Header } from './components/Header';
|
3
3
|
import { Counter } from './components/Counter';
|
4
4
|
import { ApiClient } from './api.js';
|
@@ -9,109 +9,135 @@ interface AppProps {
|
|
9
9
|
api: ApiClient;
|
10
10
|
}
|
11
11
|
|
12
|
-
|
13
|
-
|
14
|
-
const [isLoading, setIsLoading] = useState(true);
|
15
|
-
const [error, setError] = useState<string | null>(null);
|
12
|
+
// Use function declaration style instead of JSX component syntax
|
13
|
+
export function App(props: any) {
|
16
14
|
const [count, setCount] = useState(0);
|
17
|
-
const
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
)}
|
63
|
-
</div>
|
64
|
-
</div>
|
65
|
-
|
66
|
-
<div style={{ fontFamily: 'Arial, sans-serif', maxWidth: '600px', margin: '0 auto', padding: '2rem' }}>
|
67
|
-
<h1 style={{ color: '#333', textAlign: 'center' }}>Frontend Hamroun App</h1>
|
68
|
-
<p style={{ textAlign: 'center' }}>
|
69
|
-
Current theme: <strong>{theme}</strong>
|
70
|
-
</p>
|
71
|
-
<div style={{
|
72
|
-
display: 'flex',
|
73
|
-
flexDirection: 'column',
|
74
|
-
alignItems: 'center',
|
75
|
-
marginTop: '2rem',
|
76
|
-
padding: '1rem',
|
77
|
-
border: '1px solid #ccc',
|
78
|
-
borderRadius: '8px',
|
79
|
-
backgroundColor: theme === 'dark' ? '#333' : '#fff',
|
80
|
-
color: theme === 'dark' ? '#fff' : '#333'
|
81
|
-
}}>
|
82
|
-
<h2>Counter Example</h2>
|
83
|
-
<p>Count: {count}</p>
|
84
|
-
<div style={{ display: 'flex', gap: '8px' }}>
|
85
|
-
<button
|
86
|
-
onClick={() => setCount(count - 1)}
|
87
|
-
style={{
|
15
|
+
const [theme, setTheme] = useState('light');
|
16
|
+
const renderCount = useRef(0);
|
17
|
+
|
18
|
+
renderCount.current++;
|
19
|
+
|
20
|
+
// Return a standard object structure rather than JSX
|
21
|
+
return {
|
22
|
+
type: 'div',
|
23
|
+
props: {
|
24
|
+
style: {
|
25
|
+
fontFamily: 'Arial, sans-serif',
|
26
|
+
maxWidth: '600px',
|
27
|
+
margin: '0 auto',
|
28
|
+
padding: '2rem',
|
29
|
+
backgroundColor: theme === 'dark' ? '#222' : '#fff',
|
30
|
+
color: theme === 'dark' ? '#fff' : '#222'
|
31
|
+
},
|
32
|
+
children: [
|
33
|
+
{
|
34
|
+
type: 'h1',
|
35
|
+
props: {
|
36
|
+
style: { textAlign: 'center' },
|
37
|
+
children: 'Frontend Hamroun App'
|
38
|
+
}
|
39
|
+
},
|
40
|
+
{
|
41
|
+
type: 'p',
|
42
|
+
props: {
|
43
|
+
style: { textAlign: 'center' },
|
44
|
+
children: `This component has rendered ${renderCount.current} times`
|
45
|
+
}
|
46
|
+
},
|
47
|
+
{
|
48
|
+
type: 'div',
|
49
|
+
props: {
|
50
|
+
style: {
|
51
|
+
display: 'flex',
|
52
|
+
justifyContent: 'center',
|
53
|
+
marginBottom: '1rem'
|
54
|
+
},
|
55
|
+
children: {
|
56
|
+
type: 'button',
|
57
|
+
props: {
|
58
|
+
onClick: () => setTheme(theme === 'light' ? 'dark' : 'light'),
|
59
|
+
style: {
|
88
60
|
padding: '8px 16px',
|
89
|
-
|
61
|
+
backgroundColor: '#4b5563',
|
90
62
|
color: 'white',
|
91
63
|
border: 'none',
|
92
64
|
borderRadius: '4px',
|
93
65
|
cursor: 'pointer'
|
94
|
-
}
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
66
|
+
},
|
67
|
+
children: `Switch to ${theme === 'light' ? 'dark' : 'light'} mode`
|
68
|
+
}
|
69
|
+
}
|
70
|
+
}
|
71
|
+
},
|
72
|
+
{
|
73
|
+
type: 'div',
|
74
|
+
props: {
|
75
|
+
style: {
|
76
|
+
display: 'flex',
|
77
|
+
flexDirection: 'column',
|
78
|
+
alignItems: 'center',
|
79
|
+
padding: '1rem',
|
80
|
+
border: '1px solid #ccc',
|
81
|
+
borderRadius: '8px'
|
82
|
+
},
|
83
|
+
children: [
|
84
|
+
{
|
85
|
+
type: 'h2',
|
86
|
+
props: {
|
87
|
+
children: 'Counter Example'
|
88
|
+
}
|
89
|
+
},
|
90
|
+
{
|
91
|
+
type: 'p',
|
92
|
+
props: {
|
93
|
+
children: `Count: ${count}`
|
94
|
+
}
|
95
|
+
},
|
96
|
+
{
|
97
|
+
type: 'div',
|
98
|
+
props: {
|
99
|
+
style: {
|
100
|
+
display: 'flex',
|
101
|
+
gap: '8px'
|
102
|
+
},
|
103
|
+
children: [
|
104
|
+
{
|
105
|
+
type: 'button',
|
106
|
+
props: {
|
107
|
+
onClick: () => setCount(count - 1),
|
108
|
+
style: {
|
109
|
+
padding: '8px 16px',
|
110
|
+
backgroundColor: '#ff4d4d',
|
111
|
+
color: 'white',
|
112
|
+
border: 'none',
|
113
|
+
borderRadius: '4px',
|
114
|
+
cursor: 'pointer'
|
115
|
+
},
|
116
|
+
children: 'Decrement'
|
117
|
+
}
|
118
|
+
},
|
119
|
+
{
|
120
|
+
type: 'button',
|
121
|
+
props: {
|
122
|
+
onClick: () => setCount(count + 1),
|
123
|
+
style: {
|
124
|
+
padding: '8px 16px',
|
125
|
+
backgroundColor: '#4d79ff',
|
126
|
+
color: 'white',
|
127
|
+
border: 'none',
|
128
|
+
borderRadius: '4px',
|
129
|
+
cursor: 'pointer'
|
130
|
+
},
|
131
|
+
children: 'Increment'
|
132
|
+
}
|
133
|
+
}
|
134
|
+
]
|
135
|
+
}
|
136
|
+
}
|
137
|
+
]
|
138
|
+
}
|
139
|
+
}
|
140
|
+
]
|
141
|
+
}
|
142
|
+
};
|
117
143
|
}
|
@@ -141,21 +141,13 @@ function ContextConsumer() {
|
|
141
141
|
);
|
142
142
|
}
|
143
143
|
|
144
|
-
import { render
|
144
|
+
import { render } from 'frontend-hamroun';
|
145
145
|
import { App } from './App';
|
146
146
|
|
147
|
-
// Create an example context
|
148
|
-
export const AppContext = createContext({ theme: 'light' });
|
149
|
-
|
150
147
|
document.addEventListener('DOMContentLoaded', () => {
|
151
148
|
const rootElement = document.getElementById('app');
|
152
149
|
if (rootElement) {
|
153
|
-
render(
|
154
|
-
<AppContext.Provider value={{ theme: 'light' }}>
|
155
|
-
<App />
|
156
|
-
</AppContext.Provider>,
|
157
|
-
rootElement
|
158
|
-
);
|
150
|
+
render(App({}), rootElement);
|
159
151
|
console.log('App rendered successfully');
|
160
152
|
}
|
161
153
|
});
|
@@ -2,31 +2,19 @@ import { defineConfig } from 'vite';
|
|
2
2
|
import { nodePolyfills } from 'vite-plugin-node-polyfills';
|
3
3
|
|
4
4
|
export default defineConfig({
|
5
|
-
esbuild: {
|
6
|
-
jsxFactory: 'jsx',
|
7
|
-
jsxFragment: 'Fragment',
|
8
|
-
jsxInject: `import { jsx, Fragment } from 'frontend-hamroun'`
|
9
|
-
},
|
10
5
|
build: {
|
11
6
|
outDir: 'dist',
|
12
7
|
emptyOutDir: true,
|
13
8
|
rollupOptions: {
|
14
|
-
// Mark server dependencies as external
|
9
|
+
// Mark server-side dependencies as external
|
15
10
|
external: [
|
16
|
-
'mock-aws-s3',
|
17
|
-
'aws-sdk',
|
18
|
-
'nock',
|
19
|
-
'jest',
|
20
|
-
'jest-mock',
|
21
|
-
'@testing-library/react',
|
22
|
-
'@testing-library/jest-dom',
|
23
|
-
'bcrypt',
|
24
|
-
'jsonwebtoken',
|
25
|
-
'mongoose',
|
26
11
|
'express',
|
27
12
|
'compression',
|
28
13
|
'helmet',
|
29
14
|
'morgan',
|
15
|
+
'bcrypt',
|
16
|
+
'jsonwebtoken',
|
17
|
+
'mongoose',
|
30
18
|
/node:.*/
|
31
19
|
]
|
32
20
|
}
|