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.
- package/package.json +1 -1
- package/templates/basic-app/build.d.ts +2 -0
- package/templates/basic-app/build.d.ts.map +1 -0
- package/templates/basic-app/dev.d.ts +2 -0
- package/templates/basic-app/dev.d.ts.map +1 -0
- package/templates/basic-app/esbuild.config.d.ts +2 -0
- package/templates/basic-app/esbuild.config.d.ts.map +1 -0
- package/templates/basic-app/postcss.config.d.ts +8 -0
- package/templates/basic-app/postcss.config.d.ts.map +1 -0
- package/templates/basic-app/server.d.ts +2 -0
- package/templates/basic-app/server.d.ts.map +1 -0
- package/templates/basic-app/src/App.d.ts +2 -0
- package/templates/basic-app/src/App.d.ts.map +1 -0
- package/templates/basic-app/src/App.js +148 -0
- package/templates/basic-app/src/client.d.ts +2 -0
- package/templates/basic-app/src/client.d.ts.map +1 -0
- package/templates/basic-app/src/client.js +6 -0
- package/templates/basic-app/src/components/Counter.d.ts +4 -0
- package/templates/basic-app/src/components/Counter.d.ts.map +1 -0
- package/templates/basic-app/src/components/Counter.js +9 -0
- package/templates/basic-app/src/jsx-shim.d.ts +8 -0
- package/templates/basic-app/src/jsx-shim.d.ts.map +1 -0
- package/templates/basic-app/src/main.d.ts +2 -0
- package/templates/basic-app/src/main.d.ts.map +1 -0
- package/templates/basic-app/src/main.js +57 -0
- package/templates/basic-app/src/server.d.ts +2 -0
- package/templates/basic-app/src/server.d.ts.map +1 -0
- package/templates/basic-app/tailwind.config.d.ts +9 -0
- package/templates/basic-app/tailwind.config.d.ts.map +1 -0
- package/templates/basic-app/vite.config.d.ts +3 -0
- package/templates/basic-app/vite.config.d.ts.map +1 -0
- package/templates/basic-app/vite.config.js +7 -0
- package/templates/complete-app/api/hello.d.ts +1 -0
- package/templates/complete-app/api/hello.d.ts.map +1 -0
- package/templates/complete-app/client.d.ts +2 -0
- package/templates/complete-app/client.d.ts.map +1 -0
- package/templates/complete-app/lib/frontend-hamroun.d.ts +18 -0
- package/templates/complete-app/lib/frontend-hamroun.d.ts.map +1 -0
- package/templates/complete-app/pages/about.d.ts +7 -0
- package/templates/complete-app/pages/about.d.ts.map +1 -0
- package/templates/complete-app/pages/index.d.ts +7 -0
- package/templates/complete-app/pages/index.d.ts.map +1 -0
- package/templates/complete-app/pages/wasm-demo.d.ts +7 -0
- package/templates/complete-app/pages/wasm-demo.d.ts.map +1 -0
- package/templates/complete-app/public/client.d.ts +17 -0
- package/templates/complete-app/public/client.d.ts.map +1 -0
- package/templates/complete-app/server.d.ts +2 -0
- package/templates/complete-app/server.d.ts.map +1 -0
- package/templates/complete-app/server.js +236 -218
- package/templates/complete-app/src/App.d.ts +2 -0
- package/templates/complete-app/src/App.d.ts.map +1 -0
- package/templates/complete-app/src/App.js +27 -0
- package/templates/complete-app/src/client.d.ts +2 -0
- package/templates/complete-app/src/client.d.ts.map +1 -0
- package/templates/complete-app/src/client.js +52 -0
- package/templates/complete-app/src/pages/index.d.ts +2 -0
- package/templates/complete-app/src/pages/index.d.ts.map +1 -0
- package/templates/complete-app/src/pages/index.js +19 -0
- package/templates/complete-app/src/server.d.ts +2 -0
- package/templates/complete-app/src/server.d.ts.map +1 -0
- package/templates/complete-app/src/server.js +192 -0
- package/templates/complete-app/vite.config.d.ts +3 -0
- package/templates/complete-app/vite.config.d.ts.map +1 -0
- package/templates/complete-app/vite.config.js +29 -57
- package/templates/fullstack-app/api/hello.d.ts +4 -0
- package/templates/fullstack-app/api/hello.d.ts.map +1 -0
- package/templates/fullstack-app/api/hello.js +14 -11
- package/templates/fullstack-app/api/users/[id].d.ts +5 -0
- package/templates/fullstack-app/api/users/[id].d.ts.map +1 -0
- package/templates/fullstack-app/api/users/[id].js +52 -0
- package/templates/fullstack-app/api/users/index.d.ts +4 -0
- package/templates/fullstack-app/api/users/index.d.ts.map +1 -0
- package/templates/fullstack-app/api/users/index.js +25 -0
- package/templates/fullstack-app/build/main.d.ts +211 -0
- package/templates/fullstack-app/build/main.d.ts.map +1 -0
- package/templates/fullstack-app/build.d.ts +2 -0
- package/templates/fullstack-app/build.d.ts.map +1 -0
- package/templates/fullstack-app/build.js +190 -0
- package/templates/fullstack-app/postcss.config.d.ts +5 -0
- package/templates/fullstack-app/postcss.config.d.ts.map +1 -0
- package/templates/fullstack-app/process-tailwind.d.ts +2 -0
- package/templates/fullstack-app/process-tailwind.d.ts.map +1 -0
- package/templates/fullstack-app/public/route-handler.d.ts +1 -0
- package/templates/fullstack-app/public/route-handler.d.ts.map +1 -0
- package/templates/fullstack-app/server.d.ts +2 -0
- package/templates/fullstack-app/server.d.ts.map +1 -0
- package/templates/fullstack-app/server.js +428 -266
- package/templates/fullstack-app/src/client.d.ts +2 -0
- package/templates/fullstack-app/src/client.d.ts.map +1 -0
- package/templates/fullstack-app/src/components/ClientHome.d.ts +1 -0
- package/templates/fullstack-app/src/components/ClientHome.d.ts.map +1 -0
- package/templates/fullstack-app/src/components/ClientHome.js +1 -0
- package/templates/fullstack-app/src/components/ErrorBoundary.d.ts +7 -0
- package/templates/fullstack-app/src/components/ErrorBoundary.d.ts.map +1 -0
- package/templates/fullstack-app/src/components/ErrorBoundary.js +12 -0
- package/templates/fullstack-app/src/components/Layout.d.ts +7 -0
- package/templates/fullstack-app/src/components/Layout.d.ts.map +1 -0
- package/templates/fullstack-app/src/components/Layout.js +4 -0
- package/templates/fullstack-app/src/components/StateDemo.d.ts +2 -0
- package/templates/fullstack-app/src/components/StateDemo.d.ts.map +1 -0
- package/templates/fullstack-app/src/components/StateDemo.js +86 -0
- package/templates/fullstack-app/src/components/UserList.d.ts +11 -0
- package/templates/fullstack-app/src/components/UserList.d.ts.map +1 -0
- package/templates/fullstack-app/src/components/UserList.js +7 -0
- package/templates/fullstack-app/src/config.d.ts +29 -0
- package/templates/fullstack-app/src/config.d.ts.map +1 -0
- package/templates/fullstack-app/src/config.js +36 -0
- package/templates/fullstack-app/src/data/api.d.ts +35 -0
- package/templates/fullstack-app/src/data/api.d.ts.map +1 -0
- package/templates/fullstack-app/src/data/api.js +173 -0
- package/templates/fullstack-app/src/main.d.ts +7 -0
- package/templates/fullstack-app/src/main.d.ts.map +1 -0
- package/templates/fullstack-app/src/main.js +130 -0
- package/templates/fullstack-app/src/middleware.d.ts +10 -0
- package/templates/fullstack-app/src/middleware.d.ts.map +1 -0
- package/templates/fullstack-app/src/middleware.js +14 -0
- package/templates/fullstack-app/src/pages/404.d.ts +4 -0
- package/templates/fullstack-app/src/pages/404.d.ts.map +1 -0
- package/templates/fullstack-app/src/pages/404.js +4 -0
- package/templates/fullstack-app/src/pages/[id].d.ts +1 -0
- package/templates/fullstack-app/src/pages/[id].d.ts.map +1 -0
- package/templates/fullstack-app/src/pages/[id].js +1 -0
- package/templates/fullstack-app/src/pages/_app.d.ts +6 -0
- package/templates/fullstack-app/src/pages/_app.d.ts.map +1 -0
- package/templates/fullstack-app/src/pages/_app.js +6 -0
- package/templates/fullstack-app/src/pages/_document.d.ts +7 -0
- package/templates/fullstack-app/src/pages/_document.d.ts.map +1 -0
- package/templates/fullstack-app/src/pages/_document.js +4 -0
- package/templates/fullstack-app/src/pages/_error.d.ts +4 -0
- package/templates/fullstack-app/src/pages/_error.d.ts.map +1 -0
- package/templates/fullstack-app/src/pages/_error.js +8 -0
- package/templates/fullstack-app/src/pages/about/index.d.ts +5 -0
- package/templates/fullstack-app/src/pages/about/index.d.ts.map +1 -0
- package/templates/fullstack-app/src/pages/about/index.js +6 -0
- package/templates/fullstack-app/src/pages/about.d.ts +10 -0
- package/templates/fullstack-app/src/pages/about.d.ts.map +1 -0
- package/templates/fullstack-app/src/pages/about.js +21 -0
- package/templates/fullstack-app/src/pages/api/users/[id].d.ts +6 -0
- package/templates/fullstack-app/src/pages/api/users/[id].d.ts.map +1 -0
- package/templates/fullstack-app/src/pages/api/users/[id].js +51 -0
- package/templates/fullstack-app/src/pages/api/users/index.d.ts +4 -0
- package/templates/fullstack-app/src/pages/api/users/index.d.ts.map +1 -0
- package/templates/fullstack-app/src/pages/api/users/index.js +33 -0
- package/templates/fullstack-app/src/pages/index.d.ts +21 -0
- package/templates/fullstack-app/src/pages/index.d.ts.map +1 -0
- package/templates/fullstack-app/src/pages/index.js +66 -0
- package/templates/fullstack-app/src/pages/users/[id].d.ts +38 -0
- package/templates/fullstack-app/src/pages/users/[id].d.ts.map +1 -0
- package/templates/fullstack-app/src/pages/users/[id].js +79 -0
- package/templates/fullstack-app/src/pages/users.d.ts +14 -0
- package/templates/fullstack-app/src/pages/users.d.ts.map +1 -0
- package/templates/fullstack-app/src/pages/users.js +14 -0
- package/templates/fullstack-app/src/pages/wasm-demo.d.ts +1 -0
- package/templates/fullstack-app/src/pages/wasm-demo.d.ts.map +1 -0
- package/templates/fullstack-app/src/pages/wasm-demo.js +2 -0
- package/templates/fullstack-app/src/router.d.ts +22 -0
- package/templates/fullstack-app/src/router.d.ts.map +1 -0
- package/templates/fullstack-app/src/router.js +210 -0
- package/templates/fullstack-app/tailwind.config.d.ts +3 -0
- package/templates/fullstack-app/tailwind.config.d.ts.map +1 -0
- package/templates/fullstack-app/vite.config.d.ts +3 -0
- package/templates/fullstack-app/vite.config.d.ts.map +1 -0
- package/templates/ssr-template/dist/client/assets/main-D-VH3xOb.d.ts +2 -0
- package/templates/ssr-template/dist/client/assets/main-D-VH3xOb.d.ts.map +1 -0
- package/templates/ssr-template/dist/client.d.ts +85 -0
- package/templates/ssr-template/dist/client.d.ts.map +1 -0
- package/templates/ssr-template/dist/server.d.ts +2 -0
- package/templates/ssr-template/dist/server.d.ts.map +1 -0
- package/templates/ssr-template/esbuild.config.d.ts +2 -0
- package/templates/ssr-template/esbuild.config.d.ts.map +1 -0
- package/templates/ssr-template/jsx-shim.d.ts +2 -0
- package/templates/ssr-template/jsx-shim.d.ts.map +1 -0
- package/templates/ssr-template/src/App.d.ts +2 -0
- package/templates/ssr-template/src/App.d.ts.map +1 -0
- package/templates/ssr-template/src/App.js +625 -0
- package/templates/ssr-template/src/client.d.ts +2 -0
- package/templates/ssr-template/src/client.d.ts.map +1 -0
- package/templates/ssr-template/src/client.js +3 -0
- package/templates/ssr-template/src/server.d.ts +2 -0
- package/templates/ssr-template/src/server.d.ts.map +1 -0
- package/templates/ssr-template/src/server.js +29 -0
- package/templates/ssr-template/vite.config.d.ts +3 -0
- package/templates/ssr-template/vite.config.d.ts.map +1 -0
- package/templates/ssr-template/vite.config.js +30 -0
- package/templates/wasm/build-wasm.d.ts +2 -0
- package/templates/wasm/build-wasm.d.ts.map +1 -0
- package/templates/wasm/dist/assets/index-BNqTDBdE.d.ts +30 -0
- package/templates/wasm/dist/assets/index-BNqTDBdE.d.ts.map +1 -0
- package/templates/wasm/dist/wasm_exec.d.ts +1 -0
- package/templates/wasm/dist/wasm_exec.d.ts.map +1 -0
- package/templates/wasm/esbuild.config.d.ts +2 -0
- package/templates/wasm/esbuild.config.d.ts.map +1 -0
- package/templates/wasm/go/wasm_exec.d.ts +1 -0
- package/templates/wasm/go/wasm_exec.d.ts.map +1 -0
- package/templates/wasm/jsx-shim.d.ts +5 -0
- package/templates/wasm/jsx-shim.d.ts.map +1 -0
- package/templates/wasm/public/wasm_exec.d.ts +1 -0
- package/templates/wasm/public/wasm_exec.d.ts.map +1 -0
- package/templates/wasm/src/App.d.ts +2 -0
- package/templates/wasm/src/App.d.ts.map +1 -0
- package/templates/wasm/src/App.js +381 -0
- package/templates/wasm/src/client.d.ts +2 -0
- package/templates/wasm/src/client.d.ts.map +1 -0
- package/templates/wasm/src/client.js +210 -0
- package/templates/wasm/src/index.d.ts +2 -0
- package/templates/wasm/src/index.d.ts.map +1 -0
- package/templates/wasm/src/index.js +20 -0
- package/templates/wasm/src/server.d.ts +2 -0
- package/templates/wasm/src/server.d.ts.map +1 -0
- package/templates/wasm/src/server.js +131 -0
- package/templates/wasm/vite.config.d.ts +3 -0
- package/templates/wasm/vite.config.d.ts.map +1 -0
- package/templates/wasm/vite.config.js +36 -0
- package/templates/wasm/wasm-loader.d.ts +6 -0
- 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
|
6
|
-
import
|
7
|
-
import {
|
8
|
-
import
|
9
|
-
import
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
const
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
const
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
const
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
app.use(express.
|
34
|
-
app.use(
|
35
|
-
app.use(
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
}
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
{
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
}
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
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
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
}
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
}
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
};
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
}
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
}
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
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
|
+
});
|