frontend-hamroun 1.2.79 → 1.2.80

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 (219) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +129 -1513
  3. package/bin/cli.js +505 -144
  4. package/dist/index.cjs +2 -0
  5. package/dist/index.cjs.map +1 -0
  6. package/dist/index.client.cjs +2 -0
  7. package/dist/index.client.cjs.map +1 -0
  8. package/dist/index.client.js +26 -0
  9. package/dist/index.client.js.map +1 -0
  10. package/dist/index.js +298 -1
  11. package/dist/index.js.map +1 -0
  12. package/dist/jsx-runtime.cjs +2 -0
  13. package/dist/jsx-runtime.cjs.map +1 -0
  14. package/dist/jsx-runtime.js +93 -1
  15. package/dist/jsx-runtime.js.map +1 -0
  16. package/dist/renderer-Bo9zkUZ_.js +52 -0
  17. package/dist/renderer-Bo9zkUZ_.js.map +1 -0
  18. package/dist/renderer-Din1y3YM.cjs +2 -0
  19. package/dist/renderer-Din1y3YM.cjs.map +1 -0
  20. package/dist/server-renderer-CqIpQ-od.cjs +2 -0
  21. package/dist/server-renderer-CqIpQ-od.cjs.map +1 -0
  22. package/dist/server-renderer-QHt45Ip2.js +255 -0
  23. package/dist/server-renderer-QHt45Ip2.js.map +1 -0
  24. package/dist/server-renderer.cjs +2 -0
  25. package/dist/server-renderer.cjs.map +1 -0
  26. package/dist/server-renderer.js +5 -1
  27. package/dist/server-renderer.js.map +1 -0
  28. package/package.json +77 -120
  29. package/templates/basic-app/build.js +22 -0
  30. package/templates/basic-app/bun.lock +196 -0
  31. package/templates/basic-app/dev.js +27 -0
  32. package/templates/basic-app/docs/rapport_pfe.aux +27 -27
  33. package/templates/basic-app/docs/rapport_pfe.out +10 -10
  34. package/templates/basic-app/docs/rapport_pfe.toc +14 -14
  35. package/templates/basic-app/esbuild.config.js +28 -0
  36. package/templates/basic-app/index.html +1 -1
  37. package/templates/{fullstack-app → basic-app}/package-lock.json +4185 -5094
  38. package/templates/basic-app/package.json +29 -28
  39. package/templates/basic-app/server.js +24 -0
  40. package/templates/basic-app/src/App.tsx +26 -0
  41. package/templates/basic-app/src/client.tsx +11 -0
  42. package/templates/basic-app/src/components/Counter.tsx +18 -0
  43. package/templates/basic-app/src/jsx-shim.ts +4 -0
  44. package/templates/basic-app/src/main.tsx +0 -1
  45. package/templates/basic-app/src/server.ts +52 -0
  46. package/templates/basic-app/tsconfig.server.json +11 -0
  47. package/templates/fullstack-app/build/main.css +874 -874
  48. package/templates/fullstack-app/build/main.css.map +7 -7
  49. package/templates/fullstack-app/build/main.js +967 -967
  50. package/templates/fullstack-app/build/main.js.map +7 -7
  51. package/templates/fullstack-app/public/styles.css +768 -768
  52. package/templates/go/example.go +99 -154
  53. package/templates/go-wasm-app/babel.config.js +2 -8
  54. package/templates/go-wasm-app/package.json +12 -21
  55. package/templates/go-wasm-app/public/wasm/wasm_exec.js +561 -561
  56. package/templates/go-wasm-app/public/wasm/wasm_exec_node.js +39 -39
  57. package/templates/go-wasm-app/server.js +510 -59
  58. package/templates/go-wasm-app/src/app.js +2 -22
  59. package/templates/go-wasm-app/src/wasm/example.go +75 -75
  60. package/templates/go-wasm-app/vite.config.js +5 -16
  61. package/templates/ssr-template/server.js +2 -2
  62. package/templates/ssr-template/vite.config.js +5 -16
  63. package/dist/Counter.d.ts +0 -0
  64. package/dist/batch/package.json +0 -16
  65. package/dist/client-router/package.json +0 -16
  66. package/dist/component/package.json +0 -16
  67. package/dist/context/package.json +0 -16
  68. package/dist/event-bus/package.json +0 -16
  69. package/dist/forms/package.json +0 -16
  70. package/dist/hooks/package.json +0 -16
  71. package/dist/hooks-0728361a.cjs +0 -1
  72. package/dist/hooks-b58f947c.js +0 -133
  73. package/dist/hooks.js +0 -1
  74. package/dist/hooks.mjs +0 -13
  75. package/dist/index.mjs +0 -137
  76. package/dist/jsx-runtime/package.json +0 -16
  77. package/dist/jsx-runtime.mjs +0 -64
  78. package/dist/lifecycle-events/package.json +0 -16
  79. package/dist/package.json +0 -71
  80. package/dist/render-component/package.json +0 -16
  81. package/dist/renderer/package.json +0 -16
  82. package/dist/renderer.js +0 -1
  83. package/dist/renderer.mjs +0 -27
  84. package/dist/router/package.json +0 -16
  85. package/dist/server/package.json +0 -17
  86. package/dist/server/src/batch.d.ts +0 -3
  87. package/dist/server/src/batch.js +0 -23
  88. package/dist/server/src/batch.js.map +0 -1
  89. package/dist/server/src/client-router.d.ts +0 -60
  90. package/dist/server/src/client-router.js +0 -210
  91. package/dist/server/src/client-router.js.map +0 -1
  92. package/dist/server/src/component.d.ts +0 -14
  93. package/dist/server/src/component.js +0 -106
  94. package/dist/server/src/component.js.map +0 -1
  95. package/dist/server/src/context.d.ts +0 -13
  96. package/dist/server/src/context.js +0 -21
  97. package/dist/server/src/context.js.map +0 -1
  98. package/dist/server/src/event-bus.d.ts +0 -23
  99. package/dist/server/src/event-bus.js +0 -75
  100. package/dist/server/src/event-bus.js.map +0 -1
  101. package/dist/server/src/forms.d.ts +0 -40
  102. package/dist/server/src/forms.js +0 -148
  103. package/dist/server/src/forms.js.map +0 -1
  104. package/dist/server/src/hooks.d.ts +0 -12
  105. package/dist/server/src/hooks.js +0 -170
  106. package/dist/server/src/hooks.js.map +0 -1
  107. package/dist/server/src/index.client.d.ts +0 -12
  108. package/dist/server/src/index.client.js +0 -14
  109. package/dist/server/src/index.client.js.map +0 -1
  110. package/dist/server/src/index.d.ts +0 -88
  111. package/dist/server/src/index.js +0 -79
  112. package/dist/server/src/index.js.map +0 -1
  113. package/dist/server/src/jsx-runtime/jsx-dev-runtime.d.ts +0 -1
  114. package/dist/server/src/jsx-runtime/jsx-dev-runtime.js +0 -2
  115. package/dist/server/src/jsx-runtime/jsx-dev-runtime.js.map +0 -1
  116. package/dist/server/src/jsx-runtime/jsx-runtime.d.ts +0 -4
  117. package/dist/server/src/jsx-runtime/jsx-runtime.js +0 -41
  118. package/dist/server/src/jsx-runtime/jsx-runtime.js.map +0 -1
  119. package/dist/server/src/jsx-runtime.d.ts +0 -20
  120. package/dist/server/src/jsx-runtime.js +0 -105
  121. package/dist/server/src/jsx-runtime.js.map +0 -1
  122. package/dist/server/src/lifecycle-events.d.ts +0 -108
  123. package/dist/server/src/lifecycle-events.js +0 -177
  124. package/dist/server/src/lifecycle-events.js.map +0 -1
  125. package/dist/server/src/renderComponent.d.ts +0 -13
  126. package/dist/server/src/renderComponent.js +0 -30
  127. package/dist/server/src/renderComponent.js.map +0 -1
  128. package/dist/server/src/renderer.d.ts +0 -2
  129. package/dist/server/src/renderer.js +0 -31
  130. package/dist/server/src/renderer.js.map +0 -1
  131. package/dist/server/src/router.d.ts +0 -55
  132. package/dist/server/src/router.js +0 -166
  133. package/dist/server/src/router.js.map +0 -1
  134. package/dist/server/src/server/api-router.d.ts +0 -15
  135. package/dist/server/src/server/api-router.js +0 -111
  136. package/dist/server/src/server/api-router.js.map +0 -1
  137. package/dist/server/src/server/auth.d.ts +0 -32
  138. package/dist/server/src/server/auth.js +0 -80
  139. package/dist/server/src/server/auth.js.map +0 -1
  140. package/dist/server/src/server/database.d.ts +0 -24
  141. package/dist/server/src/server/database.js +0 -135
  142. package/dist/server/src/server/database.js.map +0 -1
  143. package/dist/server/src/server/index.d.ts +0 -116
  144. package/dist/server/src/server/index.js +0 -508
  145. package/dist/server/src/server/index.js.map +0 -1
  146. package/dist/server/src/server/middleware.d.ts +0 -11
  147. package/dist/server/src/server/middleware.js +0 -46
  148. package/dist/server/src/server/middleware.js.map +0 -1
  149. package/dist/server/src/server/server.d.ts +0 -9
  150. package/dist/server/src/server/server.js +0 -87
  151. package/dist/server/src/server/server.js.map +0 -1
  152. package/dist/server/src/server/templates.d.ts +0 -30
  153. package/dist/server/src/server/templates.js +0 -208
  154. package/dist/server/src/server/templates.js.map +0 -1
  155. package/dist/server/src/server/types.d.ts +0 -38
  156. package/dist/server/src/server/types.js +0 -4
  157. package/dist/server/src/server/types.js.map +0 -1
  158. package/dist/server/src/server/utils.d.ts +0 -70
  159. package/dist/server/src/server/utils.js +0 -156
  160. package/dist/server/src/server/utils.js.map +0 -1
  161. package/dist/server/src/server/wasm.d.ts +0 -9
  162. package/dist/server/src/server/wasm.js +0 -117
  163. package/dist/server/src/server/wasm.js.map +0 -1
  164. package/dist/server/src/server-renderer.d.ts +0 -5
  165. package/dist/server/src/server-renderer.js +0 -106
  166. package/dist/server/src/server-renderer.js.map +0 -1
  167. package/dist/server/src/server-types.d.ts +0 -42
  168. package/dist/server/src/server-types.js +0 -6
  169. package/dist/server/src/server-types.js.map +0 -1
  170. package/dist/server/src/store.d.ts +0 -41
  171. package/dist/server/src/store.js +0 -99
  172. package/dist/server/src/store.js.map +0 -1
  173. package/dist/server/src/types.d.ts +0 -19
  174. package/dist/server/src/types.js +0 -2
  175. package/dist/server/src/types.js.map +0 -1
  176. package/dist/server/src/utils.d.ts +0 -46
  177. package/dist/server/src/utils.js +0 -144
  178. package/dist/server/src/utils.js.map +0 -1
  179. package/dist/server/src/vdom.d.ts +0 -8
  180. package/dist/server/src/vdom.js +0 -22
  181. package/dist/server/src/vdom.js.map +0 -1
  182. package/dist/server/src/wasm.d.ts +0 -36
  183. package/dist/server/src/wasm.js +0 -159
  184. package/dist/server/src/wasm.js.map +0 -1
  185. package/dist/server/tsconfig.server.tsbuildinfo +0 -1
  186. package/dist/server-renderer/package.json +0 -16
  187. package/dist/server-renderer.mjs +0 -64
  188. package/dist/store/package.json +0 -16
  189. package/dist/types/package.json +0 -16
  190. package/dist/utils/package.json +0 -16
  191. package/dist/vdom/package.json +0 -16
  192. package/dist/wasm/package.json +0 -16
  193. package/dist/wasm.js +0 -1
  194. package/dist/wasm.mjs +0 -103
  195. package/templates/basic-app/docs/rapport_pfe.log +0 -399
  196. package/templates/complete-app/client.js +0 -58
  197. package/templates/complete-app/package-lock.json +0 -2536
  198. package/templates/complete-app/package.json +0 -17
  199. package/templates/complete-app/pages/about.js +0 -119
  200. package/templates/complete-app/pages/index.js +0 -157
  201. package/templates/complete-app/pages/wasm-demo.js +0 -290
  202. package/templates/complete-app/public/client.js +0 -80
  203. package/templates/complete-app/public/index.html +0 -47
  204. package/templates/complete-app/public/styles.css +0 -579
  205. package/templates/complete-app/readme.md +0 -188
  206. package/templates/complete-app/server.js +0 -417
  207. package/templates/complete-app/server.ts +0 -275
  208. package/templates/complete-app/src/App.tsx +0 -59
  209. package/templates/complete-app/src/client.ts +0 -61
  210. package/templates/complete-app/src/client.tsx +0 -18
  211. package/templates/complete-app/src/pages/index.tsx +0 -51
  212. package/templates/complete-app/src/server.ts +0 -218
  213. package/templates/complete-app/tsconfig.json +0 -22
  214. package/templates/complete-app/tsconfig.server.json +0 -19
  215. package/templates/complete-app/vite.config.js +0 -57
  216. package/templates/complete-app/vite.config.ts +0 -30
  217. package/templates/go-wasm-app/build.config.js +0 -62
  218. package/templates/go-wasm-app/build.js +0 -218
  219. package/templates/go-wasm-app/package-lock.json +0 -3732
