frontend-hamroun 1.2.80 → 1.2.83
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/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.client.cjs +1 -1
- package/dist/index.client.js +2 -2
- package/dist/index.js +11 -7
- package/dist/index.js.map +1 -1
- package/dist/{renderer-Din1y3YM.cjs → renderer-BL3gq8cW.cjs} +2 -2
- package/dist/{renderer-Din1y3YM.cjs.map → renderer-BL3gq8cW.cjs.map} +1 -1
- package/dist/{renderer-Bo9zkUZ_.js → renderer-Dyy-o05F.js} +2 -2
- package/dist/{renderer-Bo9zkUZ_.js.map → renderer-Dyy-o05F.js.map} +1 -1
- package/dist/{server-renderer-QHt45Ip2.js → server-renderer-C1WXH-zV.js} +99 -73
- package/dist/server-renderer-C1WXH-zV.js.map +1 -0
- package/dist/server-renderer-Chs-nmJm.cjs +2 -0
- package/dist/server-renderer-Chs-nmJm.cjs.map +1 -0
- package/dist/server-renderer.cjs +1 -1
- package/dist/server-renderer.js +1 -1
- package/package.json +1 -1
- package/templates/basic-app/src/App.jsx +16 -0
- package/templates/basic-app/src/client.jsx +5 -0
- package/templates/basic-app/src/components/Counter.jsx +13 -0
- package/templates/basic-app/src/jsx-shim.js +3 -0
- package/templates/basic-app/src/jsx-shim.ts +7 -0
- package/templates/basic-app/src/main.jsx +98 -0
- package/templates/basic-app/src/server.js +47 -0
- package/templates/complete-app/api/hello.js +0 -0
- package/templates/complete-app/lib/frontend-hamroun.js +182 -0
- package/templates/complete-app/package.json +18 -0
- package/templates/complete-app/pages/about.js +119 -0
- package/templates/complete-app/pages/about.jsx +0 -0
- package/templates/complete-app/pages/index.js +157 -0
- package/templates/complete-app/pages/index.jsx +0 -0
- package/templates/complete-app/pages/wasm-demo.js +290 -0
- package/templates/complete-app/pages/wasm-demo.jsx +0 -0
- package/templates/complete-app/public/client.js +89 -0
- package/templates/complete-app/public/index.html +118 -0
- package/templates/complete-app/public/styles.css +76 -0
- package/templates/complete-app/server.js +226 -0
- package/templates/complete-app/src/App.tsx +59 -0
- package/templates/complete-app/src/client.tsx +18 -0
- package/templates/complete-app/src/server.ts +218 -0
- package/templates/complete-app/tsconfig.json +22 -0
- package/templates/complete-app/tsconfig.server.json +19 -0
- package/templates/{ssr-template → complete-app}/vite.config.js +16 -5
- package/templates/complete-app/vite.config.ts +30 -0
- package/templates/complete-app/wasm/build.bat +0 -0
- package/templates/complete-app/wasm/build.sh +0 -0
- package/templates/complete-app/wasm/example.go +0 -0
- package/templates/fullstack-app/build/main.css +874 -874
- package/templates/fullstack-app/build/main.css.map +7 -7
- package/templates/fullstack-app/build/main.js +996 -967
- package/templates/fullstack-app/build/main.js.map +7 -7
- package/templates/fullstack-app/package-lock.json +6301 -0
- package/templates/fullstack-app/public/styles.css +768 -768
- package/templates/go/example.go +154 -99
- package/templates/ssr-template/dist/client/assets/main-D-VH3xOb.js +1 -0
- package/templates/ssr-template/dist/client/index.html +23 -0
- package/templates/ssr-template/dist/client.js +951 -0
- package/templates/ssr-template/dist/server.js +739 -0
- package/templates/ssr-template/esbuild.config.js +33 -0
- package/templates/ssr-template/jsx-shim.js +1 -0
- package/templates/ssr-template/package.json +14 -8
- package/templates/ssr-template/src/App.tsx +847 -49
- package/templates/ssr-template/src/client.tsx +3 -17
- package/templates/ssr-template/src/server.ts +21 -204
- package/templates/ssr-template/tsconfig.json +9 -8
- package/templates/ssr-template/tsconfig.server.json +6 -14
- package/templates/ssr-template/vite.config.ts +19 -17
- package/templates/wasm/build-wasm.js +228 -0
- package/templates/wasm/dist/assets/index-BNqTDBdE.js +295 -0
- package/templates/wasm/dist/example.wasm +0 -0
- package/templates/wasm/dist/index.html +53 -0
- package/templates/{go-wasm-app/public/wasm → wasm/dist}/wasm_exec.js +572 -561
- 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 +4577 -0
- package/templates/wasm/package.json +25 -0
- package/templates/wasm/public/example.wasm +0 -0
- package/templates/wasm/public/wasm_exec.js +572 -0
- package/templates/wasm/src/App.tsx +550 -0
- package/templates/wasm/src/client.tsx +220 -0
- package/templates/wasm/src/index.tsx +21 -0
- package/templates/wasm/src/server.ts +145 -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 +38 -0
- package/templates/wasm/wasm-loader.js +103 -0
- package/dist/server-renderer-CqIpQ-od.cjs +0 -2
- package/dist/server-renderer-CqIpQ-od.cjs.map +0 -1
- package/dist/server-renderer-QHt45Ip2.js.map +0 -1
- package/templates/basic-app/bun.lock +0 -196
- package/templates/basic-app/docs/rapport_pfe.aux +0 -27
- package/templates/basic-app/docs/rapport_pfe.out +0 -10
- package/templates/basic-app/docs/rapport_pfe.pdf +0 -0
- package/templates/basic-app/docs/rapport_pfe.tex +0 -68
- package/templates/basic-app/docs/rapport_pfe.toc +0 -14
- package/templates/basic-app/package-lock.json +0 -4185
- package/templates/go-wasm-app/README.md +0 -38
- package/templates/go-wasm-app/babel.config.js +0 -15
- package/templates/go-wasm-app/build-client.js +0 -49
- package/templates/go-wasm-app/build-wasm.js +0 -237
- package/templates/go-wasm-app/package.json +0 -23
- package/templates/go-wasm-app/public/index.html +0 -128
- package/templates/go-wasm-app/public/styles.css +0 -197
- package/templates/go-wasm-app/public/wasm/example.wasm +0 -0
- package/templates/go-wasm-app/public/wasm/wasm_exec_node.js +0 -39
- package/templates/go-wasm-app/server.js +0 -521
- package/templates/go-wasm-app/src/App.jsx +0 -38
- package/templates/go-wasm-app/src/app.js +0 -153
- package/templates/go-wasm-app/src/client.js +0 -57
- package/templates/go-wasm-app/src/components/Footer.jsx +0 -13
- package/templates/go-wasm-app/src/components/Header.jsx +0 -19
- package/templates/go-wasm-app/src/components/WasmDemo.jsx +0 -120
- package/templates/go-wasm-app/src/main.jsx +0 -12
- package/templates/go-wasm-app/src/wasm/example.go +0 -75
- package/templates/go-wasm-app/tsconfig.server.json +0 -18
- package/templates/go-wasm-app/vite.config.js +0 -34
- package/templates/ssr-template/package-lock.json +0 -2478
- package/templates/ssr-template/public/index.html +0 -47
- package/templates/ssr-template/server.js +0 -369
- /package/templates/{ssr-template → complete-app}/client.js +0 -0
- /package/templates/{ssr-template → complete-app}/readme.md +0 -0
- /package/templates/{ssr-template → complete-app}/server.ts +0 -0
- /package/templates/{ssr-template → complete-app}/src/client.ts +0 -0
- /package/templates/{ssr-template → complete-app}/src/pages/index.tsx +0 -0
@@ -1,18 +1,4 @@
|
|
1
|
-
import { hydrate,
|
1
|
+
import { hydrate, jsx } from 'frontend-hamroun';
|
2
|
+
import { App } from './App.js';
|
2
3
|
|
3
|
-
|
4
|
-
// In a more complex app, you might use a router
|
5
|
-
import HomePage from './pages/index';
|
6
|
-
|
7
|
-
// When the DOM is ready, hydrate the server-rendered HTML
|
8
|
-
document.addEventListener('DOMContentLoaded', () => {
|
9
|
-
const rootElement = document.getElementById('app');
|
10
|
-
|
11
|
-
if (rootElement) {
|
12
|
-
// Hydrate the app with the same component that was rendered on the server
|
13
|
-
hydrate(<HomePage />, rootElement);
|
14
|
-
console.log('Hydration complete');
|
15
|
-
} else {
|
16
|
-
console.error('Could not find root element with id "app"');
|
17
|
-
}
|
18
|
-
});
|
4
|
+
hydrate(jsx(App, {}), document.getElementById('root')!);
|
@@ -3,214 +3,31 @@ import path from 'path';
|
|
3
3
|
import { fileURLToPath } from 'url';
|
4
4
|
import { renderToString, jsx } from 'frontend-hamroun';
|
5
5
|
import { App } from './App.js';
|
6
|
-
import fs from 'fs';
|
7
6
|
|
8
|
-
const
|
7
|
+
const __filename = fileURLToPath(import.meta.url);
|
8
|
+
const __dirname = path.dirname(__filename);
|
9
|
+
|
9
10
|
const app = express();
|
10
11
|
const port = 3000;
|
11
12
|
|
12
|
-
//
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
// Helper to check if a file exists
|
31
|
-
const fileExists = async (filePath) => {
|
32
|
-
try {
|
33
|
-
await fs.promises.access(filePath);
|
34
|
-
return true;
|
35
|
-
} catch {
|
36
|
-
return false;
|
37
|
-
}
|
38
|
-
};
|
39
|
-
|
40
|
-
// Map URL path to component path
|
41
|
-
const getComponentPath = async (urlPath) => {
|
42
|
-
const pagesDir = getPagesDirectory();
|
43
|
-
|
44
|
-
// Handle root path
|
45
|
-
if (urlPath === '/') {
|
46
|
-
const indexPath = path.join(pagesDir, 'index.js');
|
47
|
-
if (await fileExists(indexPath)) {
|
48
|
-
return {
|
49
|
-
componentPath: indexPath,
|
50
|
-
params: {}
|
51
|
-
};
|
52
|
-
}
|
53
|
-
}
|
54
|
-
|
55
|
-
// Try direct match (e.g., /about -> /pages/about.js)
|
56
|
-
const directPath = path.join(pagesDir, `${urlPath.slice(1)}.js`);
|
57
|
-
if (await fileExists(directPath)) {
|
58
|
-
return {
|
59
|
-
componentPath: directPath,
|
60
|
-
params: {}
|
61
|
-
};
|
62
|
-
}
|
63
|
-
|
64
|
-
// Try directory index (e.g., /about -> /pages/about/index.js)
|
65
|
-
const dirIndexPath = path.join(pagesDir, urlPath.slice(1), 'index.js');
|
66
|
-
if (await fileExists(dirIndexPath)) {
|
67
|
-
return {
|
68
|
-
componentPath: dirIndexPath,
|
69
|
-
params: {}
|
70
|
-
};
|
71
|
-
}
|
72
|
-
|
73
|
-
// Look for dynamic routes (with [param] in filename)
|
74
|
-
const segments = urlPath.split('/').filter(Boolean);
|
75
|
-
const dynamicRoutes = [];
|
76
|
-
|
77
|
-
// Recursively scan pages directory for all files
|
78
|
-
const scanDir = (dir, basePath = '') => {
|
79
|
-
const items = fs.readdirSync(dir, { withFileTypes: true });
|
80
|
-
|
81
|
-
for (const item of items) {
|
82
|
-
const itemPath = path.join(dir, item.name);
|
83
|
-
const routePath = path.join(basePath, item.name);
|
84
|
-
|
85
|
-
if (item.isDirectory()) {
|
86
|
-
scanDir(itemPath, routePath);
|
87
|
-
} else if (item.name.endsWith('.js') && item.name.includes('[')) {
|
88
|
-
// This is a dynamic route file
|
89
|
-
const urlPattern = routePath
|
90
|
-
.replace(/\.js$/, '')
|
91
|
-
.replace(/\[([^\]]+)\]/g, ':$1');
|
92
|
-
|
93
|
-
dynamicRoutes.push({
|
94
|
-
pattern: urlPattern,
|
95
|
-
componentPath: itemPath
|
96
|
-
});
|
97
|
-
}
|
98
|
-
}
|
99
|
-
};
|
100
|
-
|
101
|
-
scanDir(pagesDir);
|
102
|
-
|
103
|
-
// Check if any dynamic routes match
|
104
|
-
for (const route of dynamicRoutes) {
|
105
|
-
const routeSegments = route.pattern.split('/').filter(Boolean);
|
106
|
-
if (routeSegments.length !== segments.length) continue;
|
107
|
-
|
108
|
-
const params = {};
|
109
|
-
let matches = true;
|
110
|
-
|
111
|
-
for (let i = 0; i < segments.length; i++) {
|
112
|
-
const routeSeg = routeSegments[i];
|
113
|
-
const urlSeg = segments[i];
|
114
|
-
|
115
|
-
if (routeSeg.startsWith(':')) {
|
116
|
-
// This is a parameter
|
117
|
-
const paramName = routeSeg.slice(1);
|
118
|
-
params[paramName] = urlSeg;
|
119
|
-
} else if (routeSeg !== urlSeg) {
|
120
|
-
matches = false;
|
121
|
-
break;
|
122
|
-
}
|
123
|
-
}
|
124
|
-
|
125
|
-
if (matches) {
|
126
|
-
return {
|
127
|
-
componentPath: route.componentPath,
|
128
|
-
params
|
129
|
-
};
|
130
|
-
}
|
131
|
-
}
|
132
|
-
|
133
|
-
// No match found
|
134
|
-
return null;
|
135
|
-
};
|
136
|
-
|
137
|
-
// Handle all routes with auto-routing
|
138
|
-
app.get('*', async (req, res) => {
|
139
|
-
try {
|
140
|
-
const clientEntry = getClientEntry();
|
141
|
-
const routeResult = await getComponentPath(req.path);
|
142
|
-
|
143
|
-
if (!routeResult) {
|
144
|
-
return res.status(404).send(`
|
145
|
-
<!DOCTYPE html>
|
146
|
-
<html>
|
147
|
-
<head>
|
148
|
-
<title>404 - Page Not Found</title>
|
149
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
150
|
-
</head>
|
151
|
-
<body>
|
152
|
-
<div id="root">
|
153
|
-
<h1>404 - Page Not Found</h1>
|
154
|
-
<p>The page you requested could not be found.</p>
|
155
|
-
</div>
|
156
|
-
<script type="module" src="/assets/${clientEntry}"></script>
|
157
|
-
</body>
|
158
|
-
</html>
|
159
|
-
`);
|
160
|
-
}
|
161
|
-
|
162
|
-
// Import the component dynamically
|
163
|
-
const { default: PageComponent } = await import(routeResult.componentPath);
|
164
|
-
|
165
|
-
if (!PageComponent) {
|
166
|
-
throw new Error(`Invalid component in ${routeResult.componentPath}`);
|
167
|
-
}
|
168
|
-
|
169
|
-
// Render the component with params
|
170
|
-
const html = await renderToString(jsx(PageComponent, { params: routeResult.params }));
|
171
|
-
|
172
|
-
// Create route data for client hydration
|
173
|
-
const initialState = {
|
174
|
-
route: req.path,
|
175
|
-
params: routeResult.params,
|
176
|
-
timestamp: new Date().toISOString()
|
177
|
-
};
|
178
|
-
|
179
|
-
res.send(`
|
180
|
-
<!DOCTYPE html>
|
181
|
-
<html>
|
182
|
-
<head>
|
183
|
-
<title>Frontend Hamroun SSR</title>
|
184
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
185
|
-
<meta charset="UTF-8">
|
186
|
-
</head>
|
187
|
-
<body>
|
188
|
-
<div id="root">${html}</div>
|
189
|
-
<script>window.__INITIAL_STATE__ = ${JSON.stringify(initialState)}</script>
|
190
|
-
<script type="module" src="/assets/${clientEntry}"></script>
|
191
|
-
</body>
|
192
|
-
</html>
|
193
|
-
`);
|
194
|
-
} catch (error) {
|
195
|
-
console.error('Rendering error:', error);
|
196
|
-
res.status(500).send(`
|
197
|
-
<!DOCTYPE html>
|
198
|
-
<html>
|
199
|
-
<head>
|
200
|
-
<title>500 - Server Error</title>
|
201
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
202
|
-
</head>
|
203
|
-
<body>
|
204
|
-
<div id="root">
|
205
|
-
<h1>500 - Server Error</h1>
|
206
|
-
<p>Something went wrong on the server.</p>
|
207
|
-
<pre>${process.env.NODE_ENV === 'production' ? '' : error.stack}</pre>
|
208
|
-
</div>
|
209
|
-
<script type="module" src="/assets/${clientEntry}"></script>
|
210
|
-
</body>
|
211
|
-
</html>
|
212
|
-
`);
|
213
|
-
}
|
13
|
+
// Serve static files from dist directory
|
14
|
+
app.use(express.static(path.join(__dirname)));
|
15
|
+
|
16
|
+
app.get('/', async (req, res) => {
|
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
|
+
`);
|
214
31
|
});
|
215
32
|
|
216
33
|
app.listen(port, () => {
|
@@ -1,22 +1,23 @@
|
|
1
1
|
{
|
2
2
|
"compilerOptions": {
|
3
|
-
"target": "
|
4
|
-
"
|
5
|
-
"lib": ["DOM", "DOM.Iterable", "ESNext"],
|
3
|
+
"target": "ES2022",
|
4
|
+
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
6
5
|
"allowJs": false,
|
7
6
|
"skipLibCheck": true,
|
8
|
-
"esModuleInterop":
|
7
|
+
"esModuleInterop": false,
|
9
8
|
"allowSyntheticDefaultImports": true,
|
10
9
|
"strict": true,
|
11
10
|
"forceConsistentCasingInFileNames": true,
|
12
11
|
"module": "ESNext",
|
13
|
-
"moduleResolution": "
|
12
|
+
"moduleResolution": "bundler",
|
14
13
|
"resolveJsonModule": true,
|
15
14
|
"isolatedModules": true,
|
16
15
|
"noEmit": true,
|
17
16
|
"jsx": "preserve",
|
18
|
-
"
|
19
|
-
"jsxFragmentFactory": "Fragment"
|
17
|
+
"jsxImportSource": "frontend-hamroun"
|
20
18
|
},
|
21
|
-
"include": [
|
19
|
+
"include": [
|
20
|
+
"src",
|
21
|
+
"server.ts"
|
22
|
+
]
|
22
23
|
}
|
@@ -1,19 +1,11 @@
|
|
1
1
|
{
|
2
2
|
"extends": "./tsconfig.json",
|
3
3
|
"compilerOptions": {
|
4
|
-
"
|
5
|
-
"
|
6
|
-
"
|
7
|
-
"
|
8
|
-
"
|
9
|
-
"declaration": true,
|
10
|
-
"sourceMap": true,
|
11
|
-
"strict": true,
|
12
|
-
"skipLibCheck": true,
|
13
|
-
"jsx": "react",
|
14
|
-
"jsxFactory": "createElement",
|
15
|
-
"jsxFragmentFactory": "Fragment"
|
4
|
+
"module": "ESNext",
|
5
|
+
"outDir": "dist",
|
6
|
+
"noEmit": false,
|
7
|
+
"jsx": "preserve",
|
8
|
+
"moduleResolution": "bundler"
|
16
9
|
},
|
17
|
-
"include": ["server.ts"
|
18
|
-
"exclude": ["node_modules", "dist"]
|
10
|
+
"include": ["src/server.ts"]
|
19
11
|
}
|
@@ -2,29 +2,31 @@ import { defineConfig } from 'vite';
|
|
2
2
|
import path from 'path';
|
3
3
|
|
4
4
|
export default defineConfig({
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
5
|
+
esbuild: {
|
6
|
+
jsx: 'transform',
|
7
|
+
jsxFactory: 'jsx',
|
8
|
+
jsxFragment: 'Fragment',
|
9
|
+
jsxImportSource: 'frontend-hamroun',
|
10
|
+
},
|
11
|
+
ssr: {
|
12
|
+
noExternal: ['frontend-hamroun']
|
13
|
+
},
|
14
|
+
optimizeDeps: {
|
15
|
+
include: ['frontend-hamroun'],
|
16
|
+
exclude: []
|
9
17
|
},
|
10
18
|
build: {
|
11
|
-
|
12
|
-
ssr: 'src/server.ts',
|
19
|
+
target: 'esnext',
|
13
20
|
rollupOptions: {
|
14
|
-
input: {
|
15
|
-
client: './src/client.tsx',
|
16
|
-
server: './src/server.ts'
|
17
|
-
},
|
18
21
|
output: {
|
19
|
-
|
20
|
-
chunkFileNames: 'assets/[name]-[hash].js',
|
21
|
-
assetFileNames: 'assets/[name]-[hash].[ext]'
|
22
|
+
format: 'es'
|
22
23
|
}
|
23
24
|
}
|
24
25
|
},
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
26
|
+
resolve: {
|
27
|
+
alias: {
|
28
|
+
'frontend-hamroun/jsx-dev-runtime': 'frontend-hamroun',
|
29
|
+
'frontend-hamroun/jsx-runtime': 'frontend-hamroun'
|
30
|
+
}
|
29
31
|
}
|
30
32
|
});
|
@@ -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
|
+
});
|