baraqex 1.0.74 → 2.0.0

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 (185) hide show
  1. package/CHANGELOG.md +73 -0
  2. package/README.md +272 -472
  3. package/bin/baraqex.js +150 -12
  4. package/dist/browser.d.ts +1 -1
  5. package/dist/browser.d.ts.map +1 -1
  6. package/dist/browser.js +2319 -205
  7. package/dist/browser.js.map +4 -4
  8. package/dist/core/batch.d.ts +10 -0
  9. package/dist/core/batch.d.ts.map +1 -0
  10. package/dist/core/component.d.ts +69 -0
  11. package/dist/core/component.d.ts.map +1 -0
  12. package/dist/core/context.d.ts +22 -0
  13. package/dist/core/context.d.ts.map +1 -0
  14. package/dist/core/errors.d.ts +125 -0
  15. package/dist/core/errors.d.ts.map +1 -0
  16. package/dist/core/event-bus.d.ts +29 -0
  17. package/dist/core/event-bus.d.ts.map +1 -0
  18. package/dist/core/forms.d.ts +128 -0
  19. package/dist/core/forms.d.ts.map +1 -0
  20. package/dist/core/hooks.d.ts +84 -0
  21. package/dist/core/hooks.d.ts.map +1 -0
  22. package/dist/core/index.d.ts +23 -0
  23. package/dist/core/index.d.ts.map +1 -0
  24. package/dist/core/jsx-runtime.d.ts +45 -0
  25. package/dist/core/jsx-runtime.d.ts.map +1 -0
  26. package/dist/core/lifecycle-events.d.ts +71 -0
  27. package/dist/core/lifecycle-events.d.ts.map +1 -0
  28. package/dist/core/renderer.d.ts +39 -0
  29. package/dist/core/renderer.d.ts.map +1 -0
  30. package/dist/core/router.d.ts +108 -0
  31. package/dist/core/router.d.ts.map +1 -0
  32. package/dist/core/server-renderer.d.ts +26 -0
  33. package/dist/core/server-renderer.d.ts.map +1 -0
  34. package/dist/core/store.d.ts +102 -0
  35. package/dist/core/store.d.ts.map +1 -0
  36. package/dist/core/types.d.ts +66 -0
  37. package/dist/core/types.d.ts.map +1 -0
  38. package/dist/core/utils.d.ts +153 -0
  39. package/dist/core/utils.d.ts.map +1 -0
  40. package/dist/core/vdom.d.ts +29 -0
  41. package/dist/core/vdom.d.ts.map +1 -0
  42. package/dist/index.d.ts +39 -35
  43. package/dist/index.d.ts.map +1 -1
  44. package/dist/index.js +2592 -508
  45. package/dist/index.js.map +4 -4
  46. package/dist/server/auth.d.ts +8 -3
  47. package/dist/server/auth.d.ts.map +1 -1
  48. package/dist/server/index.d.ts +2 -2
  49. package/dist/server/index.d.ts.map +1 -1
  50. package/dist/server/index.js +173 -112
  51. package/dist/server/index.js.map +4 -4
  52. package/dist/server/middleware.d.ts +10 -1
  53. package/dist/server/middleware.d.ts.map +1 -1
  54. package/package.json +224 -124
  55. package/templates/basic-app/src/main.jsx +336 -0
  56. package/templates/complete-app/api/hello.js +0 -0
  57. package/templates/complete-app/client.js +58 -0
  58. package/templates/complete-app/lib/frontend-hamroun.js +182 -0
  59. package/templates/complete-app/package.json +18 -0
  60. package/templates/complete-app/pages/about.js +119 -0
  61. package/templates/complete-app/pages/about.jsx +0 -0
  62. package/templates/complete-app/pages/index.js +157 -0
  63. package/templates/complete-app/pages/index.jsx +0 -0
  64. package/templates/complete-app/pages/wasm-demo.js +290 -0
  65. package/templates/complete-app/pages/wasm-demo.jsx +0 -0
  66. package/templates/complete-app/public/client.js +89 -0
  67. package/templates/complete-app/public/index.html +118 -0
  68. package/templates/complete-app/public/styles.css +76 -0
  69. package/templates/complete-app/readme.md +188 -0
  70. package/templates/complete-app/server.js +226 -0
  71. package/templates/complete-app/server.ts +275 -0
  72. package/templates/complete-app/src/App.tsx +59 -0
  73. package/templates/complete-app/src/client.ts +61 -0
  74. package/templates/complete-app/src/client.tsx +18 -0
  75. package/templates/complete-app/src/pages/index.tsx +51 -0
  76. package/templates/complete-app/src/server.ts +218 -0
  77. package/templates/complete-app/tsconfig.json +22 -0
  78. package/templates/complete-app/tsconfig.server.json +19 -0
  79. package/templates/complete-app/vite.config.js +57 -0
  80. package/templates/complete-app/vite.config.ts +30 -0
  81. package/templates/complete-app/wasm/build.bat +0 -0
  82. package/templates/complete-app/wasm/build.sh +0 -0
  83. package/templates/complete-app/wasm/example.go +0 -0
  84. package/templates/fullstack-app/README.md +37 -0
  85. package/templates/fullstack-app/api/hello.js +11 -0
  86. package/templates/fullstack-app/api/hello.ts +18 -0
  87. package/templates/fullstack-app/api/users/[id].ts +73 -0
  88. package/templates/fullstack-app/api/users/index.ts +32 -0
  89. package/templates/fullstack-app/build/main.css +874 -0
  90. package/templates/fullstack-app/build/main.css.map +7 -0
  91. package/templates/fullstack-app/build/main.js +967 -0
  92. package/templates/fullstack-app/build/main.js.map +7 -0
  93. package/templates/fullstack-app/build.ts +210 -0
  94. package/templates/fullstack-app/index.html +36 -0
  95. package/templates/fullstack-app/package.json +35 -0
  96. package/templates/fullstack-app/postcss.config.js +6 -0
  97. package/templates/fullstack-app/process-tailwind.js +45 -0
  98. package/templates/fullstack-app/public/_redirects +1 -0
  99. package/templates/fullstack-app/public/route-handler.js +47 -0
  100. package/templates/fullstack-app/public/spa-fix.html +17 -0
  101. package/templates/fullstack-app/public/styles.css +975 -0
  102. package/templates/fullstack-app/public/tailwind.css +15 -0
  103. package/templates/fullstack-app/server.js +267 -0
  104. package/templates/fullstack-app/server.ts +474 -0
  105. package/templates/fullstack-app/src/README.md +55 -0
  106. package/templates/fullstack-app/src/client.js +87 -0
  107. package/templates/fullstack-app/src/components/ClientHome.tsx +0 -0
  108. package/templates/fullstack-app/src/components/ErrorBoundary.tsx +36 -0
  109. package/templates/fullstack-app/src/components/Layout.tsx +42 -0
  110. package/templates/fullstack-app/src/components/StateDemo.tsx +207 -0
  111. package/templates/fullstack-app/src/components/UserList.tsx +44 -0
  112. package/templates/fullstack-app/src/config.ts +42 -0
  113. package/templates/fullstack-app/src/data/api.ts +206 -0
  114. package/templates/fullstack-app/src/main.tsx +155 -0
  115. package/templates/fullstack-app/src/middleware.ts +28 -0
  116. package/templates/fullstack-app/src/pages/404.tsx +28 -0
  117. package/templates/fullstack-app/src/pages/[id].tsx +0 -0
  118. package/templates/fullstack-app/src/pages/_app.tsx +11 -0
  119. package/templates/fullstack-app/src/pages/_document.tsx +25 -0
  120. package/templates/fullstack-app/src/pages/_error.tsx +45 -0
  121. package/templates/fullstack-app/src/pages/about/index.tsx +67 -0
  122. package/templates/fullstack-app/src/pages/about.tsx +71 -0
  123. package/templates/fullstack-app/src/pages/api/users/[id].ts +73 -0
  124. package/templates/fullstack-app/src/pages/api/users/index.ts +43 -0
  125. package/templates/fullstack-app/src/pages/index.tsx +110 -0
  126. package/templates/fullstack-app/src/pages/users/[id].tsx +153 -0
  127. package/templates/fullstack-app/src/pages/users.tsx +60 -0
  128. package/templates/fullstack-app/src/pages/wasm-demo.tsx +1 -0
  129. package/templates/fullstack-app/src/router.ts +255 -0
  130. package/templates/fullstack-app/src/styles.css +5 -0
  131. package/templates/fullstack-app/tailwind.config.js +11 -0
  132. package/templates/fullstack-app/tsconfig.json +18 -0
  133. package/templates/fullstack-app/vite.config.js +87 -0
  134. package/templates/go/build.bat +36 -0
  135. package/templates/go/build.sh +43 -0
  136. package/templates/go/example.go +205 -0
  137. package/templates/go-wasm-app/README.md +38 -0
  138. package/templates/go-wasm-app/babel.config.js +21 -0
  139. package/templates/go-wasm-app/build-client.js +49 -0
  140. package/templates/go-wasm-app/build-wasm.js +237 -0
  141. package/templates/go-wasm-app/build.config.js +62 -0
  142. package/templates/go-wasm-app/build.js +218 -0
  143. package/templates/go-wasm-app/package.json +32 -0
  144. package/templates/go-wasm-app/public/index.html +128 -0
  145. package/templates/go-wasm-app/public/styles.css +197 -0
  146. package/templates/go-wasm-app/public/wasm/example.wasm +0 -0
  147. package/templates/go-wasm-app/public/wasm/wasm_exec.js +561 -0
  148. package/templates/go-wasm-app/public/wasm/wasm_exec_node.js +39 -0
  149. package/templates/go-wasm-app/server.js +70 -0
  150. package/templates/go-wasm-app/src/App.jsx +38 -0
  151. package/templates/go-wasm-app/src/app.js +173 -0
  152. package/templates/go-wasm-app/src/client.js +57 -0
  153. package/templates/go-wasm-app/src/components/Footer.jsx +13 -0
  154. package/templates/go-wasm-app/src/components/Header.jsx +19 -0
  155. package/templates/go-wasm-app/src/components/WasmDemo.jsx +120 -0
  156. package/templates/go-wasm-app/src/main.jsx +12 -0
  157. package/templates/go-wasm-app/src/wasm/example.go +75 -0
  158. package/templates/go-wasm-app/tsconfig.server.json +18 -0
  159. package/templates/go-wasm-app/vite.config.js +45 -0
  160. package/templates/ssr-template/package.json +16 -10
  161. package/templates/wasm/package.json +43 -43
  162. package/templates/wasm/src/App.tsx +2 -2
  163. package/dist/forms/index.d.ts +0 -2
  164. package/dist/forms/index.d.ts.map +0 -1
  165. package/dist/forms/types.d.ts +0 -2
  166. package/dist/forms/types.d.ts.map +0 -1
  167. package/dist/frontend/components/WasmLoader.d.ts +0 -2
  168. package/dist/frontend/components/WasmLoader.d.ts.map +0 -1
  169. package/dist/frontend/hooks/useWasm.d.ts +0 -2
  170. package/dist/frontend/hooks/useWasm.d.ts.map +0 -1
  171. package/dist/frontend/index.d.ts +0 -2
  172. package/dist/frontend/index.d.ts.map +0 -1
  173. package/dist/router/index.d.ts +0 -2
  174. package/dist/router/index.d.ts.map +0 -1
  175. package/dist/router/types.d.ts +0 -2
  176. package/dist/router/types.d.ts.map +0 -1
  177. package/dist/store/index.d.ts +0 -2
  178. package/dist/store/index.d.ts.map +0 -1
  179. package/dist/store/types.d.ts +0 -2
  180. package/dist/store/types.d.ts.map +0 -1
  181. package/templates/basic-app/package-lock.json +0 -7173
  182. package/templates/fullstack-template/package-lock.json +0 -3558
  183. package/templates/ssr-template/package-lock.json +0 -5380
  184. package/templates/wasm/package-lock.json +0 -5347
  185. package/templates/wasm/public/example.wasm +0 -0
