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.
Files changed (128) hide show
  1. package/dist/index.cjs +1 -1
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.client.cjs +1 -1
  4. package/dist/index.client.js +2 -2
  5. package/dist/index.js +11 -7
  6. package/dist/index.js.map +1 -1
  7. package/dist/{renderer-Din1y3YM.cjs → renderer-BL3gq8cW.cjs} +2 -2
  8. package/dist/{renderer-Din1y3YM.cjs.map → renderer-BL3gq8cW.cjs.map} +1 -1
  9. package/dist/{renderer-Bo9zkUZ_.js → renderer-Dyy-o05F.js} +2 -2
  10. package/dist/{renderer-Bo9zkUZ_.js.map → renderer-Dyy-o05F.js.map} +1 -1
  11. package/dist/{server-renderer-QHt45Ip2.js → server-renderer-C1WXH-zV.js} +99 -73
  12. package/dist/server-renderer-C1WXH-zV.js.map +1 -0
  13. package/dist/server-renderer-Chs-nmJm.cjs +2 -0
  14. package/dist/server-renderer-Chs-nmJm.cjs.map +1 -0
  15. package/dist/server-renderer.cjs +1 -1
  16. package/dist/server-renderer.js +1 -1
  17. package/package.json +1 -1
  18. package/templates/basic-app/src/App.jsx +16 -0
  19. package/templates/basic-app/src/client.jsx +5 -0
  20. package/templates/basic-app/src/components/Counter.jsx +13 -0
  21. package/templates/basic-app/src/jsx-shim.js +3 -0
  22. package/templates/basic-app/src/jsx-shim.ts +7 -0
  23. package/templates/basic-app/src/main.jsx +98 -0
  24. package/templates/basic-app/src/server.js +47 -0
  25. package/templates/complete-app/api/hello.js +0 -0
  26. package/templates/complete-app/lib/frontend-hamroun.js +182 -0
  27. package/templates/complete-app/package.json +18 -0
  28. package/templates/complete-app/pages/about.js +119 -0
  29. package/templates/complete-app/pages/about.jsx +0 -0
  30. package/templates/complete-app/pages/index.js +157 -0
  31. package/templates/complete-app/pages/index.jsx +0 -0
  32. package/templates/complete-app/pages/wasm-demo.js +290 -0
  33. package/templates/complete-app/pages/wasm-demo.jsx +0 -0
  34. package/templates/complete-app/public/client.js +89 -0
  35. package/templates/complete-app/public/index.html +118 -0
  36. package/templates/complete-app/public/styles.css +76 -0
  37. package/templates/complete-app/server.js +226 -0
  38. package/templates/complete-app/src/App.tsx +59 -0
  39. package/templates/complete-app/src/client.tsx +18 -0
  40. package/templates/complete-app/src/server.ts +218 -0
  41. package/templates/complete-app/tsconfig.json +22 -0
  42. package/templates/complete-app/tsconfig.server.json +19 -0
  43. package/templates/{ssr-template → complete-app}/vite.config.js +16 -5
  44. package/templates/complete-app/vite.config.ts +30 -0
  45. package/templates/complete-app/wasm/build.bat +0 -0
  46. package/templates/complete-app/wasm/build.sh +0 -0
  47. package/templates/complete-app/wasm/example.go +0 -0
  48. package/templates/fullstack-app/build/main.css +874 -874
  49. package/templates/fullstack-app/build/main.css.map +7 -7
  50. package/templates/fullstack-app/build/main.js +996 -967
  51. package/templates/fullstack-app/build/main.js.map +7 -7
  52. package/templates/fullstack-app/package-lock.json +6301 -0
  53. package/templates/fullstack-app/public/styles.css +768 -768
  54. package/templates/go/example.go +154 -99
  55. package/templates/ssr-template/dist/client/assets/main-D-VH3xOb.js +1 -0
  56. package/templates/ssr-template/dist/client/index.html +23 -0
  57. package/templates/ssr-template/dist/client.js +951 -0
  58. package/templates/ssr-template/dist/server.js +739 -0
  59. package/templates/ssr-template/esbuild.config.js +33 -0
  60. package/templates/ssr-template/jsx-shim.js +1 -0
  61. package/templates/ssr-template/package.json +14 -8
  62. package/templates/ssr-template/src/App.tsx +847 -49
  63. package/templates/ssr-template/src/client.tsx +3 -17
  64. package/templates/ssr-template/src/server.ts +21 -204
  65. package/templates/ssr-template/tsconfig.json +9 -8
  66. package/templates/ssr-template/tsconfig.server.json +6 -14
  67. package/templates/ssr-template/vite.config.ts +19 -17
  68. package/templates/wasm/build-wasm.js +228 -0
  69. package/templates/wasm/dist/assets/index-BNqTDBdE.js +295 -0
  70. package/templates/wasm/dist/example.wasm +0 -0
  71. package/templates/wasm/dist/index.html +53 -0
  72. package/templates/{go-wasm-app/public/wasm → wasm/dist}/wasm_exec.js +572 -561
  73. package/templates/wasm/esbuild.config.js +63 -0
  74. package/templates/wasm/go/main.go +256 -0
  75. package/templates/wasm/go/wasm_exec.js +0 -0
  76. package/templates/wasm/index.html +97 -0
  77. package/templates/wasm/jsx-shim.js +9 -0
  78. package/templates/wasm/package-lock.json +4577 -0
  79. package/templates/wasm/package.json +25 -0
  80. package/templates/wasm/public/example.wasm +0 -0
  81. package/templates/wasm/public/wasm_exec.js +572 -0
  82. package/templates/wasm/src/App.tsx +550 -0
  83. package/templates/wasm/src/client.tsx +220 -0
  84. package/templates/wasm/src/index.tsx +21 -0
  85. package/templates/wasm/src/server.ts +145 -0
  86. package/templates/wasm/tsconfig.json +21 -0
  87. package/templates/wasm/tsconfig.node.json +13 -0
  88. package/templates/wasm/tsconfig.server.json +23 -0
  89. package/templates/wasm/vite.config.ts +38 -0
  90. package/templates/wasm/wasm-loader.js +103 -0
  91. package/dist/server-renderer-CqIpQ-od.cjs +0 -2
  92. package/dist/server-renderer-CqIpQ-od.cjs.map +0 -1
  93. package/dist/server-renderer-QHt45Ip2.js.map +0 -1
  94. package/templates/basic-app/bun.lock +0 -196
  95. package/templates/basic-app/docs/rapport_pfe.aux +0 -27
  96. package/templates/basic-app/docs/rapport_pfe.out +0 -10
  97. package/templates/basic-app/docs/rapport_pfe.pdf +0 -0
  98. package/templates/basic-app/docs/rapport_pfe.tex +0 -68
  99. package/templates/basic-app/docs/rapport_pfe.toc +0 -14
  100. package/templates/basic-app/package-lock.json +0 -4185
  101. package/templates/go-wasm-app/README.md +0 -38
  102. package/templates/go-wasm-app/babel.config.js +0 -15
  103. package/templates/go-wasm-app/build-client.js +0 -49
  104. package/templates/go-wasm-app/build-wasm.js +0 -237
  105. package/templates/go-wasm-app/package.json +0 -23
  106. package/templates/go-wasm-app/public/index.html +0 -128
  107. package/templates/go-wasm-app/public/styles.css +0 -197
  108. package/templates/go-wasm-app/public/wasm/example.wasm +0 -0
  109. package/templates/go-wasm-app/public/wasm/wasm_exec_node.js +0 -39
  110. package/templates/go-wasm-app/server.js +0 -521
  111. package/templates/go-wasm-app/src/App.jsx +0 -38
  112. package/templates/go-wasm-app/src/app.js +0 -153
  113. package/templates/go-wasm-app/src/client.js +0 -57
  114. package/templates/go-wasm-app/src/components/Footer.jsx +0 -13
  115. package/templates/go-wasm-app/src/components/Header.jsx +0 -19
  116. package/templates/go-wasm-app/src/components/WasmDemo.jsx +0 -120
  117. package/templates/go-wasm-app/src/main.jsx +0 -12
  118. package/templates/go-wasm-app/src/wasm/example.go +0 -75
  119. package/templates/go-wasm-app/tsconfig.server.json +0 -18
  120. package/templates/go-wasm-app/vite.config.js +0 -34
  121. package/templates/ssr-template/package-lock.json +0 -2478
  122. package/templates/ssr-template/public/index.html +0 -47
  123. package/templates/ssr-template/server.js +0 -369
  124. /package/templates/{ssr-template → complete-app}/client.js +0 -0
  125. /package/templates/{ssr-template → complete-app}/readme.md +0 -0
  126. /package/templates/{ssr-template → complete-app}/server.ts +0 -0
  127. /package/templates/{ssr-template → complete-app}/src/client.ts +0 -0
  128. /package/templates/{ssr-template → complete-app}/src/pages/index.tsx +0 -0
