frontend-hamroun 1.2.84 → 1.2.85

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 (215) hide show
  1. package/package.json +1 -1
  2. package/templates/basic-app/build.d.ts +2 -0
  3. package/templates/basic-app/build.d.ts.map +1 -0
  4. package/templates/basic-app/dev.d.ts +2 -0
  5. package/templates/basic-app/dev.d.ts.map +1 -0
  6. package/templates/basic-app/esbuild.config.d.ts +2 -0
  7. package/templates/basic-app/esbuild.config.d.ts.map +1 -0
  8. package/templates/basic-app/postcss.config.d.ts +8 -0
  9. package/templates/basic-app/postcss.config.d.ts.map +1 -0
  10. package/templates/basic-app/server.d.ts +2 -0
  11. package/templates/basic-app/server.d.ts.map +1 -0
  12. package/templates/basic-app/src/App.d.ts +2 -0
  13. package/templates/basic-app/src/App.d.ts.map +1 -0
  14. package/templates/basic-app/src/App.js +148 -0
  15. package/templates/basic-app/src/client.d.ts +2 -0
  16. package/templates/basic-app/src/client.d.ts.map +1 -0
  17. package/templates/basic-app/src/client.js +6 -0
  18. package/templates/basic-app/src/components/Counter.d.ts +4 -0
  19. package/templates/basic-app/src/components/Counter.d.ts.map +1 -0
  20. package/templates/basic-app/src/components/Counter.js +9 -0
  21. package/templates/basic-app/src/jsx-shim.d.ts +8 -0
  22. package/templates/basic-app/src/jsx-shim.d.ts.map +1 -0
  23. package/templates/basic-app/src/main.d.ts +2 -0
  24. package/templates/basic-app/src/main.d.ts.map +1 -0
  25. package/templates/basic-app/src/main.js +57 -0
  26. package/templates/basic-app/src/server.d.ts +2 -0
  27. package/templates/basic-app/src/server.d.ts.map +1 -0
  28. package/templates/basic-app/tailwind.config.d.ts +9 -0
  29. package/templates/basic-app/tailwind.config.d.ts.map +1 -0
  30. package/templates/basic-app/vite.config.d.ts +3 -0
  31. package/templates/basic-app/vite.config.d.ts.map +1 -0
  32. package/templates/basic-app/vite.config.js +7 -0
  33. package/templates/complete-app/api/hello.d.ts +1 -0
  34. package/templates/complete-app/api/hello.d.ts.map +1 -0
  35. package/templates/complete-app/client.d.ts +2 -0
  36. package/templates/complete-app/client.d.ts.map +1 -0
  37. package/templates/complete-app/lib/frontend-hamroun.d.ts +18 -0
  38. package/templates/complete-app/lib/frontend-hamroun.d.ts.map +1 -0
  39. package/templates/complete-app/pages/about.d.ts +7 -0
  40. package/templates/complete-app/pages/about.d.ts.map +1 -0
  41. package/templates/complete-app/pages/index.d.ts +7 -0
  42. package/templates/complete-app/pages/index.d.ts.map +1 -0
  43. package/templates/complete-app/pages/wasm-demo.d.ts +7 -0
  44. package/templates/complete-app/pages/wasm-demo.d.ts.map +1 -0
  45. package/templates/complete-app/public/client.d.ts +17 -0
  46. package/templates/complete-app/public/client.d.ts.map +1 -0
  47. package/templates/complete-app/server.d.ts +2 -0
  48. package/templates/complete-app/server.d.ts.map +1 -0
  49. package/templates/complete-app/server.js +236 -218
  50. package/templates/complete-app/src/App.d.ts +2 -0
  51. package/templates/complete-app/src/App.d.ts.map +1 -0
  52. package/templates/complete-app/src/App.js +27 -0
  53. package/templates/complete-app/src/client.d.ts +2 -0
  54. package/templates/complete-app/src/client.d.ts.map +1 -0
  55. package/templates/complete-app/src/client.js +52 -0
  56. package/templates/complete-app/src/pages/index.d.ts +2 -0
  57. package/templates/complete-app/src/pages/index.d.ts.map +1 -0
  58. package/templates/complete-app/src/pages/index.js +19 -0
  59. package/templates/complete-app/src/server.d.ts +2 -0
  60. package/templates/complete-app/src/server.d.ts.map +1 -0
  61. package/templates/complete-app/src/server.js +192 -0
  62. package/templates/complete-app/vite.config.d.ts +3 -0
  63. package/templates/complete-app/vite.config.d.ts.map +1 -0
  64. package/templates/complete-app/vite.config.js +29 -57
  65. package/templates/fullstack-app/api/hello.d.ts +4 -0
  66. package/templates/fullstack-app/api/hello.d.ts.map +1 -0
  67. package/templates/fullstack-app/api/hello.js +14 -11
  68. package/templates/fullstack-app/api/users/[id].d.ts +5 -0
  69. package/templates/fullstack-app/api/users/[id].d.ts.map +1 -0
  70. package/templates/fullstack-app/api/users/[id].js +52 -0
  71. package/templates/fullstack-app/api/users/index.d.ts +4 -0
  72. package/templates/fullstack-app/api/users/index.d.ts.map +1 -0
  73. package/templates/fullstack-app/api/users/index.js +25 -0
  74. package/templates/fullstack-app/build/main.d.ts +211 -0
  75. package/templates/fullstack-app/build/main.d.ts.map +1 -0
  76. package/templates/fullstack-app/build.d.ts +2 -0
  77. package/templates/fullstack-app/build.d.ts.map +1 -0
  78. package/templates/fullstack-app/build.js +190 -0
  79. package/templates/fullstack-app/postcss.config.d.ts +5 -0
  80. package/templates/fullstack-app/postcss.config.d.ts.map +1 -0
  81. package/templates/fullstack-app/process-tailwind.d.ts +2 -0
  82. package/templates/fullstack-app/process-tailwind.d.ts.map +1 -0
  83. package/templates/fullstack-app/public/route-handler.d.ts +1 -0
  84. package/templates/fullstack-app/public/route-handler.d.ts.map +1 -0
  85. package/templates/fullstack-app/server.d.ts +2 -0
  86. package/templates/fullstack-app/server.d.ts.map +1 -0
  87. package/templates/fullstack-app/server.js +428 -266
  88. package/templates/fullstack-app/src/client.d.ts +2 -0
  89. package/templates/fullstack-app/src/client.d.ts.map +1 -0
  90. package/templates/fullstack-app/src/components/ClientHome.d.ts +1 -0
  91. package/templates/fullstack-app/src/components/ClientHome.d.ts.map +1 -0
  92. package/templates/fullstack-app/src/components/ClientHome.js +1 -0
  93. package/templates/fullstack-app/src/components/ErrorBoundary.d.ts +7 -0
  94. package/templates/fullstack-app/src/components/ErrorBoundary.d.ts.map +1 -0
  95. package/templates/fullstack-app/src/components/ErrorBoundary.js +12 -0
  96. package/templates/fullstack-app/src/components/Layout.d.ts +7 -0
  97. package/templates/fullstack-app/src/components/Layout.d.ts.map +1 -0
  98. package/templates/fullstack-app/src/components/Layout.js +4 -0
  99. package/templates/fullstack-app/src/components/StateDemo.d.ts +2 -0
  100. package/templates/fullstack-app/src/components/StateDemo.d.ts.map +1 -0
  101. package/templates/fullstack-app/src/components/StateDemo.js +86 -0
  102. package/templates/fullstack-app/src/components/UserList.d.ts +11 -0
  103. package/templates/fullstack-app/src/components/UserList.d.ts.map +1 -0
  104. package/templates/fullstack-app/src/components/UserList.js +7 -0
  105. package/templates/fullstack-app/src/config.d.ts +29 -0
  106. package/templates/fullstack-app/src/config.d.ts.map +1 -0
  107. package/templates/fullstack-app/src/config.js +36 -0
  108. package/templates/fullstack-app/src/data/api.d.ts +35 -0
  109. package/templates/fullstack-app/src/data/api.d.ts.map +1 -0
  110. package/templates/fullstack-app/src/data/api.js +173 -0
  111. package/templates/fullstack-app/src/main.d.ts +7 -0
  112. package/templates/fullstack-app/src/main.d.ts.map +1 -0
  113. package/templates/fullstack-app/src/main.js +130 -0
  114. package/templates/fullstack-app/src/middleware.d.ts +10 -0
  115. package/templates/fullstack-app/src/middleware.d.ts.map +1 -0
  116. package/templates/fullstack-app/src/middleware.js +14 -0
  117. package/templates/fullstack-app/src/pages/404.d.ts +4 -0
  118. package/templates/fullstack-app/src/pages/404.d.ts.map +1 -0
  119. package/templates/fullstack-app/src/pages/404.js +4 -0
  120. package/templates/fullstack-app/src/pages/[id].d.ts +1 -0
  121. package/templates/fullstack-app/src/pages/[id].d.ts.map +1 -0
  122. package/templates/fullstack-app/src/pages/[id].js +1 -0
  123. package/templates/fullstack-app/src/pages/_app.d.ts +6 -0
  124. package/templates/fullstack-app/src/pages/_app.d.ts.map +1 -0
  125. package/templates/fullstack-app/src/pages/_app.js +6 -0
  126. package/templates/fullstack-app/src/pages/_document.d.ts +7 -0
  127. package/templates/fullstack-app/src/pages/_document.d.ts.map +1 -0
  128. package/templates/fullstack-app/src/pages/_document.js +4 -0
  129. package/templates/fullstack-app/src/pages/_error.d.ts +4 -0
  130. package/templates/fullstack-app/src/pages/_error.d.ts.map +1 -0
  131. package/templates/fullstack-app/src/pages/_error.js +8 -0
  132. package/templates/fullstack-app/src/pages/about/index.d.ts +5 -0
  133. package/templates/fullstack-app/src/pages/about/index.d.ts.map +1 -0
  134. package/templates/fullstack-app/src/pages/about/index.js +6 -0
  135. package/templates/fullstack-app/src/pages/about.d.ts +10 -0
  136. package/templates/fullstack-app/src/pages/about.d.ts.map +1 -0
  137. package/templates/fullstack-app/src/pages/about.js +21 -0
  138. package/templates/fullstack-app/src/pages/api/users/[id].d.ts +6 -0
  139. package/templates/fullstack-app/src/pages/api/users/[id].d.ts.map +1 -0
  140. package/templates/fullstack-app/src/pages/api/users/[id].js +51 -0
  141. package/templates/fullstack-app/src/pages/api/users/index.d.ts +4 -0
  142. package/templates/fullstack-app/src/pages/api/users/index.d.ts.map +1 -0
  143. package/templates/fullstack-app/src/pages/api/users/index.js +33 -0
  144. package/templates/fullstack-app/src/pages/index.d.ts +21 -0
  145. package/templates/fullstack-app/src/pages/index.d.ts.map +1 -0
  146. package/templates/fullstack-app/src/pages/index.js +66 -0
  147. package/templates/fullstack-app/src/pages/users/[id].d.ts +38 -0
  148. package/templates/fullstack-app/src/pages/users/[id].d.ts.map +1 -0
  149. package/templates/fullstack-app/src/pages/users/[id].js +79 -0
  150. package/templates/fullstack-app/src/pages/users.d.ts +14 -0
  151. package/templates/fullstack-app/src/pages/users.d.ts.map +1 -0
  152. package/templates/fullstack-app/src/pages/users.js +14 -0
  153. package/templates/fullstack-app/src/pages/wasm-demo.d.ts +1 -0
  154. package/templates/fullstack-app/src/pages/wasm-demo.d.ts.map +1 -0
  155. package/templates/fullstack-app/src/pages/wasm-demo.js +2 -0
  156. package/templates/fullstack-app/src/router.d.ts +22 -0
  157. package/templates/fullstack-app/src/router.d.ts.map +1 -0
  158. package/templates/fullstack-app/src/router.js +210 -0
  159. package/templates/fullstack-app/tailwind.config.d.ts +3 -0
  160. package/templates/fullstack-app/tailwind.config.d.ts.map +1 -0
  161. package/templates/fullstack-app/vite.config.d.ts +3 -0
  162. package/templates/fullstack-app/vite.config.d.ts.map +1 -0
  163. package/templates/ssr-template/dist/client/assets/main-D-VH3xOb.d.ts +2 -0
  164. package/templates/ssr-template/dist/client/assets/main-D-VH3xOb.d.ts.map +1 -0
  165. package/templates/ssr-template/dist/client.d.ts +85 -0
  166. package/templates/ssr-template/dist/client.d.ts.map +1 -0
  167. package/templates/ssr-template/dist/server.d.ts +2 -0
  168. package/templates/ssr-template/dist/server.d.ts.map +1 -0
  169. package/templates/ssr-template/esbuild.config.d.ts +2 -0
  170. package/templates/ssr-template/esbuild.config.d.ts.map +1 -0
  171. package/templates/ssr-template/jsx-shim.d.ts +2 -0
  172. package/templates/ssr-template/jsx-shim.d.ts.map +1 -0
  173. package/templates/ssr-template/src/App.d.ts +2 -0
  174. package/templates/ssr-template/src/App.d.ts.map +1 -0
  175. package/templates/ssr-template/src/App.js +625 -0
  176. package/templates/ssr-template/src/client.d.ts +2 -0
  177. package/templates/ssr-template/src/client.d.ts.map +1 -0
  178. package/templates/ssr-template/src/client.js +3 -0
  179. package/templates/ssr-template/src/server.d.ts +2 -0
  180. package/templates/ssr-template/src/server.d.ts.map +1 -0
  181. package/templates/ssr-template/src/server.js +29 -0
  182. package/templates/ssr-template/vite.config.d.ts +3 -0
  183. package/templates/ssr-template/vite.config.d.ts.map +1 -0
  184. package/templates/ssr-template/vite.config.js +30 -0
  185. package/templates/wasm/build-wasm.d.ts +2 -0
  186. package/templates/wasm/build-wasm.d.ts.map +1 -0
  187. package/templates/wasm/dist/assets/index-BNqTDBdE.d.ts +30 -0
  188. package/templates/wasm/dist/assets/index-BNqTDBdE.d.ts.map +1 -0
  189. package/templates/wasm/dist/wasm_exec.d.ts +1 -0
  190. package/templates/wasm/dist/wasm_exec.d.ts.map +1 -0
  191. package/templates/wasm/esbuild.config.d.ts +2 -0
  192. package/templates/wasm/esbuild.config.d.ts.map +1 -0
  193. package/templates/wasm/go/wasm_exec.d.ts +1 -0
  194. package/templates/wasm/go/wasm_exec.d.ts.map +1 -0
  195. package/templates/wasm/jsx-shim.d.ts +5 -0
  196. package/templates/wasm/jsx-shim.d.ts.map +1 -0
  197. package/templates/wasm/public/wasm_exec.d.ts +1 -0
  198. package/templates/wasm/public/wasm_exec.d.ts.map +1 -0
  199. package/templates/wasm/src/App.d.ts +2 -0
  200. package/templates/wasm/src/App.d.ts.map +1 -0
  201. package/templates/wasm/src/App.js +381 -0
  202. package/templates/wasm/src/client.d.ts +2 -0
  203. package/templates/wasm/src/client.d.ts.map +1 -0
  204. package/templates/wasm/src/client.js +210 -0
  205. package/templates/wasm/src/index.d.ts +2 -0
  206. package/templates/wasm/src/index.d.ts.map +1 -0
  207. package/templates/wasm/src/index.js +20 -0
  208. package/templates/wasm/src/server.d.ts +2 -0
  209. package/templates/wasm/src/server.d.ts.map +1 -0
  210. package/templates/wasm/src/server.js +131 -0
  211. package/templates/wasm/vite.config.d.ts +3 -0
  212. package/templates/wasm/vite.config.d.ts.map +1 -0
  213. package/templates/wasm/vite.config.js +36 -0
  214. package/templates/wasm/wasm-loader.d.ts +6 -0
  215. package/templates/wasm/wasm-loader.d.ts.map +1 -0