@@ -0,0 +1,336 @@
1
+ import { render, useState, useEffect, useMemo, useRef, useErrorBoundary, createContext, useContext } from 'baraqex';
2
+ import './main.css';
3
+ // Create a theme context with proper typing
4
+ const ThemeContext = createContext('light');
5
+ // Main App Component - Fix the tab rendering logic
6
+ function App() {
7
+ const [activeTab, setActiveTab] = useState('counter');
8
+ const [theme, setTheme] = useState('light');
9
+ const [error, resetError] = useErrorBoundary();
10
+ useEffect(() => {
11
+ document.title = `Baraqex Demo - ${activeTab.charAt(0).toUpperCase() + activeTab.slice(1)}`;
12
+ }, [activeTab]);
13
+ // Add debug logging for theme changes
14
+ useEffect(() => {
15
+ console.log('Theme changed to:', theme);
16
+ }, [theme]);
17
+ // Add debug logging for tab changes
18
+ useEffect(() => {
19
+ console.log('Active tab changed to:', activeTab);
20
+ }, [activeTab]);
21
+ if (error) {
22
+ return (<div className="min-h-screen bg-gradient-to-br from-red-50 to-red-100 flex items-center justify-center">
23
+ <div className="card max-w-md mx-auto text-center">
24
+ <div className="text-6xl mb-4">🚨</div>
25
+ <h1 className="text-2xl font-bold text-red-600 mb-4">Oops! Something went wrong</h1>
26
+ <p className="text-gray-600 mb-4">
27
+ {error.message || 'An unexpected error occurred'}
28
+ </p>
29
+ <button onClick={resetError} className="btn btn-primary">
30
+ Try Again
31
+ </button>
32
+ </div>
33
+ </div>);
34
+ }
35
+ // Function to render the current tab content
36
+ const renderTabContent = () => {
37
+ console.log('Rendering tab content for:', activeTab);
38
+ switch (activeTab) {
39
+ case 'counter':
40
+ console.log('Rendering Counter component');
41
+ return <Counter />;
42
+ case 'error':
43
+ console.log('Rendering BuggyComponent');
44
+ return <BuggyComponent />;
45
+ case 'context':
46
+ console.log('Rendering ContextConsumer component');
47
+ return <ContextConsumer />;
48
+ default:
49
+ console.log('Unknown tab, rendering Counter as fallback');
50
+ return <Counter />;
51
+ }
52
+ };
53
+ return (<ThemeContext.Provider value={theme}>
54
+ <div className={`min-h-screen transition-colors ${theme === 'dark'
55
+ ? 'bg-gradient-to-br from-gray-900 to-gray-800'
56
+ : 'bg-gradient-to-br from-blue-50 to-indigo-100'}`}>
57
+ <div className="container mx-auto px-4 py-8">
58
+
59
+ {/* Header with Logo */}
60
+ <header className="text-center mb-12">
61
+ <div className="flex items-center justify-center mb-6">
62
+ <img src="/logo.png" alt="Baraqex Logo" className="w-16 h-16 mr-4 rounded-lg shadow-lg" onError={(e) => {
63
+ // Fallback to emoji if logo doesn't exist
64
+ e.target.style.display = 'none';
65
+ e.target.nextElementSibling.style.display = 'block';
66
+ }}/>
67
+ <div className="text-6xl" style={{ display: 'none' }}>🚀</div>
68
+ <div>
69
+ <h1 className={`text-5xl font-bold mb-2 ${theme === 'dark' ? 'text-white' : 'text-gray-800'}`}>
70
+ Baraqex
71
+ </h1>
72
+ <p className={`text-xl ${theme === 'dark' ? 'text-gray-300' : 'text-gray-600'}`}>
73
+ Powered by Frontend Hamroun
74
+ </p>
75
+ </div>
76
+ </div>
77
+
78
+ {/* About Baraqex */}
79
+ <div className="card max-w-4xl mx-auto mb-8">
80
+ <h2 className="text-2xl font-bold text-gray-800 mb-6 text-center">
81
+ Welcome to Baraqex Framework! 🎉
82
+ </h2>
83
+ <div className="grid grid-cols-1 md:grid-cols-2 gap-8 text-left">
84
+ <div>
85
+ <h3 className="text-lg font-semibold text-primary-600 mb-3">🚀 What is Baraqex?</h3>
86
+ <p className="text-gray-700 leading-relaxed mb-4">
87
+ Baraqex is a powerful, modern full-stack framework built on top of the Frontend Hamroun library.
88
+ It provides everything you need to build high-performance web applications with ease.
89
+ </p>
90
+ <p className="text-gray-700 leading-relaxed">
91
+ From simple SPAs to complex server-side rendered applications with WebAssembly integration,
92
+ Baraqex has you covered with a developer-friendly API and excellent performance.
93
+ </p>
94
+ </div>
95
+ <div>
96
+ <h3 className="text-lg font-semibold text-primary-600 mb-3">✨ Key Features</h3>
97
+ <ul className="space-y-2 text-gray-700">
98
+ <li className="flex items-center">
99
+ <span className="text-green-500 mr-2">✓</span>
100
+ Reactive state management with hooks
101
+ </li>
102
+ <li className="flex items-center">
103
+ <span className="text-green-500 mr-2">✓</span>
104
+ Server-side rendering (SSR) support
105
+ </li>
106
+ <li className="flex items-center">
107
+ <span className="text-green-500 mr-2">✓</span>
108
+ WebAssembly (WASM) integration
109
+ </li>
110
+ <li className="flex items-center">
111
+ <span className="text-green-500 mr-2">✓</span>
112
+ Built-in authentication & database support
113
+ </li>
114
+ <li className="flex items-center">
115
+ <span className="text-green-500 mr-2">✓</span>
116
+ TypeScript support out of the box
117
+ </li>
118
+ <li className="flex items-center">
119
+ <span className="text-green-500 mr-2">✓</span>
120
+ Production-ready with optimized builds
121
+ </li>
122
+ </ul>
123
+ </div>
124
+ </div>
125
+
126
+ <div className="mt-8 text-center">
127
+ <button onClick={() => {
128
+ const newTheme = theme === 'light' ? 'dark' : 'light';
129
+ console.log('Theme toggle clicked, changing from', theme, 'to', newTheme);
130
+ setTheme(newTheme);
131
+ }} className={`btn ${theme === 'dark' ? 'bg-yellow-400 text-gray-900 hover:bg-yellow-300' : 'bg-gray-800 text-white hover:bg-gray-700'}`}>
132
+ 🌙 Toggle {theme === 'light' ? 'Dark' : 'Light'} Mode
133
+ </button>
134
+ </div>
135
+ </div>
136
+ </header>
137
+
138
+ {/* Tab Navigation */}
139
+ <div className="flex justify-center mb-8">
140
+ <div className="bg-white rounded-lg shadow-sm p-1 flex space-x-1 overflow-x-auto">
141
+ {[
142
+ { id: 'counter', label: 'Counter', icon: '🔢' },
143
+ { id: 'error', label: 'Error Test', icon: '🚨' },
144
+ { id: 'context', label: 'Context', icon: '🔄' }
145
+ ].map(tab => (<button key={tab.id} onClick={() => {
146
+ console.log('Tab clicked:', tab.id, 'current activeTab:', activeTab);
147
+ setActiveTab(tab.id);
148
+ }} className={`px-4 py-2 rounded-md transition-colors whitespace-nowrap ${activeTab === tab.id
149
+ ? 'bg-primary-500 text-white'
150
+ : 'text-gray-600 hover:text-gray-800 hover:bg-gray-100'}`}>
151
+ <span className="mr-2">{tab.icon}</span>
152
+ {tab.label}
153
+ </button>))}
154
+ </div>
155
+ </div>
156
+
157
+ {/* Tab Content - Use the function to render content */}
158
+ <div className="flex justify-center mb-12">
159
+ {renderTabContent()}
160
+ </div>
161
+
162
+ {/* Footer */}
163
+ <footer className="text-center">
164
+ <div className="card max-w-4xl mx-auto">
165
+ <h3 className="text-xl font-semibold text-gray-800 mb-6">
166
+ 🎯 Framework Capabilities Demo
167
+ </h3>
168
+
169
+ <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-8">
170
+ <div className="text-center">
171
+ <div className="text-3xl mb-2">⚡</div>
172
+ <h4 className="font-semibold text-gray-800 mb-2">State Management</h4>
173
+ <p className="text-sm text-gray-600">
174
+ useState, useEffect, useMemo, and useRef hooks working seamlessly
175
+ </p>
176
+ </div>
177
+ <div className="text-center">
178
+ <div className="text-3xl mb-2">🎨</div>
179
+ <h4 className="font-semibold text-gray-800 mb-2">Tailwind CSS</h4>
180
+ <p className="text-sm text-gray-600">
181
+ Utility-first CSS framework integrated for rapid UI development
182
+ </p>
183
+ </div>
184
+ <div className="text-center">
185
+ <div className="text-3xl mb-2">🛡️</div>
186
+ <h4 className="font-semibold text-gray-800 mb-2">Error Boundaries</h4>
187
+ <p className="text-sm text-gray-600">
188
+ Graceful error handling with useErrorBoundary hook
189
+ </p>
190
+ </div>
191
+ <div className="text-center">
192
+ <div className="text-3xl mb-2">🔄</div>
193
+ <h4 className="font-semibold text-gray-800 mb-2">Context API</h4>
194
+ <p className="text-sm text-gray-600">
195
+ Share state across components with createContext and useContext
196
+ </p>
197
+ </div>
198
+ </div>
199
+
200
+ <div className="border-t pt-6">
201
+ <h4 className="font-semibold text-gray-800 mb-4">🚀 Ready to build something amazing?</h4>
202
+ <p className="text-gray-600 mb-4">
203
+ Edit <code className="bg-gray-100 px-2 py-1 rounded text-sm">src/main.tsx</code> to customize this app,
204
+ or create new components to expand your application.
205
+ </p>
206
+ <div className="flex justify-center space-x-4">
207
+ <a href="https://www.baraqex.tech/docs" target="_blank" rel="noopener noreferrer" className="text-primary-600 hover:text-primary-800 font-medium">
208
+ 📚 Documentation
209
+ </a>
210
+ <a href="https://github.com/mohamedx2/baraqex" target="_blank" rel="noopener noreferrer" className="text-primary-600 hover:text-primary-800 font-medium">
211
+ 🐙 GitHub
212
+ </a>
213
+ <a href="https://www.baraqex.tech/examples" target="_blank" rel="noopener noreferrer" className="text-primary-600 hover:text-primary-800 font-medium">
214
+ 🎯 Examples
215
+ </a>
216
+ </div>
217
+ </div>
218
+ </div>
219
+ </footer>
220
+ </div>
221
+ </div>
222
+ </ThemeContext.Provider>);
223
+ }
224
+ // Simple Counter Component with Tailwind styles - Fixed hooks
225
+ function Counter() {
226
+ // Initialize with proper values and ensure hooks work correctly
227
+ const [count, setCount] = useState(0);
228
+ const renderCount = useRef(0);
229
+ useEffect(() => {
230
+ renderCount.current = (renderCount.current || 0) + 1;
231
+ console.log('Counter effect running, count:', count, 'renders:', renderCount.current);
232
+ }, [count]);
233
+ // Ensure count is a number before calculation
234
+ const doubled = useMemo(() => {
235
+ const numCount = typeof count === 'number' ? count : 0;
236
+ console.log('Calculating doubled for count:', numCount);
237
+ return numCount * 2;
238
+ }, [count]);
239
+ // Add debug logging
240
+ console.log('Counter render - count:', count, 'doubled:', doubled, 'renders:', renderCount.current);
241
+ return (<div className="card max-w-sm mx-auto">
242
+ <h2 className="text-2xl font-bold text-gray-800 mb-4 text-center">
243
+ Counter Example
244
+ </h2>
245
+ <div className="text-center">
246
+ <div className="text-4xl font-bold text-primary-600 mb-6">
247
+ {typeof count === 'number' ? count : 0}
248
+ </div>
249
+ <div className="mb-4">
250
+ <p className="text-sm text-gray-600 mb-2">
251
+ Doubled: {typeof doubled === 'number' ? doubled : 'Error'}
252
+ </p>
253
+ <p className="text-sm text-gray-600">
254
+ Renders: {renderCount.current || 0}
255
+ </p>
256
+ </div>
257
+ <div className="space-x-2">
258
+ <button onClick={() => {
259
+ console.log('Increment clicked, current count:', count);
260
+ const newCount = (typeof count === 'number' ? count : 0) + 1;
261
+ console.log('Setting new count:', newCount);
262
+ setCount(newCount);
263
+ }} className="btn btn-primary">
264
+ Increment
265
+ </button>
266
+ <button onClick={() => {
267
+ console.log('Decrement clicked, current count:', count);
268
+ const newCount = (typeof count === 'number' ? count : 0) - 1;
269
+ console.log('Setting new count:', newCount);
270
+ setCount(newCount);
271
+ }} className="btn btn-secondary">
272
+ Decrement
273
+ </button>
274
+ <button onClick={() => {
275
+ console.log('Reset clicked');
276
+ setCount(0);
277
+ }} className="btn btn-danger">
278
+ Reset
279
+ </button>
280
+ </div>
281
+ </div>
282
+ </div>);
283
+ }
284
+ // Error boundary test component with debugging
285
+ function BuggyComponent() {
286
+ console.log('BuggyComponent rendering...');
287
+ const [shouldError, setShouldError] = useState(false);
288
+ if (shouldError) {
289
+ throw new Error("Test error from BuggyComponent");
290
+ }
291
+ return (<div className="card max-w-sm mx-auto">
292
+ <h3 className="text-lg font-semibold text-gray-800 mb-4 text-center">
293
+ Error Boundary Test
294
+ </h3>
295
+ <p className="text-sm text-gray-600 mb-4 text-center">
296
+ Click the button below to test error handling
297
+ </p>
298
+ <div className="text-center">
299
+ <button onClick={() => {
300
+ console.log('Triggering error...');
301
+ setShouldError(true);
302
+ }} className="btn btn-danger">
303
+ Trigger Error
304
+ </button>
305
+ </div>
306
+ </div>);
307
+ }
308
+ // Context test component - fixed to properly extract theme value
309
+ function ContextConsumer() {
310
+ const theme = useContext(ThemeContext);
311
+ // Extract the actual theme value - handle both direct values and wrapped objects
312
+ const actualTheme = typeof theme === 'object' && theme !== null
313
+ ? theme.value || 'light'
314
+ : (typeof theme === 'string' ? theme : 'light');
315
+ console.log('Context consumer - raw theme:', theme, 'actual theme:', actualTheme);
316
+ return (<div className="card max-w-sm mx-auto">
317
+ <h3 className="text-lg font-semibold text-gray-800 mb-4 text-center">
318
+ Context API Test
319
+ </h3>
320
+ <div className={`p-4 rounded-md border text-center ${actualTheme === 'dark' ? 'border-gray-600 bg-gray-700 text-white' : 'border-gray-300 bg-gray-50'}`}>
321
+ <p className="text-sm mb-2">Current theme: <strong>{actualTheme}</strong></p>
322
+ <p className="text-xs text-gray-500">
323
+ Theme is provided by Context API
324
+ </p>
325
+ </div>
326
+ </div>);
327
+ }
328
+ // Mount the app with null check and debug logging
329
+ const rootElement = document.getElementById('root');
330
+ if (rootElement) {
331
+ console.log('Mounting app to root element');
332
+ render(<App />, rootElement);
333
+ }
334
+ else {
335
+ console.error('Root element not found');
336
+ }
File without changes
@@ -0,0 +1,58 @@
1
+ import { hydrate, jsx } from 'frontend-hamroun';
2
+
3
+ // Create a sample virtual DOM matching what was rendered on the server
4
+ const app = {
5
+ type: 'div',
6
+ props: {
7
+ id: 'app',
8
+ children: [
9
+ {
10
+ type: 'h1',
11
+ props: {
12
+ children: 'Hello from Server-Side Rendering!'
13
+ }
14
+ },
15
+ {
16
+ type: 'p',
17
+ props: {
18
+ children: `This page was rendered at ${new Date().toISOString()}`
19
+ }
20
+ },
21
+ {
22
+ type: 'button',
23
+ props: {
24
+ id: 'counter-btn',
25
+ className: 'btn',
26
+ onClick: () => {
27
+ let count = 1; // Start at 1 since we're updating
28
+ const btn = document.getElementById('counter-btn');
29
+ if (btn) {
30
+ btn.textContent = `Click me (${count})`;
31
+ btn.addEventListener('click', () => {
32
+ count++;
33
+ btn.textContent = `Click me (${count})`;
34
+ });
35
+ }
36
+ },
37
+ children: 'Click me (0)'
38
+ }
39
+ }
40
+ ]
41
+ }
42
+ };
43
+
44
+ // Wait for DOM to be fully loaded before hydrating
45
+ window.addEventListener('DOMContentLoaded', () => {
46
+ console.log('Hydrating client-side content...');
47
+
48
+ // Get the container element
49
+ const container = document.getElementById('app');
50
+ if (!container) {
51
+ console.error('Could not find app container for hydration');
52
+ return;
53
+ }
54
+
55
+ // Hydrate the app
56
+ hydrate(app, container);
57
+ console.log('Hydration complete!');
58
+ });
@@ -0,0 +1,182 @@
1
+ /**
2
+ * Simple JSX implementation for server-side rendering
3
+ */
4
+
5
+ // Render a virtual DOM node to HTML string
6
+ export function renderToString(vnode) {
7
+ // Handle null or undefined
8
+ if (vnode == null) return '';
9
+
10
+ // Handle primitive values
11
+ if (typeof vnode === 'string' || typeof vnode === 'number')
12
+ return escapeHtml(String(vnode));
13
+
14
+ // Handle arrays (like fragments)
15
+ if (Array.isArray(vnode))
16
+ return vnode.map(renderToString).join('');
17
+
18
+ // Handle functional components
19
+ if (typeof vnode.type === 'function') {
20
+ try {
21
+ const result = vnode.type(vnode.props || {});
22
+ return renderToString(result);
23
+ } catch (err) {
24
+ console.error('Error rendering component:', err);
25
+ return `<div class="error">Error: ${escapeHtml(err.message)}</div>`;
26
+ }
27
+ }
28
+
29
+ // Handle Fragment
30
+ if (vnode.type === Symbol.for('react.fragment')) {
31
+ return renderToString(vnode.props.children);
32
+ }
33
+
34
+ // Handle regular DOM elements
35
+ if (typeof vnode.type === 'string') {
36
+ let props = vnode.props || {};
37
+ let children = props.children || [];
38
+ if (!Array.isArray(children)) {
39
+ children = [children];
40
+ }
41
+
42
+ // Build opening tag with attributes
43
+ let html = `<${vnode.type}`;
44
+
45
+ for (const [key, value] of Object.entries(props)) {
46
+ if (key === 'children' || key === 'dangerouslySetInnerHTML') continue;
47
+
48
+ // Handle event handlers (they should be ignored in SSR)
49
+ if (key.startsWith('on')) continue;
50
+
51
+ // Handle className -> class
52
+ if (key === 'className') {
53
+ html += ` class="${escapeHtml(value)}"`;
54
+ continue;
55
+ }
56
+
57
+ // Handle style objects
58
+ if (key === 'style' && typeof value === 'object') {
59
+ const styleStr = Object.entries(value)
60
+ .map(([k, v]) => `${kebabCase(k)}:${v}`)
61
+ .join(';');
62
+ html += ` style="${escapeHtml(styleStr)}"`;
63
+ continue;
64
+ }
65
+
66
+ // Handle boolean attributes
67
+ if (value === true) {
68
+ html += ` ${key}`;
69
+ continue;
70
+ }
71
+
72
+ // Skip false boolean attributes
73
+ if (value === false) continue;
74
+
75
+ // Regular attributes
76
+ if (value != null) {
77
+ html += ` ${key}="${escapeHtml(value)}"`;
78
+ }
79
+ }
80
+
81
+ // Handle self-closing tags
82
+ const selfClosing = ['img', 'input', 'br', 'hr', 'meta', 'link', 'area', 'base', 'col', 'embed', 'param', 'source', 'track', 'wbr'];
83
+ if (selfClosing.includes(vnode.type)) {
84
+ return `${html} />`;
85
+ }
86
+
87
+ // Add closing bracket for opening tag
88
+ html += '>';
89
+
90
+ // Handle dangerouslySetInnerHTML
91
+ if (props.dangerouslySetInnerHTML) {
92
+ html += props.dangerouslySetInnerHTML.__html || '';
93
+ } else {
94
+ // Add children
95
+ for (const child of children) {
96
+ html += renderToString(child);
97
+ }
98
+ }
99
+
100
+ // Add closing tag
101
+ html += `</${vnode.type}>`;
102
+
103
+ return html;
104
+ }
105
+
106
+ // Unknown node type
107
+ console.warn('Unknown vnode type:', vnode.type);
108
+ return '';
109
+ }
110
+
111
+ // Create a JSX element
112
+ export function jsx(type, props, ...children) {
113
+ props = props || {};
114
+ if (children.length) {
115
+ props.children = children.length === 1 ? children[0] : children;
116
+ }
117
+ return { type, props };
118
+ }
119
+
120
+ // Helper for escaping HTML
121
+ function escapeHtml(str) {
122
+ return String(str)
123
+ .replace(/&/g, '&amp;')
124
+ .replace(/</g, '&lt;')
125
+ .replace(/>/g, '&gt;')
126
+ .replace(/"/g, '&quot;')
127
+ .replace(/'/g, '&#039;');
128
+ }
129
+
130
+ // Helper to convert camelCase to kebab-case for CSS properties
131
+ function kebabCase(str) {
132
+ return str.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase();
133
+ }
134
+
135
+ // Create a basic requestLogger middleware
136
+ export function requestLogger(req, res, next) {
137
+ console.log(`${new Date().toISOString()} - ${req.method} ${req.url}`);
138
+ next();
139
+ }
140
+
141
+ // Create a basic error handler middleware
142
+ export function errorHandler(err, req, res, next) {
143
+ console.error('Server error:', err);
144
+ res.status(500).send('Server Error');
145
+ }
146
+
147
+ // Create a basic 404 handler middleware
148
+ export function notFoundHandler(req, res) {
149
+ res.status(404).send('Not Found');
150
+ }
151
+
152
+ // Create a basic rate limiter middleware
153
+ export function rateLimit(options = { windowMs: 60000, max: 100 }) {
154
+ const requests = new Map();
155
+
156
+ return (req, res, next) => {
157
+ const ip = req.ip || 'unknown';
158
+ const now = Date.now();
159
+
160
+ if (!requests.has(ip)) {
161
+ requests.set(ip, []);
162
+ }
163
+
164
+ const reqs = requests.get(ip);
165
+ const validReqs = reqs.filter(time => now - time < options.windowMs);
166
+
167
+ validReqs.push(now);
168
+ requests.set(ip, validReqs);
169
+
170
+ if (validReqs.length > options.max) {
171
+ return res.status(429).send('Too Many Requests');
172
+ }
173
+
174
+ next();
175
+ };
176
+ }
177
+
178
+ // Export other necessary functions
179
+ export const Fragment = Symbol.for('react.fragment');
180
+ export function loadGoWasmFromFile() {
181
+ throw new Error('WASM not supported in this environment');
182
+ }
@@ -0,0 +1,18 @@
1
+ {
2
+ "name": "ssr-app",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "scripts": {
6
+ "dev": "node server.js",
7
+ "start": "node server.js",
8
+ "build": "echo 'No build step required for this template'"
9
+ },
10
+ "dependencies": {
11
+ "compression": "^1.8.0",
12
+ "cors": "^2.8.5",
13
+ "dotenv": "^16.0.3",
14
+ "express": "^4.18.2",
15
+ "frontend-hamroun": "^1.2.79",
16
+ "node-fetch": "^3.3.1"
17
+ }
18
+ }