baraqex 1.0.32 → 1.0.34
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/bin/baraqex.js +28 -27
- package/dist/server/index.d.ts +3 -6
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +8 -125
- package/dist/server/index.js.map +1 -1
- package/package.json +8 -2
- package/templates/fullstack-app/src/pages/index.js +0 -0
- package/templates/fullstack-template/src/pages/index.js +193 -48
- package/templates/ssr-template/package-lock.json +5080 -0
- package/templates/ssr-template/package.json +8 -14
- package/templates/ssr-template/src/App.tsx +7 -19
- package/templates/ssr-template/src/client.tsx +1 -21
- package/templates/ssr-template/src/server.ts +14 -183
- package/templates/ssr-template/tsconfig.json +6 -15
- package/templates/ssr-template/tsconfig.server.json +5 -18
- package/templates/ssr-template/vite.config.ts +0 -0
- package/templates/wasm/build-wasm.js +228 -0
- package/templates/wasm/esbuild.config.js +63 -0
- package/templates/wasm/go/main.go +256 -0
- package/templates/wasm/go/wasm_exec.js +0 -0
- package/templates/wasm/index.html +97 -0
- package/templates/wasm/jsx-shim.js +9 -0
- package/templates/wasm/package-lock.json +4848 -0
- package/templates/wasm/package.json +27 -0
- package/templates/wasm/public/example.wasm +0 -0
- package/templates/wasm/public/wasm_exec.js +572 -0
- package/templates/wasm/src/App.tsx +519 -0
- package/templates/wasm/src/client.tsx +220 -0
- package/templates/wasm/src/index.html +14 -0
- package/templates/wasm/src/index.tsx +21 -0
- package/templates/wasm/src/main.tsx +5 -0
- package/templates/wasm/src/server.ts +145 -0
- package/templates/wasm/src/wasm-loader.ts +119 -0
- package/templates/wasm/tsconfig.json +21 -0
- package/templates/wasm/tsconfig.node.json +13 -0
- package/templates/wasm/tsconfig.server.json +23 -0
- package/templates/wasm/vite.config.ts +73 -0
- package/templates/wasm/wasm-loader.js +103 -0
|
@@ -1,16 +1,13 @@
|
|
|
1
1
|
{
|
|
2
|
-
"name": "ssr-
|
|
2
|
+
"name": "ssr-version",
|
|
3
|
+
"private": true,
|
|
3
4
|
"version": "0.0.0",
|
|
4
5
|
"type": "module",
|
|
5
6
|
"scripts": {
|
|
6
|
-
"
|
|
7
|
+
"build:client": "esbuild src/client.tsx --bundle --outfile=dist/client.js --platform=browser --format=esm",
|
|
8
|
+
"build:server": "esbuild src/server.ts --bundle --outfile=dist/server.js --platform=node --format=esm --external:frontend-hamroun --packages=external",
|
|
7
9
|
"build": "node esbuild.config.js",
|
|
8
|
-
"
|
|
9
|
-
"build:client": "cross-env BUILD_TARGET=client vite build",
|
|
10
|
-
"build:server": "cross-env BUILD_TARGET=server vite build --ssr",
|
|
11
|
-
"start": "node dist/server.js",
|
|
12
|
-
"preview": "npm run build && npm run start",
|
|
13
|
-
"clean": "rm -rf node_modules package-lock.json dist && npm install"
|
|
10
|
+
"start": "node dist/server.js"
|
|
14
11
|
},
|
|
15
12
|
"dependencies": {
|
|
16
13
|
"express": "^4.18.2",
|
|
@@ -18,11 +15,8 @@
|
|
|
18
15
|
},
|
|
19
16
|
"devDependencies": {
|
|
20
17
|
"@types/express": "^4.17.17",
|
|
21
|
-
"@types/node": "^20.
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
"esbuild": "^0.19.0",
|
|
25
|
-
"typescript": "^5.0.0",
|
|
26
|
-
"vite": "^5.0.0"
|
|
18
|
+
"@types/node": "^20.5.0",
|
|
19
|
+
"esbuild": "^0.19.12",
|
|
20
|
+
"typescript": "^5.0.0"
|
|
27
21
|
}
|
|
28
22
|
}
|
|
@@ -1,18 +1,5 @@
|
|
|
1
1
|
import { useState, useEffect, useRef, useMemo } from 'frontend-hamroun';
|
|
2
2
|
|
|
3
|
-
// Type definitions
|
|
4
|
-
interface Todo {
|
|
5
|
-
id: number;
|
|
6
|
-
text: string;
|
|
7
|
-
completed: boolean;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
interface TodoItemProps {
|
|
11
|
-
todo: Todo;
|
|
12
|
-
onToggle: (id: number) => void;
|
|
13
|
-
onDelete: (id: number) => void;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
3
|
// Custom hooks for better code organization
|
|
17
4
|
function useTimer(initialTime = 0) {
|
|
18
5
|
const [time, setTime] = useState(initialTime);
|
|
@@ -165,7 +152,7 @@ function useTheme() {
|
|
|
165
152
|
}
|
|
166
153
|
|
|
167
154
|
// Todo Item Component
|
|
168
|
-
function TodoItem({ todo, onToggle, onDelete }:
|
|
155
|
+
function TodoItem({ todo, onToggle, onDelete, ...props }:any) {
|
|
169
156
|
return (
|
|
170
157
|
<div style={{
|
|
171
158
|
display: 'flex',
|
|
@@ -185,7 +172,7 @@ function TodoItem({ todo, onToggle, onDelete }: TodoItemProps) {
|
|
|
185
172
|
onChange={() => onToggle(todo.id)}
|
|
186
173
|
style={{ marginRight: '0.75rem' }}
|
|
187
174
|
/>
|
|
188
|
-
<span style={{ flex: 1
|
|
175
|
+
<span style={{ flex: 1 }}>{todo.text}</span>
|
|
189
176
|
<button
|
|
190
177
|
onClick={() => onDelete(todo.id)}
|
|
191
178
|
style={{
|
|
@@ -205,7 +192,7 @@ function TodoItem({ todo, onToggle, onDelete }: TodoItemProps) {
|
|
|
205
192
|
}
|
|
206
193
|
|
|
207
194
|
// Stats Component
|
|
208
|
-
function StatsCard({ title, value, color = '#3498db' }
|
|
195
|
+
function StatsCard({ title, value, color = '#3498db' }) {
|
|
209
196
|
return (
|
|
210
197
|
<div style={{
|
|
211
198
|
background: 'white',
|
|
@@ -249,7 +236,7 @@ export function App() {
|
|
|
249
236
|
const inputRef = useRef(null);
|
|
250
237
|
|
|
251
238
|
// Handle todo form submission
|
|
252
|
-
const handleTodoSubmit = (e:
|
|
239
|
+
const handleTodoSubmit = (e: { preventDefault: () => void; }) => {
|
|
253
240
|
e.preventDefault();
|
|
254
241
|
// Ensure newTodo is a string before passing to addTodo
|
|
255
242
|
const todoText = String(newTodo || '');
|
|
@@ -451,7 +438,7 @@ export function App() {
|
|
|
451
438
|
min="1"
|
|
452
439
|
max="10"
|
|
453
440
|
value={step}
|
|
454
|
-
onChange={(e
|
|
441
|
+
onChange={(e) => setStep(parseInt(e.target.value))}
|
|
455
442
|
style={{ width: '100%' }}
|
|
456
443
|
/>
|
|
457
444
|
</div>
|
|
@@ -492,7 +479,7 @@ export function App() {
|
|
|
492
479
|
background: colors.bg,
|
|
493
480
|
color: colors.text
|
|
494
481
|
}}
|
|
495
|
-
onKeyPress={(e
|
|
482
|
+
onKeyPress={(e) => {
|
|
496
483
|
if (e.key === 'Enter') {
|
|
497
484
|
setValue(parseInt(e.target.value) || 0);
|
|
498
485
|
e.target.value = '';
|
|
@@ -730,6 +717,7 @@ export function App() {
|
|
|
730
717
|
) : (
|
|
731
718
|
todos.map(todo => (
|
|
732
719
|
<TodoItem
|
|
720
|
+
key={todo.id}
|
|
733
721
|
todo={todo}
|
|
734
722
|
onToggle={toggleTodo}
|
|
735
723
|
onDelete={deleteTodo}
|
|
@@ -1,24 +1,4 @@
|
|
|
1
1
|
import { hydrate, jsx } from 'frontend-hamroun';
|
|
2
2
|
import { App } from './App.js';
|
|
3
3
|
|
|
4
|
-
document.
|
|
5
|
-
const root = document.getElementById('root');
|
|
6
|
-
if (root) {
|
|
7
|
-
try {
|
|
8
|
-
// Create the app element
|
|
9
|
-
const appElement = jsx(App, {});
|
|
10
|
-
|
|
11
|
-
// Hydrate the app with error boundary
|
|
12
|
-
hydrate(appElement, root);
|
|
13
|
-
|
|
14
|
-
console.log('✅ Client hydrated successfully!');
|
|
15
|
-
} catch (error) {
|
|
16
|
-
console.error('❌ Hydration failed:', error);
|
|
17
|
-
|
|
18
|
-
// Fallback rendering
|
|
19
|
-
root.innerHTML = '<div style="padding: 2rem; text-align: center;">⚠️ Client-side rendering failed, but page content is still available.</div>';
|
|
20
|
-
}
|
|
21
|
-
} else {
|
|
22
|
-
console.error('❌ Root element not found');
|
|
23
|
-
}
|
|
24
|
-
});
|
|
4
|
+
hydrate(jsx(App, {}), document.getElementById('root')!);
|
|
@@ -14,189 +14,20 @@ const port = 3000;
|
|
|
14
14
|
app.use(express.static(path.join(__dirname)));
|
|
15
15
|
|
|
16
16
|
app.get('/', async (req, res) => {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
box-sizing: border-box;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
body {
|
|
35
|
-
margin: 0;
|
|
36
|
-
padding: 0;
|
|
37
|
-
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
38
|
-
line-height: 1.6;
|
|
39
|
-
color: #333;
|
|
40
|
-
background: #f5f5f5;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/* Responsive design */
|
|
44
|
-
@media (max-width: 768px) {
|
|
45
|
-
.grid-responsive {
|
|
46
|
-
grid-template-columns: 1fr !important;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
.flex-responsive {
|
|
50
|
-
flex-direction: column;
|
|
51
|
-
gap: 0.5rem !important;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
.padding-responsive {
|
|
55
|
-
padding: 1rem !important;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/* Smooth transitions */
|
|
60
|
-
* {
|
|
61
|
-
transition: all 0.2s ease;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/* Button hover effects */
|
|
65
|
-
button:hover {
|
|
66
|
-
transform: translateY(-2px);
|
|
67
|
-
box-shadow: 0 4px 12px rgba(0,0,0,0.2);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
button:active {
|
|
71
|
-
transform: translateY(0);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/* Input focus styles */
|
|
75
|
-
input:focus {
|
|
76
|
-
outline: none;
|
|
77
|
-
box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.3);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/* Loading states */
|
|
81
|
-
.loading {
|
|
82
|
-
animation: pulse 2s infinite;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
@keyframes pulse {
|
|
86
|
-
0% { opacity: 1; }
|
|
87
|
-
50% { opacity: 0.5; }
|
|
88
|
-
100% { opacity: 1; }
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/* Grid animations */
|
|
92
|
-
.grid-item {
|
|
93
|
-
animation: slideInUp 0.6s ease-out;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
@keyframes slideInUp {
|
|
97
|
-
from {
|
|
98
|
-
opacity: 0;
|
|
99
|
-
transform: translateY(30px);
|
|
100
|
-
}
|
|
101
|
-
to {
|
|
102
|
-
opacity: 1;
|
|
103
|
-
transform: translateY(0);
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
/* Dark theme support */
|
|
108
|
-
.dark-theme {
|
|
109
|
-
background: #1a1a1a;
|
|
110
|
-
color: #ffffff;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
/* Custom scrollbar */
|
|
114
|
-
::-webkit-scrollbar {
|
|
115
|
-
width: 8px;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
::-webkit-scrollbar-track {
|
|
119
|
-
background: #f1f1f1;
|
|
120
|
-
border-radius: 4px;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
::-webkit-scrollbar-thumb {
|
|
124
|
-
background: #c1c1c1;
|
|
125
|
-
border-radius: 4px;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
::-webkit-scrollbar-thumb:hover {
|
|
129
|
-
background: #a8a8a8;
|
|
130
|
-
}
|
|
131
|
-
</style>
|
|
132
|
-
</head>
|
|
133
|
-
<body>
|
|
134
|
-
<div id="root">${html}</div>
|
|
135
|
-
<script type="module" src="/client.js"></script>
|
|
136
|
-
|
|
137
|
-
<!-- Performance monitoring -->
|
|
138
|
-
<script>
|
|
139
|
-
// Log performance metrics
|
|
140
|
-
window.addEventListener('load', () => {
|
|
141
|
-
const perfData = performance.getEntriesByType('navigation')[0];
|
|
142
|
-
console.log('🚀 Frontend Hamroun SSR Performance:');
|
|
143
|
-
console.log('⏱️ Page Load Time:', Math.round(perfData.loadEventEnd - perfData.fetchStart), 'ms');
|
|
144
|
-
console.log('🎨 DOM Content Loaded:', Math.round(perfData.domContentLoadedEventEnd - perfData.fetchStart), 'ms');
|
|
145
|
-
console.log('📡 Server Response:', Math.round(perfData.responseEnd - perfData.requestStart), 'ms');
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
// Enhanced error handling
|
|
149
|
-
window.addEventListener('error', (event) => {
|
|
150
|
-
console.error('🚨 Runtime Error:', event.error);
|
|
151
|
-
});
|
|
152
|
-
|
|
153
|
-
// Console welcome message
|
|
154
|
-
console.log('%c🚀 Frontend Hamroun SSR Template', 'color: #3498db; font-size: 24px; font-weight: bold;');
|
|
155
|
-
console.log('%cFeatures: SSR ✓ Hooks ✓ Modern Design ✓ TypeScript ✓', 'color: #27ae60; font-size: 14px;');
|
|
156
|
-
</script>
|
|
157
|
-
</body>
|
|
158
|
-
</html>
|
|
159
|
-
`);
|
|
160
|
-
} catch (error) {
|
|
161
|
-
console.error('Server-side rendering error:', error);
|
|
162
|
-
res.status(500).send(`
|
|
163
|
-
<!DOCTYPE html>
|
|
164
|
-
<html>
|
|
165
|
-
<head>
|
|
166
|
-
<title>Frontend Hamroun SSR - Error</title>
|
|
167
|
-
<style>
|
|
168
|
-
body {
|
|
169
|
-
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
170
|
-
display: flex;
|
|
171
|
-
justify-content: center;
|
|
172
|
-
align-items: center;
|
|
173
|
-
min-height: 100vh;
|
|
174
|
-
margin: 0;
|
|
175
|
-
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
176
|
-
color: white;
|
|
177
|
-
}
|
|
178
|
-
.error-container {
|
|
179
|
-
text-align: center;
|
|
180
|
-
padding: 2rem;
|
|
181
|
-
background: rgba(255,255,255,0.1);
|
|
182
|
-
border-radius: 16px;
|
|
183
|
-
backdrop-filter: blur(10px);
|
|
184
|
-
border: 1px solid rgba(255,255,255,0.2);
|
|
185
|
-
}
|
|
186
|
-
</style>
|
|
187
|
-
</head>
|
|
188
|
-
<body>
|
|
189
|
-
<div class="error-container">
|
|
190
|
-
<h1>🚨 Server Error</h1>
|
|
191
|
-
<p>The Frontend Hamroun SSR template encountered an error, but don't worry!</p>
|
|
192
|
-
<p>Error: ${error instanceof Error ? error.message : String(error)}</p>
|
|
193
|
-
<p><a href="/" style="color: white;">Try again</a></p>
|
|
194
|
-
</div>
|
|
195
|
-
<script type="module" src="/client.js"></script>
|
|
196
|
-
</body>
|
|
197
|
-
</html>
|
|
198
|
-
`);
|
|
199
|
-
}
|
|
17
|
+
const html = await renderToString(jsx(App, {}));
|
|
18
|
+
|
|
19
|
+
res.send(`
|
|
20
|
+
<!DOCTYPE html>
|
|
21
|
+
<html>
|
|
22
|
+
<head>
|
|
23
|
+
<title>SSR App</title>
|
|
24
|
+
</head>
|
|
25
|
+
<body>
|
|
26
|
+
<div id="root">${html}</div>
|
|
27
|
+
<script type="module" src="/client.js"></script>
|
|
28
|
+
</body>
|
|
29
|
+
</html>
|
|
30
|
+
`);
|
|
200
31
|
});
|
|
201
32
|
|
|
202
33
|
app.listen(port, () => {
|
|
@@ -2,31 +2,22 @@
|
|
|
2
2
|
"compilerOptions": {
|
|
3
3
|
"target": "ES2022",
|
|
4
4
|
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
|
5
|
-
"allowJs":
|
|
5
|
+
"allowJs": false,
|
|
6
6
|
"skipLibCheck": true,
|
|
7
|
-
"esModuleInterop":
|
|
7
|
+
"esModuleInterop": false,
|
|
8
8
|
"allowSyntheticDefaultImports": true,
|
|
9
9
|
"strict": true,
|
|
10
10
|
"forceConsistentCasingInFileNames": true,
|
|
11
11
|
"module": "ESNext",
|
|
12
|
-
"moduleResolution": "
|
|
12
|
+
"moduleResolution": "bundler",
|
|
13
13
|
"resolveJsonModule": true,
|
|
14
14
|
"isolatedModules": true,
|
|
15
15
|
"noEmit": true,
|
|
16
16
|
"jsx": "preserve",
|
|
17
|
-
"
|
|
18
|
-
"outDir": "./dist",
|
|
19
|
-
"rootDir": "./src",
|
|
20
|
-
"baseUrl": ".",
|
|
21
|
-
"paths": {
|
|
22
|
-
"@/*": ["./src/*"]
|
|
23
|
-
}
|
|
17
|
+
"jsxImportSource": "frontend-hamroun"
|
|
24
18
|
},
|
|
25
19
|
"include": [
|
|
26
|
-
"src
|
|
27
|
-
|
|
28
|
-
"exclude": [
|
|
29
|
-
"node_modules",
|
|
30
|
-
"dist"
|
|
20
|
+
"src",
|
|
21
|
+
"server.ts"
|
|
31
22
|
]
|
|
32
23
|
}
|
|
@@ -1,24 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"extends": "./tsconfig.json",
|
|
3
3
|
"compilerOptions": {
|
|
4
|
-
"target": "ES2022",
|
|
5
4
|
"module": "ESNext",
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
"
|
|
9
|
-
"
|
|
10
|
-
"outDir": "./dist",
|
|
11
|
-
"rootDir": "./src",
|
|
12
|
-
"esModuleInterop": true,
|
|
13
|
-
"allowSyntheticDefaultImports": true,
|
|
14
|
-
"skipLibCheck": true
|
|
5
|
+
"outDir": "dist",
|
|
6
|
+
"noEmit": false,
|
|
7
|
+
"jsx": "preserve",
|
|
8
|
+
"moduleResolution": "bundler"
|
|
15
9
|
},
|
|
16
|
-
"include": [
|
|
17
|
-
"src/server.ts",
|
|
18
|
-
"src/**/*.ts"
|
|
19
|
-
],
|
|
20
|
-
"exclude": [
|
|
21
|
-
"src/client.tsx",
|
|
22
|
-
"node_modules"
|
|
23
|
-
]
|
|
10
|
+
"include": ["src/server.ts"]
|
|
24
11
|
}
|
|
File without changes
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
import { spawn } from 'child_process';
|
|
2
|
+
import { join, dirname } from 'path';
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
4
|
+
import fs from 'fs';
|
|
5
|
+
|
|
6
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
7
|
+
const __dirname = dirname(__filename);
|
|
8
|
+
|
|
9
|
+
const goDir = join(__dirname, 'go');
|
|
10
|
+
const outputDir = join(__dirname, 'public');
|
|
11
|
+
const wasmFile = join(outputDir, 'example.wasm');
|
|
12
|
+
|
|
13
|
+
// Prevent infinite loops by checking if we're already running
|
|
14
|
+
const lockFile = join(__dirname, '.build-lock');
|
|
15
|
+
if (fs.existsSync(lockFile)) {
|
|
16
|
+
console.log('Build already in progress, skipping...');
|
|
17
|
+
process.exit(0);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Create lock file
|
|
21
|
+
fs.writeFileSync(lockFile, process.pid.toString());
|
|
22
|
+
|
|
23
|
+
// Clean up lock file on exit
|
|
24
|
+
process.on('exit', () => {
|
|
25
|
+
try {
|
|
26
|
+
fs.unlinkSync(lockFile);
|
|
27
|
+
} catch (e) {
|
|
28
|
+
// Ignore cleanup errors
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
process.on('SIGINT', () => {
|
|
33
|
+
try {
|
|
34
|
+
fs.unlinkSync(lockFile);
|
|
35
|
+
} catch (e) {
|
|
36
|
+
// Ignore cleanup errors
|
|
37
|
+
}
|
|
38
|
+
process.exit(0);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
// Ensure public directory exists
|
|
42
|
+
if (!fs.existsSync(outputDir)) {
|
|
43
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Only create Go files if they don't exist (prevent infinite generation)
|
|
47
|
+
if (!fs.existsSync(goDir) || !fs.existsSync(join(goDir, 'main.go'))) {
|
|
48
|
+
console.log('Creating Go WASM example files...');
|
|
49
|
+
fs.mkdirSync(goDir, { recursive: true });
|
|
50
|
+
|
|
51
|
+
// Create the corrected Go main file with proper function names
|
|
52
|
+
const goMainContent = `package main
|
|
53
|
+
|
|
54
|
+
import (
|
|
55
|
+
"fmt"
|
|
56
|
+
"strings"
|
|
57
|
+
"syscall/js"
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
func goHello(this js.Value, inputs []js.Value) interface{} {
|
|
61
|
+
name := inputs[0].String()
|
|
62
|
+
return fmt.Sprintf("Hello, %s from Go WASM!", name)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
func goAdd(this js.Value, inputs []js.Value) interface{} {
|
|
66
|
+
a := inputs[0].Int()
|
|
67
|
+
b := inputs[1].Int()
|
|
68
|
+
return a + b
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
func goMultiply(this js.Value, inputs []js.Value) interface{} {
|
|
72
|
+
a := inputs[0].Float()
|
|
73
|
+
b := inputs[1].Float()
|
|
74
|
+
return a * b
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
func goFibonacci(this js.Value, inputs []js.Value) interface{} {
|
|
78
|
+
n := inputs[0].Int()
|
|
79
|
+
if n <= 1 {
|
|
80
|
+
return n
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
a, b := 0, 1
|
|
84
|
+
for i := 2; i <= n; i++ {
|
|
85
|
+
a, b = b, a+b
|
|
86
|
+
}
|
|
87
|
+
return b
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
func goIsPrime(this js.Value, inputs []js.Value) interface{} {
|
|
91
|
+
n := inputs[0].Int()
|
|
92
|
+
if n < 2 {
|
|
93
|
+
return false
|
|
94
|
+
}
|
|
95
|
+
if n == 2 {
|
|
96
|
+
return true
|
|
97
|
+
}
|
|
98
|
+
if n%2 == 0 {
|
|
99
|
+
return false
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
for i := 3; i*i <= n; i += 2 {
|
|
103
|
+
if n%i == 0 {
|
|
104
|
+
return false
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return true
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
func main() {
|
|
111
|
+
fmt.Println("Go WASM initialized")
|
|
112
|
+
|
|
113
|
+
// Register functions with correct names that match the frontend
|
|
114
|
+
js.Global().Set("goHello", js.FuncOf(goHello))
|
|
115
|
+
js.Global().Set("goAdd", js.FuncOf(goAdd))
|
|
116
|
+
js.Global().Set("goMultiply", js.FuncOf(goMultiply))
|
|
117
|
+
js.Global().Set("goFibonacci", js.FuncOf(goFibonacci))
|
|
118
|
+
js.Global().Set("goIsPrime", js.FuncOf(goIsPrime))
|
|
119
|
+
|
|
120
|
+
fmt.Println("Go functions registered and ready!")
|
|
121
|
+
|
|
122
|
+
// Keep the program running
|
|
123
|
+
select {}
|
|
124
|
+
}
|
|
125
|
+
`;
|
|
126
|
+
|
|
127
|
+
fs.writeFileSync(join(goDir, 'main.go'), goMainContent);
|
|
128
|
+
|
|
129
|
+
// Create go.mod file
|
|
130
|
+
const goModContent = `module wasm-example
|
|
131
|
+
|
|
132
|
+
go 1.21
|
|
133
|
+
`;
|
|
134
|
+
|
|
135
|
+
fs.writeFileSync(join(goDir, 'go.mod'), goModContent);
|
|
136
|
+
|
|
137
|
+
console.log('✅ Go example files created');
|
|
138
|
+
} else {
|
|
139
|
+
console.log('Go files already exist, skipping creation');
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
console.log('Building Go WASM module...');
|
|
143
|
+
|
|
144
|
+
// Set environment variables for WASM compilation
|
|
145
|
+
const env = {
|
|
146
|
+
...process.env,
|
|
147
|
+
GOOS: 'js',
|
|
148
|
+
GOARCH: 'wasm'
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
// Build command
|
|
152
|
+
const buildArgs = ['build', '-o', wasmFile, 'main.go'];
|
|
153
|
+
|
|
154
|
+
console.log(`Running: go ${buildArgs.join(' ')}`);
|
|
155
|
+
console.log(`Working directory: ${goDir}`);
|
|
156
|
+
console.log(`Output: ${wasmFile}`);
|
|
157
|
+
|
|
158
|
+
const goProcess = spawn('go', buildArgs, {
|
|
159
|
+
cwd: goDir,
|
|
160
|
+
env: env,
|
|
161
|
+
stdio: 'inherit',
|
|
162
|
+
shell: true
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
goProcess.on('close', (code) => {
|
|
166
|
+
// Clean up lock file
|
|
167
|
+
try {
|
|
168
|
+
fs.unlinkSync(lockFile);
|
|
169
|
+
} catch (e) {
|
|
170
|
+
// Ignore cleanup errors
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if (code === 0) {
|
|
174
|
+
console.log('✅ Go WASM build successful!');
|
|
175
|
+
console.log(`📦 WASM file created: ${wasmFile}`);
|
|
176
|
+
|
|
177
|
+
// Check if wasm_exec.js exists, if not, copy it
|
|
178
|
+
const wasmExecJs = join(outputDir, 'wasm_exec.js');
|
|
179
|
+
if (!fs.existsSync(wasmExecJs)) {
|
|
180
|
+
console.log('📋 Copying wasm_exec.js...');
|
|
181
|
+
|
|
182
|
+
// Try to find wasm_exec.js in GOROOT
|
|
183
|
+
const findWasmExec = spawn('go', ['env', 'GOROOT'], {
|
|
184
|
+
stdio: 'pipe',
|
|
185
|
+
shell: true
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
let goroot = '';
|
|
189
|
+
findWasmExec.stdout.on('data', (data) => {
|
|
190
|
+
goroot += data.toString().trim();
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
findWasmExec.on('close', () => {
|
|
194
|
+
if (goroot) {
|
|
195
|
+
const wasmExecSource = join(goroot, 'misc', 'wasm', 'wasm_exec.js');
|
|
196
|
+
if (fs.existsSync(wasmExecSource)) {
|
|
197
|
+
fs.copyFileSync(wasmExecSource, wasmExecJs);
|
|
198
|
+
console.log('✅ wasm_exec.js copied successfully');
|
|
199
|
+
} else {
|
|
200
|
+
console.log('⚠️ wasm_exec.js not found, you may need to copy it manually');
|
|
201
|
+
console.log(`Expected location: ${wasmExecSource}`);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
} else {
|
|
207
|
+
console.error('❌ Go WASM build failed with exit code:', code);
|
|
208
|
+
console.log('\n💡 Troubleshooting tips:');
|
|
209
|
+
console.log('1. Make sure Go is installed and in your PATH');
|
|
210
|
+
console.log('2. Check that your Go code in ./go/main.go is valid');
|
|
211
|
+
console.log('3. Ensure you have Go 1.11+ for WASM support');
|
|
212
|
+
process.exit(1);
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
goProcess.on('error', (error) => {
|
|
217
|
+
// Clean up lock file
|
|
218
|
+
try {
|
|
219
|
+
fs.unlinkSync(lockFile);
|
|
220
|
+
} catch (e) {
|
|
221
|
+
// Ignore cleanup errors
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
console.error('❌ Failed to start Go build process:', error.message);
|
|
225
|
+
console.log('\n💡 Make sure Go is installed and available in your PATH');
|
|
226
|
+
console.log('Download Go from: https://golang.org/dl/');
|
|
227
|
+
process.exit(1);
|
|
228
|
+
});
|