@@ -1,188 +0,0 @@
1
- # Frontend Hamroun SSR Template
2
-
3
- This is a comprehensive server-side rendering (SSR) example using Frontend Hamroun.
4
-
5
- ## Getting Started
6
-
7
- 1. Install dependencies:
8
- ```
9
- npm install
10
- ```
11
-
12
- 2. Start the server:
13
- ```
14
- npm start
15
- ```
16
-
17
- 3. Open your browser at http://localhost:3000
18
-
19
- ## Core Features
20
-
21
- This template demonstrates:
22
-
23
- ### Server-Side Rendering
24
- - Pre-rendering of components on the server
25
- - Hydration of server-rendered content on the client
26
- - Data fetching during server rendering
27
- - AI-powered meta tag generation
28
-
29
- ### Automatic File-Based Routing
30
- - Pages are automatically rendered based on their file path in the `pages` directory
31
- - For example:
32
- - `/pages/index.js` → `/` route
33
- - `/pages/about.js` → `/about` route
34
- - `/pages/blog/index.js` → `/blog` route
35
- - `/pages/users/[id].js` → `/users/:id` dynamic route
36
-
37
- ### API Integration
38
- - RESTful API endpoints
39
- - Dynamic API routing
40
- - API middleware for validation and security
41
- - File-based API structure
42
-
43
- ### Database Integration
44
- - MongoDB, MySQL, and PostgreSQL support
45
- - ORM-like query interface
46
- - Connection pooling
47
- - Transaction support
48
-
49
- ### Authentication & Authorization
50
- - JWT-based authentication
51
- - Role-based access control
52
- - Password hashing and validation
53
- - Token refresh mechanism
54
-
55
- ### Performance Optimization
56
- - Caching strategies
57
- - Response compression
58
- - Static asset optimization
59
- - Efficient metadata handling
60
-
61
- ## Implementation Examples
62
-
63
- ### Creating Components
64
-
65
- Use the `jsx` or `createElement` function from 'frontend-hamroun':
66
-
67
- ```jsx
68
- import { jsx } from 'frontend-hamroun';
69
-
70
- export default function MyComponent(props) {
71
- return jsx('div', { className: "container" }, [
72
- jsx('h1', {}, "Hello World"),
73
- jsx('p', {}, `Props value: ${props.value}`)
74
- ]);
75
- }
76
- ```
77
-
78
- ### Creating API Routes
79
-
80
- Create files in the `api` directory following this pattern:
81
-
82
- ```typescript
83
- // api/users/index.ts
84
- import { Request, Response } from 'express';
85
-
86
- export const get = (req: Request, res: Response) => {
87
- res.json({ users: [...] });
88
- };
89
-
90
- export const post = (req: Request, res: Response) => {
91
- // Create user
92
- res.status(201).json({ success: true });
93
- };
94
- ```
95
-
96
- ### Database Usage
97
-
98
- ```typescript
99
- import { Server } from 'frontend-hamroun/server';
100
-
101
- const server = new Server({
102
- db: {
103
- url: process.env.DATABASE_URL,
104
- type: 'mongodb' // or 'mysql', 'postgres'
105
- }
106
- });
107
-
108
- // Get typed database instance
109
- const db = server.getDatabase();
110
- const users = await db.query('SELECT * FROM users'); // For SQL
111
- const docs = await db.getMongoDb().collection('users').find().toArray(); // For MongoDB
112
- ```
113
-
114
- ### Authentication
115
-
116
- ```typescript
117
- import { AuthService } from 'frontend-hamroun/server';
118
-
119
- const auth = new AuthService({
120
- secret: process.env.JWT_SECRET,
121
- expiresIn: '24h'
122
- });
123
-
124
- // Protect routes
125
- app.get('/api/protected', auth.requireAuth(), (req, res) => {
126
- res.json({ message: "Authenticated!" });
127
- });
128
-
129
- // Create user & login
130
- const hashedPassword = await auth.hashPassword(password);
131
- const token = auth.generateToken(user);
132
- ```
133
-
134
- ### Advanced Middleware
135
-
136
- ```typescript
137
- import { rateLimit, requestLogger, errorHandler } from 'frontend-hamroun/server';
138
-
139
- app.use(requestLogger);
140
- app.use('/api', rateLimit({ windowMs: 15 * 60 * 1000, max: 100 }));
141
- app.use(errorHandler);
142
- ```
143
-
144
- ## File-Based Routing Examples
145
-
146
- ### Static Routes
147
- Create files in the `pages` directory:
148
-
149
- ```jsx
150
- // pages/index.js - Maps to "/"
151
- export default function HomePage() {
152
- return <h1>Home Page</h1>;
153
- }
154
-
155
- // pages/about.js - Maps to "/about"
156
- export default function AboutPage() {
157
- return <h1>About Us</h1>;
158
- }
159
-
160
- // pages/contact/index.js - Maps to "/contact"
161
- export default function ContactPage() {
162
- return <h1>Contact Us</h1>;
163
- }
164
- ```
165
-
166
- ### Dynamic Routes
167
- Use brackets in filenames to define dynamic parameters:
168
-
169
- ```jsx
170
- // pages/users/[id].js - Maps to "/users/:id"
171
- export default function UserPage({ params }) {
172
- return <h1>User Profile: {params.id}</h1>;
173
- }
174
-
175
- // pages/blog/[category]/[slug].js - Maps to "/blog/:category/:slug"
176
- export default function BlogPost({ params }) {
177
- return (
178
- <div>
179
- <h1>Blog Post: {params.slug}</h1>
180
- <p>Category: {params.category}</p>
181
- </div>
182
- );
183
- }
184
- ```
185
-
186
- ## Next Steps
187
-
188
- Explore the full API documentation for more advanced features and customization options.
@@ -1,417 +0,0 @@
1
- import express from 'express';
2
- import path from 'path';
3
- import { fileURLToPath } from 'url';
4
- import fs from 'fs';
5
- import {
6
- renderToString,
7
- jsx,
8
- Server,
9
- createServer,
10
- rateLimit,
11
- requestLogger,
12
- errorHandler,
13
- notFoundHandler,
14
- loadGoWasmFromFile
15
- } from 'frontend-hamroun';
16
- import dotenv from 'dotenv';
17
- import compression from 'compression';
18
- import cors from 'cors';
19
-
20
- // Load environment variables
21
- dotenv.config();
22
-
23
- // Get __dirname equivalent in ESM
24
- const __filename = fileURLToPath(import.meta.url);
25
- const __dirname = path.dirname(__filename);
26
-
27
- // Create Express app
28
- const app = express();
29
- const PORT = process.env.PORT || 3000;
30
-
31
- // Middleware
32
- app.use(compression()); // Compress responses
33
- app.use(express.json()); // Parse JSON requests
34
- app.use(express.urlencoded({ extended: true })); // Parse URL-encoded requests
35
- app.use(cors()); // Enable CORS
36
- app.use(requestLogger); // Log all requests
37
-
38
- // Add rate limiting to prevent abuse
39
- app.use(rateLimit({
40
- windowMs: 15 * 60 * 1000, // 15 minutes
41
- max: 100 // limit each IP to 100 requests per windowMs
42
- }));
43
-
44
- // Serve static files from the public directory
45
- app.use(express.static(path.join(__dirname, 'public')));
46
-
47
- // Add correct MIME type for client.js module
48
- app.get('/client.js', (req, res) => {
49
- res.type('application/javascript').sendFile(path.join(__dirname, 'public', 'client.js'));
50
- });
51
-
52
- // Serve WebAssembly files with correct MIME type
53
- app.get('*.wasm', (req, res, next) => {
54
- res.type('application/wasm');
55
- next();
56
- });
57
-
58
- // Add API routes example with authentication
59
- app.get('/api/hello', (req, res) => {
60
- res.json({
61
- message: 'Hello from the API!',
62
- serverTime: new Date().toISOString()
63
- });
64
- });
65
-
66
- // Load WebAssembly modules if available
67
- async function loadWasmModules() {
68
- const wasmDir = path.join(__dirname, 'wasm');
69
-
70
- if (fs.existsSync(wasmDir)) {
71
- try {
72
- const wasmFiles = fs.readdirSync(wasmDir).filter(file => file.endsWith('.wasm'));
73
-
74
- for (const wasmFile of wasmFiles) {
75
- const wasmPath = path.join(wasmDir, wasmFile);
76
- const wasmModule = await loadGoWasmFromFile(wasmPath, { debug: true });
77
-
78
- console.log(`Loaded WASM module: ${wasmFile}`);
79
- console.log(`Available functions:`, Object.keys(wasmModule.functions));
80
-
81
- // Store modules globally for API routes to use
82
- global.wasmModules = global.wasmModules || {};
83
- global.wasmModules[wasmFile.replace('.wasm', '')] = wasmModule;
84
- }
85
- } catch (error) {
86
- console.error('Failed to load WASM modules:', error);
87
- }
88
- }
89
- }
90
-
91
- // Find the pages directory
92
- const getPagesDirectory = () => {
93
- return path.join(__dirname, 'pages');
94
- };
95
-
96
- // Helper to check if a file exists
97
- const fileExists = async (filePath) => {
98
- try {
99
- await fs.promises.access(filePath);
100
- return true;
101
- } catch {
102
- return false;
103
- }
104
- };
105
-
106
- // Generate meta tags for SEO
107
- async function generateMetaTags(content, title = '') {
108
- // Extract title from content or use provided title
109
- const pageTitle = title || 'Frontend Hamroun App';
110
-
111
- // Generate description from content
112
- const plainText = content.replace(/<[^>]*>/g, ' ').trim();
113
- const description = plainText.substring(0, 160) + (plainText.length > 160 ? '...' : '');
114
-
115
- // Extract keywords
116
- const keywords = plainText
117
- .toLowerCase()
118
- .replace(/[^\w\s]/g, '')
119
- .split(/\s+/)
120
- .filter(w => w.length > 3)
121
- .slice(0, 5)
122
- .join(', ');
123
-
124
- return {
125
- title: pageTitle,
126
- description,
127
- keywords
128
- };
129
- }
130
-
131
- // Map URL path to component path
132
- const getComponentPath = async (urlPath) => {
133
- const pagesDir = getPagesDirectory();
134
-
135
- // Handle root path
136
- if (urlPath === '/') {
137
- const indexPath = path.join(pagesDir, 'index.js');
138
- if (await fileExists(indexPath)) {
139
- return {
140
- componentPath: indexPath,
141
- params: {}
142
- };
143
- }
144
- }
145
-
146
- // Try direct match (e.g., /about -> /pages/about.js)
147
- // Only look for .js files since Node.js ESM doesn't support .jsx directly
148
- const possibleExtensions = ['.js']; // Remove .jsx, .ts, .tsx
149
-
150
- for (const ext of possibleExtensions) {
151
- const directPath = path.join(pagesDir, `${urlPath.slice(1)}${ext}`);
152
- if (await fileExists(directPath)) {
153
- return {
154
- componentPath: directPath,
155
- params: {}
156
- };
157
- }
158
- }
159
-
160
- // Try directory index (e.g., /about -> /pages/about/index.js)
161
- for (const ext of possibleExtensions) {
162
- const dirIndexPath = path.join(pagesDir, urlPath.slice(1), `index${ext}`);
163
- if (await fileExists(dirIndexPath)) {
164
- return {
165
- componentPath: dirIndexPath,
166
- params: {}
167
- };
168
- }
169
- }
170
-
171
- // Look for dynamic routes (with [param] in filename)
172
- const segments = urlPath.split('/').filter(Boolean);
173
- const dynamicRoutes = [];
174
-
175
- // Recursively scan pages directory for all files
176
- const scanDir = (dir, basePath = '') => {
177
- const items = fs.readdirSync(dir, { withFileTypes: true });
178
-
179
- for (const item of items) {
180
- const itemPath = path.join(dir, item.name);
181
- const routePath = path.join(basePath, item.name);
182
-
183
- if (item.isDirectory()) {
184
- scanDir(itemPath, routePath);
185
- } else if (item.name.endsWith('.js')) {
186
- if (item.name.includes('[')) {
187
- // This is a dynamic route file
188
- const urlPattern = routePath
189
- .replace(/\.js$/, '')
190
- .replace(/\[([^\]]+)\]/g, ':$1');
191
-
192
- dynamicRoutes.push({
193
- pattern: urlPattern,
194
- componentPath: itemPath
195
- });
196
- }
197
- }
198
- }
199
- };
200
-
201
- scanDir(pagesDir);
202
-
203
- // Check if any dynamic routes match
204
- for (const route of dynamicRoutes) {
205
- const routeSegments = route.pattern.split('/').filter(Boolean);
206
- if (routeSegments.length !== segments.length) continue;
207
-
208
- const params = {};
209
- let matches = true;
210
-
211
- for (let i = 0; i < segments.length; i++) {
212
- const routeSeg = routeSegments[i];
213
- const urlSeg = segments[i];
214
-
215
- if (routeSeg.startsWith(':')) {
216
- // This is a parameter
217
- const paramName = routeSeg.slice(1);
218
- params[paramName] = urlSeg;
219
- } else if (routeSeg !== urlSeg) {
220
- matches = false;
221
- break;
222
- }
223
- }
224
-
225
- if (matches) {
226
- return {
227
- componentPath: route.componentPath,
228
- params
229
- };
230
- }
231
- }
232
-
233
- // No match found
234
- return null;
235
- };
236
-
237
- // Handle all routes with SSR
238
- app.get('*', async (req, res, next) => {
239
- try {
240
- // Skip static assets and API routes
241
- if (req.path.match(/\.(js|css|ico|png|jpg|jpeg|gif|svg|wasm)$/) || req.path.startsWith('/api/')) {
242
- return next();
243
- }
244
-
245
- const routeResult = await getComponentPath(req.path);
246
-
247
- if (!routeResult) {
248
- return res.status(404).send(`
249
- <!DOCTYPE html>
250
- <html>
251
- <head>
252
- <title>404 - Page Not Found</title>
253
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
254
- <link href="/styles.css" rel="stylesheet" type="text/css">
255
- </head>
256
- <body>
257
- <div id="app">
258
- <div class="container">
259
- <h1>404 - Page Not Found</h1>
260
- <p>The page you requested could not be found.</p>
261
- <a href="/" class="button">Go to Home</a>
262
- </div>
263
- </div>
264
- <script id="__APP_DATA__" type="application/json">${JSON.stringify({
265
- path: req.path,
266
- error: 'not_found'
267
- })}</script>
268
- <script type="module" src="/client.js"></script>
269
- </body>
270
- </html>
271
- `);
272
- }
273
-
274
- // Fixed component loading to use file:// URL scheme for Windows
275
- const componentUrl = new URL(`file://${routeResult.componentPath}`).href;
276
-
277
- try {
278
- // Import the component - handle both module.default and direct module exports
279
- const moduleImport = await import(componentUrl);
280
- const PageComponent = moduleImport.default || moduleImport;
281
-
282
- if (!PageComponent || typeof PageComponent !== 'function') {
283
- throw new Error(`Invalid component in ${routeResult.componentPath}: component is not a function`);
284
- }
285
-
286
- // Create props with route data
287
- const initialProps = {
288
- params: routeResult.params,
289
- path: req.path,
290
- query: req.query,
291
- api: {
292
- serverTime: new Date().toISOString()
293
- }
294
- };
295
-
296
- // Use a simpler rendering approach for more reliability
297
- let html;
298
- try {
299
- // Create a simple HTML structure based on the component's output
300
- const result = PageComponent(initialProps);
301
-
302
- // Create a fallback HTML if the result is not valid
303
- if (!result || typeof result !== 'object' || !result.type) {
304
- html = `
305
- <div class="error-container">
306
- <h1>Frontend Hamroun App</h1>
307
- <p>This is a simple fallback page.</p>
308
- <p>Path: ${req.path}</p>
309
- <p>Server time: ${initialProps.api.serverTime}</p>
310
- </div>
311
- `;
312
- } else {
313
- // Use renderToString with error handling
314
- html = renderToString(result) || '<div>Rendering failed</div>';
315
- }
316
- } catch (err) {
317
- console.error("Error with renderToString:", err);
318
- html = `
319
- <div class="error-container">
320
- <h1>Rendering Error</h1>
321
- <p>There was an error rendering this page: ${err.message}</p>
322
- <p>Path: ${req.path}</p>
323
- </div>
324
- `;
325
- }
326
-
327
- // Generate meta tags
328
- const metaTags = await generateMetaTags(html,
329
- typeof PageComponent.getTitle === 'function' ? PageComponent.getTitle(initialProps) : 'Frontend Hamroun App');
330
-
331
- // Send complete HTML with hydration data
332
- res.send(`
333
- <!DOCTYPE html>
334
- <html lang="en">
335
- <head>
336
- <meta charset="UTF-8">
337
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
338
-
339
- <!-- Generated Meta Tags -->
340
- <title>${metaTags.title}</title>
341
- <meta name="description" content="${metaTags.description}">
342
- <meta name="keywords" content="${metaTags.keywords}">
343
-
344
- <!-- Open Graph Meta Tags -->
345
- <meta property="og:title" content="${metaTags.title}">
346
- <meta property="og:description" content="${metaTags.description}">
347
- <meta property="og:type" content="website">
348
- <meta property="og:url" content="${req.protocol}://${req.get('host')}${req.originalUrl}">
349
-
350
- <!-- Import styles -->
351
- <link href="/styles.css" rel="stylesheet" type="text/css">
352
- </head>
353
- <body>
354
- <div id="app">${html}</div>
355
-
356
- <!-- Add initial state for hydration -->
357
- <script id="__APP_DATA__" type="application/json">${JSON.stringify(initialProps)}</script>
358
- <script type="module" src="/client.js"></script>
359
- </body>
360
- </html>
361
- `);
362
- } catch (importError) {
363
- console.error(`Error importing component from ${componentUrl}:`, importError);
364
- throw new Error(`Failed to import component: ${importError.message}`);
365
- }
366
- } catch (error) {
367
- console.error('Rendering error:', error);
368
- res.status(500).send(`
369
- <!DOCTYPE html>
370
- <html>
371
- <head>
372
- <title>500 - Server Error</title>
373
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
374
- <link href="/styles.css" rel="stylesheet" type="text/css">
375
- </head>
376
- <body>
377
- <div id="app">
378
- <div class="container">
379
- <h1>500 - Server Error</h1>
380
- <p>Something went wrong on the server.</p>
381
- ${process.env.NODE_ENV === 'development' ? `<pre>${error.stack}</pre>` : ''}
382
- <a href="/" class="button">Go to Home</a>
383
- </div>
384
- </div>
385
- <script id="__APP_DATA__" type="application/json">${JSON.stringify({
386
- path: req.path,
387
- error: 'server_error'
388
- })}</script>
389
- <script type="module" src="/client.js"></script>
390
- </body>
391
- </html>
392
- `);
393
- }
394
- });
395
-
396
- // Add error handler middleware
397
- app.use(errorHandler);
398
-
399
- // Add 404 handler for API routes
400
- app.use(notFoundHandler);
401
-
402
- // Start the server
403
- const startServer = async () => {
404
- // Load WebAssembly modules if available
405
- await loadWasmModules();
406
-
407
- // Start the server
408
- app.listen(PORT, () => {
409
- console.log(`Server running at http://localhost:${PORT}`);
410
- console.log(`Mode: ${process.env.NODE_ENV || 'development'}`);
411
- });
412
- };
413
-
414
- startServer().catch(err => {
415
- console.error('Failed to start server:', err);
416
- process.exit(1);
417
- });