@@ -1,267 +1,429 @@
1
- import express from 'express';
2
- import path from 'path';
3
- import { fileURLToPath } from 'url';
4
- import fs from 'fs';
5
- import dotenv from 'dotenv';
6
- import { createServer } from 'http';
7
- import { Server as SocketServer } from 'socket.io';
8
- import compression from 'compression';
9
- import cors from 'cors';
10
-
11
- // Load environment variables
12
- dotenv.config();
13
-
14
- // Get __dirname equivalent in ESM
15
- const __filename = fileURLToPath(import.meta.url);
16
- const __dirname = path.dirname(__filename);
17
-
18
- // Create Express app
19
- const app = express();
20
- const PORT = process.env.PORT || 3000;
21
- const httpServer = createServer(app);
22
-
23
- // Create socket.io server
24
- const io = new SocketServer(httpServer, {
25
- cors: {
26
- origin: process.env.NODE_ENV === 'production' ? false : '*',
27
- methods: ['GET', 'POST']
28
- }
29
- });
30
-
31
- // Middleware setup
32
- app.use(express.json());
33
- app.use(express.urlencoded({ extended: true }));
34
- app.use(compression()); // Add compression for better performance
35
- app.use(cors()); // Enable CORS for API access
36
-
37
- // Add request logging in development mode
38
- if (process.env.NODE_ENV !== 'production') {
39
- app.use((req, res, next) => {
40
- console.log(`${new Date().toISOString()} - ${req.method} ${req.url}`);
41
- next();
42
- });
43
- }
44
-
45
- // For production, serve the built files
46
- if (process.env.NODE_ENV === 'production') {
47
- app.use(express.static(path.join(__dirname, 'dist')));
48
- } else {
49
- // In development, we'll let Vite handle the frontend
50
- console.log('Running in development mode - Vite handles the frontend');
51
- }
52
-
53
- // Global in-memory store for demo purposes
54
- // In a real app, you would use a database
55
- const store = {
56
- users: [
57
- { id: 1, name: 'User 1', email: 'user1@example.com' },
58
- { id: 2, name: 'User 2', email: 'user2@example.com' },
59
- { id: 3, name: 'User 3', email: 'user3@example.com' }
60
- ],
61
- posts: [
62
- { id: 1, title: 'Post 1', content: 'Content for post 1', authorId: 1 },
63
- { id: 2, title: 'Post 2', content: 'Content for post 2', authorId: 2 },
64
- { id: 3, title: 'Post 3', content: 'Content for post 3', authorId: 1 }
65
- ]
66
- };
67
-
68
- // Core API routes (available without file-based routing)
69
- app.get('/api/hello', (req, res) => {
70
- res.json({
71
- message: "Hello from the API!",
72
- time: new Date().toISOString(),
73
- features: [
74
- "Server-side rendering",
75
- "API routes",
76
- "Component-based UI",
77
- "React-like development experience",
78
- "WebSocket integration",
79
- "Database connectivity",
80
- "Authentication"
81
- ]
82
- });
83
- });
84
-
85
- // REST API endpoints for store data
86
- app.get('/api/users', (req, res) => {
87
- res.json(store.users);
88
- });
89
-
90
- app.get('/api/users/:id', (req, res) => {
91
- const user = store.users.find(u => u.id === parseInt(req.params.id));
92
- if (user) {
93
- res.json(user);
94
- } else {
95
- res.status(404).json({ error: 'User not found' });
96
- }
97
- });
98
-
99
- app.get('/api/posts', (req, res) => {
100
- const { authorId } = req.query;
101
-
102
- if (authorId) {
103
- const filteredPosts = store.posts.filter(p => p.authorId === parseInt(authorId));
104
- return res.json(filteredPosts);
105
- }
106
-
107
- res.json(store.posts);
108
- });
109
-
110
- // Improved dynamic API route loading with better error handling
111
- const apiDir = path.join(__dirname, 'api');
112
- if (fs.existsSync(apiDir)) {
113
- console.log('Loading API routes from directory...');
114
-
115
- // Function to map file paths to API routes
116
- const registerApiRoutes = async (dir, routePrefix = '') => {
117
- try {
118
- const entries = fs.readdirSync(dir, { withFileTypes: true });
119
-
120
- for (const entry of entries) {
121
- const fullPath = path.join(dir, entry.name);
122
-
123
- if (entry.isDirectory()) {
124
- // Process directories recursively
125
- await registerApiRoutes(fullPath, `${routePrefix}/${entry.name}`);
126
- } else if (entry.name.endsWith('.js') || entry.name.endsWith('.ts')) {
127
- // Process API file
128
- try {
129
- const fileName = entry.name.replace(/\.[^/.]+$/, ""); // Remove extension
130
- const routePath = fileName === 'index'
131
- ? routePrefix
132
- : fileName.startsWith('[') && fileName.endsWith(']')
133
- ? `${routePrefix}/:${fileName.slice(1, -1)}` // Convert [param] to :param
134
- : `${routePrefix}/${fileName}`;
135
-
136
- // Import the route module
137
- const module = await import(`file://${fullPath}`);
138
-
139
- // Register handlers for HTTP methods
140
- ['get', 'post', 'put', 'delete', 'patch'].forEach(method => {
141
- if (typeof module[method] === 'function') {
142
- console.log(` Registered ${method.toUpperCase()} ${routePath}`);
143
- app[method](`/api${routePath}`, module[method]);
144
- }
145
- });
146
-
147
- // Special case for 'delete' which might be named 'delete_' in some files
148
- if (typeof module['delete_'] === 'function') {
149
- console.log(` Registered DELETE ${routePath}`);
150
- app.delete(`/api${routePath}`, module['delete_']);
151
- }
152
- } catch (err) {
153
- console.error(`Error loading API route ${fullPath}:`, err);
1
+ import express from 'express';
2
+ import path from 'path';
3
+ import { fileURLToPath } from 'url';
4
+ import fs from 'fs/promises';
5
+ import { existsSync } from 'fs';
6
+ import dotenv from 'dotenv';
7
+ import { createServer } from 'http';
8
+ import { Server as SocketServer } from 'socket.io';
9
+ import compression from 'compression';
10
+ import cors from 'cors';
11
+ import * as esbuild from 'esbuild';
12
+ // Setup environment
13
+ dotenv.config();
14
+ const __filename = fileURLToPath(import.meta.url);
15
+ const __dirname = path.dirname(__filename);
16
+ // Create Express app
17
+ const app = express();
18
+ const PORT = process.env.PORT ? parseInt(process.env.PORT) : 3000;
19
+ const httpServer = createServer(app);
20
+ // Set development mode
21
+ if (process.env.NODE_ENV === undefined) {
22
+ process.env.NODE_ENV = 'development';
23
+ }
24
+ const isDev = process.env.NODE_ENV !== 'production';
25
+ // Create socket.io server
26
+ const io = new SocketServer(httpServer, {
27
+ cors: {
28
+ origin: isDev ? '*' : false,
29
+ methods: ['GET', 'POST']
30
+ }
31
+ });
32
+ // Middleware setup
33
+ app.use(express.json());
34
+ app.use(express.urlencoded({ extended: true }));
35
+ app.use(compression());
36
+ app.use(cors());
37
+ if (isDev) {
38
+ app.use((req, res, next) => {
39
+ console.log(`${new Date().toISOString()} - ${req.method} ${req.url}`);
40
+ next();
41
+ });
42
+ }
43
+ // Sample data store
44
+ const store = {
45
+ users: [
46
+ { id: 1, name: 'User 1', email: 'user1@example.com' },
47
+ { id: 2, name: 'User 2', email: 'user2@example.com' },
48
+ { id: 3, name: 'User 3', email: 'user3@example.com' }
49
+ ],
50
+ posts: [
51
+ { id: 1, title: 'Post 1', content: 'Content for post 1', authorId: 1 },
52
+ { id: 2, title: 'Post 2', content: 'Content for post 2', authorId: 2 },
53
+ { id: 3, title: 'Post 3', content: 'Content for post 3', authorId: 1 }
54
+ ]
55
+ };
56
+ // API Routes
57
+ app.get('/api/hello', (req, res) => {
58
+ res.json({
59
+ message: 'Hello from the API!',
60
+ time: new Date().toISOString()
61
+ });
62
+ });
63
+ app.get('/api/users', (req, res) => {
64
+ res.json(store.users);
65
+ });
66
+ app.get('/api/users/:id', (req, res) => {
67
+ const user = store.users.find(u => u.id === parseInt(req.params.id));
68
+ if (user) {
69
+ res.json(user);
70
+ }
71
+ else {
72
+ res.status(404).json({ error: 'User not found' });
73
+ }
74
+ });
75
+ // Setup esbuild
76
+ let esbuildContext;
77
+ async function setupEsbuild() {
78
+ const buildDir = path.join(__dirname, 'build');
79
+ if (!existsSync(buildDir)) {
80
+ await fs.mkdir(buildDir, { recursive: true });
81
+ }
82
+ // Import PostCSS, Tailwind and Autoprefixer when in development mode
83
+ let postcssPlugin = null;
84
+ if (isDev) {
85
+ try {
86
+ const postcss = (await import('postcss')).default;
87
+ const tailwindcss = (await import('tailwindcss')).default;
88
+ const autoprefixer = (await import('autoprefixer')).default;
89
+ // Create a plugin to process CSS with Tailwind
90
+ postcssPlugin = {
91
+ name: 'postcss-tailwind',
92
+ setup(build) {
93
+ build.onLoad({ filter: /\.css$/ }, async (args) => {
94
+ const css = await fs.readFile(args.path, 'utf8');
95
+ try {
96
+ // Process CSS with PostCSS + Tailwind
97
+ const result = await postcss([
98
+ tailwindcss,
99
+ autoprefixer
100
+ ]).process(css, {
101
+ from: args.path,
102
+ to: path.join(buildDir, 'styles.css')
103
+ });
104
+ return {
105
+ contents: result.css,
106
+ loader: 'css'
107
+ };
108
+ }
109
+ catch (error) {
110
+ console.error('Error processing CSS with Tailwind:', error);
111
+ return { contents: css, loader: 'css' };
112
+ }
113
+ });
114
+ }
115
+ };
116
+ }
117
+ catch (error) {
118
+ console.warn('PostCSS plugins not available, CSS will not be processed with Tailwind:', error);
119
+ }
120
+ }
121
+ esbuildContext = await esbuild.context({
122
+ entryPoints: [
123
+ path.join(__dirname, 'src', 'main.tsx'),
124
+ ],
125
+ bundle: true,
126
+ format: 'esm',
127
+ outdir: buildDir,
128
+ sourcemap: isDev,
129
+ minify: !isDev,
130
+ jsx: 'transform',
131
+ jsxFactory: 'jsx',
132
+ jsxFragment: 'Fragment',
133
+ external: ['react', 'react/jsx-runtime', 'react-dom'],
134
+ define: {
135
+ 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development')
136
+ },
137
+ loader: {
138
+ '.tsx': 'tsx',
139
+ '.ts': 'ts',
140
+ '.jsx': 'jsx',
141
+ '.js': 'js',
142
+ '.css': 'css',
143
+ '.json': 'json',
144
+ '.png': 'file',
145
+ '.jpg': 'file',
146
+ '.svg': 'file'
147
+ },
148
+ plugins: [
149
+ {
150
+ name: 'jsx-runtime-import',
151
+ setup(build) {
152
+ build.onLoad({ filter: /\.(tsx|jsx)$/ }, async (args) => {
153
+ const source = await fs.readFile(args.path, 'utf8');
154
+ const content = `import { jsx, Fragment } from 'frontend-hamroun';\n${source}`;
155
+ return { contents: content, loader: args.path.endsWith('tsx') ? 'tsx' : 'jsx' };
156
+ });
157
+ }
158
+ },
159
+ ...(postcssPlugin ? [postcssPlugin] : [])
160
+ ]
161
+ });
162
+ if (isDev) {
163
+ await esbuildContext.rebuild();
164
+ console.log('esbuild: Initial build complete');
165
+ }
166
+ else {
167
+ await esbuildContext.rebuild();
168
+ await esbuildContext.dispose();
169
+ console.log('esbuild: Production build complete');
170
+ }
171
+ }
172
+ // Initialize esbuild
173
+ setupEsbuild().catch(err => {
174
+ console.error('Failed to setup esbuild:', err);
175
+ process.exit(1);
176
+ });
177
+ // Serve static files
178
+ app.use('/build', express.static(path.join(__dirname, 'build')));
179
+ app.use(express.static(path.join(__dirname, 'public')));
180
+ // Development mode file serving
181
+ if (isDev) {
182
+ app.get('/src/*', async (req, res, next) => {
183
+ try {
184
+ const filePath = path.join(__dirname, req.path);
185
+ // Check if file exists
186
+ if (!existsSync(filePath)) {
187
+ return next();
188
+ }
189
+ // Read the file
190
+ const source = await fs.readFile(filePath, 'utf8');
191
+ // Determine content type based on file extension
192
+ const ext = path.extname(filePath);
193
+ let contentType = 'application/javascript';
194
+ let loader = 'js';
195
+ switch (ext) {
196
+ case '.ts':
197
+ loader = 'ts';
198
+ break;
199
+ case '.tsx':
200
+ loader = 'tsx';
201
+ break;
202
+ case '.jsx':
203
+ loader = 'jsx';
204
+ break;
205
+ case '.css':
206
+ contentType = 'text/css';
207
+ loader = 'css';
208
+ break;
209
+ case '.json':
210
+ contentType = 'application/json';
211
+ loader = 'json';
212
+ break;
213
+ }
214
+ // Transform the file with esbuild
215
+ const result = await esbuild.transform(source, {
216
+ loader: loader,
217
+ sourcemap: 'inline',
218
+ jsxFactory: 'jsx',
219
+ jsxFragment: 'Fragment'
220
+ });
221
+ res.setHeader('Content-Type', contentType);
222
+ res.send(result.code);
223
+ }
224
+ catch (error) {
225
+ console.error(`Error serving ${req.path}:`, error);
226
+ next(error);
227
+ }
228
+ });
229
+ }
230
+ // Helper function to check if file exists
231
+ async function fileExists(filepath) {
232
+ try {
233
+ await fs.access(filepath);
234
+ return true;
235
+ }
236
+ catch {
237
+ return false;
238
+ }
239
+ }
240
+ // Import server utilities directly without WASM functionality
241
+ import { renderToString } from 'frontend-hamroun';
242
+ // Simple renderComponent implementation
243
+ async function renderComponent(Component, props = {}) {
244
+ try {
245
+ // Create HTML string from component
246
+ const html = renderToString(Component(props));
247
+ return {
248
+ html,
249
+ success: true
250
+ };
251
+ }
252
+ catch (error) {
253
+ console.error('Error rendering component:', error);
254
+ return {
255
+ html: `<div class="error">Error rendering component</div>`,
256
+ success: false,
257
+ error
258
+ };
259
+ }
260
+ }
261
+ // SSR handler for all routes except /api and static files
262
+ app.get('*', async (req, res, next) => {
263
+ // Skip API routes, static assets, and build/src files
264
+ if (req.path.startsWith('/api/') ||
265
+ req.path.startsWith('/build/') ||
266
+ req.path.startsWith('/src/') ||
267
+ req.path.match(/\.(js|css|ico|png|jpg|jpeg|gif|svg|woff|woff2|ttf|eot)$/)) {
268
+ return next();
269
+ }
270
+ console.log(`[SSR] Processing request for: ${req.path}`);
271
+ try {
272
+ // Normalize the path
273
+ const pagePath = req.path === '/' ? 'index' : req.path.slice(1);
274
+ // Create initial state
275
+ const initialState = {
276
+ route: req.path,
277
+ timestamp: new Date().toISOString(),
278
+ serverRendered: true,
279
+ data: {
280
+ users: store.users || [],
281
+ posts: store.posts || []
282
+ }
283
+ };
284
+ // Generate HTML content directly as a string instead of JSX
285
+ const rootContent = `
286
+ <div style="padding: 20px; max-width: 800px; margin: 0 auto;">
287
+ <h1>Loading Application...</h1>
288
+ <p>The application is initializing. If you continue to see this message, please ensure JavaScript is enabled in your browser.</p>
289
+ </div>
290
+ `;
291
+ // Create HTML template with properly structured content
292
+ const html = `<!DOCTYPE html>
293
+ <html lang="en">
294
+ <head>
295
+ <meta charset="UTF-8">
296
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
297
+ <title>Frontend Hamroun App</title>
298
+ <!-- Include the processed Tailwind CSS file -->
299
+ <link rel="stylesheet" href="/styles.css">
300
+ <style>
301
+ body {
302
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
303
+ line-height: 1.6;
304
+ color: #333;
305
+ margin: 0;
306
+ padding: 0;
154
307
  }
155
- }
156
- }
157
- } catch (err) {
158
- console.error(`Error reading directory ${dir}:`, err);
159
- }
160
- };
161
-
162
- // Start registering API routes
163
- registerApiRoutes(apiDir).catch(err => {
164
- console.error('Error loading API routes:', err);
165
- });
166
- } else {
167
- console.log('API directory not found, skipping API route loading');
168
- }
169
-
170
- // WebSocket setup
171
- io.on('connection', (socket) => {
172
- console.log('Client connected:', socket.id);
173
-
174
- // Send welcome message
175
- socket.emit('welcome', {
176
- message: 'Connected to WebSocket server',
177
- time: new Date().toISOString()
178
- });
179
-
180
- // Handle client messages
181
- socket.on('message', (data) => {
182
- console.log('Received message:', data);
183
- // Broadcast to all clients
184
- io.emit('broadcast', {
185
- from: socket.id,
186
- data,
187
- time: new Date().toISOString()
188
- });
189
- });
190
-
191
- // Handle disconnect
192
- socket.on('disconnect', () => {
193
- console.log('Client disconnected:', socket.id);
194
- });
195
- });
196
-
197
- // In production or if using SSR, handle all routes
198
- app.get('*', (req, res, next) => {
199
- // Skip API routes
200
- if (req.path.startsWith('/api/')) {
201
- return next();
202
- }
203
-
204
- // In production, serve the index.html
205
- if (process.env.NODE_ENV === 'production') {
206
- const indexPath = path.join(__dirname, 'dist', 'index.html');
207
- if (fs.existsSync(indexPath)) {
208
- try {
209
- // Read the index.html file
210
- let html = fs.readFileSync(indexPath, 'utf8');
211
-
212
- // Create initial state for client hydration
213
- const initialState = {
214
- route: req.path,
215
- timestamp: new Date().toISOString()
216
- };
217
-
218
- // Inject initial state for hydration
219
- html = html.replace(
220
- '</head>',
221
- `<script>window.__INITIAL_STATE__ = ${JSON.stringify(initialState)};</script></head>`
222
- );
223
-
224
- res.send(html);
225
- } catch (error) {
226
- console.error('Error serving HTML:', error);
227
- res.status(500).send('Server Error');
228
- }
229
- } else {
230
- res.status(404).send('Not found');
231
- }
232
- } else {
233
- // In development, use Vite's dev server
234
- // Instead of redirecting, proxy the request to maintain the URL path
235
- // This allows Vite to handle the route properly
236
- const viteDevServerUrl = 'http://localhost:5173';
237
-
238
- // Tell the client which route to handle via response headers
239
- res.setHeader('x-original-route', req.path);
240
-
241
- // Forward the request to the Vite dev server with the original path
242
- res.redirect(302, `${viteDevServerUrl}${req.path}`);
243
-
244
- // Note: If the above still causes 404s, you can try this alternative
245
- // res.redirect(302, `${viteDevServerUrl}/?_path=${encodeURIComponent(req.path)}`);
246
- }
247
- });
248
-
249
- // Error handling middleware
250
- app.use((err, req, res, next) => {
251
- console.error('Server error:', err);
252
- res.status(500).json({
253
- error: process.env.NODE_ENV === 'production'
254
- ? 'Internal server error'
255
- : err.message
256
- });
257
- });
258
-
259
- // Start server
260
- httpServer.listen(PORT, () => {
261
- console.log(`Server running on http://localhost:${PORT}`);
262
-
263
- if (process.env.NODE_ENV !== 'production') {
264
- console.log(`Frontend development server will run on http://localhost:5173`);
265
- console.log(`Run 'npm run dev' to start both servers`);
266
- }
267
- });
308
+ a {
309
+ color: #0066cc;
310
+ text-decoration: none;
311
+ }
312
+ a:hover {
313
+ text-decoration: underline;
314
+ }
315
+ pre {
316
+ white-space: pre-wrap;
317
+ word-break: break-word;
318
+ }
319
+ </style>
320
+ <script>
321
+ window.__INITIAL_STATE__ = ${JSON.stringify(initialState)};
322
+ </script>
323
+ </head>
324
+ <body>
325
+ <div id="root">${rootContent}</div>
326
+ <script src="/build/main.js" type="module"></script>
327
+ <script src="/socket.io/socket.io.js"></script>
328
+ </body>
329
+ </html>`;
330
+ // Send the rendered HTML
331
+ res.send(html);
332
+ }
333
+ catch (error) {
334
+ console.error('[SSR] Server error:', error);
335
+ next(error);
336
+ }
337
+ });
338
+ // Error handler
339
+ app.use((err, req, res, next) => {
340
+ console.error('Server error:', err);
341
+ res.status(500).send(`
342
+ <!DOCTYPE html>
343
+ <html>
344
+ <head><title>Server Error</title></head>
345
+ <body>
346
+ <h1>500 - Server Error</h1>
347
+ <p>${err.message}</p>
348
+ ${isDev ? `<pre>${err.stack}</pre>` : ''}
349
+ </body>
350
+ </html>
351
+ `);
352
+ });
353
+ // WebSocket setup
354
+ io.on('connection', (socket) => {
355
+ console.log('Client connected:', socket.id);
356
+ // Send welcome message
357
+ socket.emit('welcome', {
358
+ message: 'Connected to WebSocket server',
359
+ time: new Date().toISOString()
360
+ });
361
+ // Handle client messages
362
+ socket.on('message', (data) => {
363
+ console.log('Received message:', data);
364
+ // Broadcast to all clients
365
+ io.emit('broadcast', {
366
+ from: socket.id,
367
+ data,
368
+ time: new Date().toISOString()
369
+ });
370
+ });
371
+ // Handle disconnect
372
+ socket.on('disconnect', () => {
373
+ console.log('Client disconnected:', socket.id);
374
+ });
375
+ });
376
+ // Handle file changes for live reload in development
377
+ if (isDev) {
378
+ const { watch } = await import('chokidar');
379
+ const watcher = watch([
380
+ path.join(__dirname, 'src/**/*'),
381
+ path.join(__dirname, 'public/**/*')
382
+ ]);
383
+ watcher.on('change', async (changedPath) => {
384
+ console.log(`[Watcher] File changed: ${changedPath}`);
385
+ // Rebuild if source files changed
386
+ if (changedPath.startsWith(path.join(__dirname, 'src'))) {
387
+ try {
388
+ await esbuildContext.rebuild();
389
+ console.log('[Watcher] Rebuild complete');
390
+ // Notify clients to reload
391
+ io.emit('reload');
392
+ }
393
+ catch (error) {
394
+ console.error('[Watcher] Rebuild failed:', error);
395
+ }
396
+ }
397
+ // Notify clients of public file changes without rebuild
398
+ if (changedPath.startsWith(path.join(__dirname, 'public'))) {
399
+ io.emit('reload');
400
+ }
401
+ });
402
+ console.log('[Watcher] File watching enabled for development');
403
+ }
404
+ // API routes
405
+ app.get('/api/posts', (req, res) => {
406
+ const { authorId } = req.query;
407
+ if (authorId) {
408
+ const filteredPosts = store.posts.filter(p => p.authorId === parseInt(authorId));
409
+ return res.json(filteredPosts);
410
+ }
411
+ res.json(store.posts);
412
+ });
413
+ // Start the server
414
+ httpServer.listen(PORT, () => {
415
+ console.log(`Server running at http://localhost:${PORT}`);
416
+ console.log(`Server-side rendering enabled with direct esbuild compilation`);
417
+ if (isDev) {
418
+ console.log(`Development mode with live reload active`);
419
+ }
420
+ });
421
+ // Handle graceful shutdown
422
+ process.on('SIGINT', async () => {
423
+ console.log('Shutting down server...');
424
+ // Dispose esbuild context if active
425
+ if (esbuildContext) {
426
+ await esbuildContext.dispose();
427
+ }
428
+ process.exit(0);
429
+ });