@@ -1,18 +1,4 @@
1
- import { hydrate, createElement } from 'frontend-hamroun';
1
+ import { hydrate, jsx } from 'frontend-hamroun';
2
+ import { App } from './App.js';
2
3
 
3
- // For simplicity in this example, we just hydrate the root component
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 __dirname = path.dirname(fileURLToPath(import.meta.url));
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
- // Find the client entry file
13
- const getClientEntry = () => {
14
- const assetsDir = path.join(__dirname, './');
15
- const files = fs.readdirSync(assetsDir);
16
- return files.find(file => file.startsWith("client") && file.endsWith('.js'));
17
- };
18
-
19
- // Serve static files from dist/assets
20
- app.use('/assets', express.static(path.join(__dirname, './')));
21
-
22
- // Serve static files from dist
23
- app.use(express.static(path.join(__dirname, 'dist')));
24
-
25
- // Auto-routing middleware - scans the pages directory for components
26
- const getPagesDirectory = () => {
27
- return path.join(__dirname, 'pages');
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": "ESNext",
4
- "useDefineForClassFields": true,
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": true,
7
+ "esModuleInterop": false,
9
8
  "allowSyntheticDefaultImports": true,
10
9
  "strict": true,
11
10
  "forceConsistentCasingInFileNames": true,
12
11
  "module": "ESNext",
13
- "moduleResolution": "Node",
12
+ "moduleResolution": "bundler",
14
13
  "resolveJsonModule": true,
15
14
  "isolatedModules": true,
16
15
  "noEmit": true,
17
16
  "jsx": "preserve",
18
- "jsxFactory": "createElement",
19
- "jsxFragmentFactory": "Fragment"
17
+ "jsxImportSource": "frontend-hamroun"
20
18
  },
21
- "include": ["src"]
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
- "target": "ES2020",
5
- "module": "NodeNext",
6
- "moduleResolution": "NodeNext",
7
- "esModuleInterop": true,
8
- "outDir": "./dist/server",
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", "src/pages/**/*.tsx"],
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
- resolve: {
6
- alias: {
7
- 'frontend-hamroun': path.resolve(__dirname, 'node_modules/frontend-hamroun')
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
- outDir: 'dist',
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
- entryFileNames: '[name].js',
20
- chunkFileNames: 'assets/[name]-[hash].js',
21
- assetFileNames: 'assets/[name]-[hash].[ext]'
22
+ format: 'es'
22
23
  }
23
24
  }
24
25
  },
25
- esbuild: {
26
- jsxFactory: '_jsx',
27
- jsxFragment: '_Fragment',
28
- jsxInject: `import { jsx as _jsx, Fragment as _Fragment } from 'frontend-hamroun'`
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
+ });