frontend-hamroun 1.2.64 → 1.2.66
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/README.md +972 -216
- package/bin/cli.js +190 -2
- package/dist/index.d.ts +2 -0
- package/dist/wasm.d.ts +36 -0
- package/package.json +1 -1
- package/templates/go/README.md +150 -0
- package/templates/go/build.bat +36 -0
- package/templates/go/build.sh +43 -0
- package/templates/go/example.go +137 -0
- package/templates/go-wasm-app/.tmp-wasm-build/example.go +75 -0
- package/templates/go-wasm-app/.tmp-wasm-build/go.mod +3 -0
- package/templates/go-wasm-app/README.md +21 -0
- package/templates/go-wasm-app/build-wasm.js +218 -0
- package/templates/go-wasm-app/package-lock.json +4123 -0
- package/templates/go-wasm-app/package.json +20 -0
- package/templates/go-wasm-app/public/index.html +13 -0
- package/templates/go-wasm-app/public/styles.css +167 -0
- package/templates/go-wasm-app/src/App.jsx +64 -0
- package/templates/go-wasm-app/src/components/WasmDemo.jsx +119 -0
- package/templates/go-wasm-app/src/main.jsx +7 -0
- package/templates/go-wasm-app/src/wasm/example.go +75 -0
- package/templates/go-wasm-app/vite.config.js +28 -0
@@ -0,0 +1,20 @@
|
|
1
|
+
{
|
2
|
+
"name": "go-wasm-app",
|
3
|
+
"version": "1.0.0",
|
4
|
+
"description": "WebAssembly integration with Go for Frontend Hamroun",
|
5
|
+
"type": "module",
|
6
|
+
"main": "index.js",
|
7
|
+
"scripts": {
|
8
|
+
"build:wasm": "node build-wasm.js",
|
9
|
+
"dev": "npm run build:wasm && vite",
|
10
|
+
"build": "npm run build:wasm && vite build",
|
11
|
+
"serve": "vite preview",
|
12
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
13
|
+
},
|
14
|
+
"dependencies": {
|
15
|
+
"frontend-hamroun": "^1.2.0"
|
16
|
+
},
|
17
|
+
"devDependencies": {
|
18
|
+
"vite": "^4.4.9"
|
19
|
+
}
|
20
|
+
}
|
@@ -0,0 +1,13 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html lang="en">
|
3
|
+
<head>
|
4
|
+
<meta charset="UTF-8">
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
6
|
+
<title>Frontend Hamroun + Go WebAssembly</title>
|
7
|
+
<link rel="stylesheet" href="/styles.css">
|
8
|
+
</head>
|
9
|
+
<body>
|
10
|
+
<div id="root"></div>
|
11
|
+
<script type="module" src="/src/main.jsx"></script>
|
12
|
+
</body>
|
13
|
+
</html>
|
@@ -0,0 +1,167 @@
|
|
1
|
+
:root {
|
2
|
+
--primary-color: #0070f3;
|
3
|
+
--secondary-color: #0051cc;
|
4
|
+
--background: #f9f9f9;
|
5
|
+
--text-color: #333;
|
6
|
+
--card-background: #fff;
|
7
|
+
--border-color: #eaeaea;
|
8
|
+
--error-color: #f44336;
|
9
|
+
--success-color: #4caf50;
|
10
|
+
}
|
11
|
+
|
12
|
+
* {
|
13
|
+
box-sizing: border-box;
|
14
|
+
}
|
15
|
+
|
16
|
+
body {
|
17
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
|
18
|
+
background-color: var(--background);
|
19
|
+
color: var(--text-color);
|
20
|
+
margin: 0;
|
21
|
+
padding: 0;
|
22
|
+
line-height: 1.6;
|
23
|
+
}
|
24
|
+
|
25
|
+
.app {
|
26
|
+
max-width: 900px;
|
27
|
+
margin: 0 auto;
|
28
|
+
padding: 20px;
|
29
|
+
}
|
30
|
+
|
31
|
+
header {
|
32
|
+
text-align: center;
|
33
|
+
margin-bottom: 2rem;
|
34
|
+
}
|
35
|
+
|
36
|
+
header h1 {
|
37
|
+
margin-bottom: 0.5rem;
|
38
|
+
color: var(--primary-color);
|
39
|
+
}
|
40
|
+
|
41
|
+
header p {
|
42
|
+
color: #666;
|
43
|
+
}
|
44
|
+
|
45
|
+
footer {
|
46
|
+
margin-top: 3rem;
|
47
|
+
text-align: center;
|
48
|
+
color: #666;
|
49
|
+
padding: 1rem 0;
|
50
|
+
border-top: 1px solid var(--border-color);
|
51
|
+
}
|
52
|
+
|
53
|
+
footer a {
|
54
|
+
color: var(--primary-color);
|
55
|
+
text-decoration: none;
|
56
|
+
}
|
57
|
+
|
58
|
+
.loading {
|
59
|
+
text-align: center;
|
60
|
+
padding: 2rem;
|
61
|
+
}
|
62
|
+
|
63
|
+
.error {
|
64
|
+
background-color: rgba(244, 67, 54, 0.1);
|
65
|
+
border: 1px solid var(--error-color);
|
66
|
+
border-radius: 8px;
|
67
|
+
padding: 1rem;
|
68
|
+
margin: 1rem 0;
|
69
|
+
}
|
70
|
+
|
71
|
+
.error-message {
|
72
|
+
background-color: rgba(244, 67, 54, 0.1);
|
73
|
+
color: var(--error-color);
|
74
|
+
padding: 1rem;
|
75
|
+
border-radius: 8px;
|
76
|
+
margin-bottom: 1rem;
|
77
|
+
}
|
78
|
+
|
79
|
+
.demo-section {
|
80
|
+
background-color: var(--card-background);
|
81
|
+
border: 1px solid var(--border-color);
|
82
|
+
border-radius: 8px;
|
83
|
+
padding: 1.5rem;
|
84
|
+
margin-bottom: 2rem;
|
85
|
+
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
|
86
|
+
}
|
87
|
+
|
88
|
+
.input-row {
|
89
|
+
display: flex;
|
90
|
+
align-items: center;
|
91
|
+
gap: 0.5rem;
|
92
|
+
margin-bottom: 1rem;
|
93
|
+
}
|
94
|
+
|
95
|
+
.input-row input {
|
96
|
+
width: 80px;
|
97
|
+
padding: 0.5rem;
|
98
|
+
border: 1px solid var(--border-color);
|
99
|
+
border-radius: 4px;
|
100
|
+
font-size: 1rem;
|
101
|
+
}
|
102
|
+
|
103
|
+
.input-row .operator {
|
104
|
+
font-size: 1.5rem;
|
105
|
+
margin: 0 0.5rem;
|
106
|
+
}
|
107
|
+
|
108
|
+
button {
|
109
|
+
background-color: var(--primary-color);
|
110
|
+
color: white;
|
111
|
+
border: none;
|
112
|
+
border-radius: 4px;
|
113
|
+
padding: 0.5rem 1rem;
|
114
|
+
cursor: pointer;
|
115
|
+
font-size: 1rem;
|
116
|
+
transition: background-color 0.2s;
|
117
|
+
}
|
118
|
+
|
119
|
+
button:hover {
|
120
|
+
background-color: var(--secondary-color);
|
121
|
+
}
|
122
|
+
|
123
|
+
.json-editor {
|
124
|
+
display: flex;
|
125
|
+
flex-direction: column;
|
126
|
+
gap: 1rem;
|
127
|
+
}
|
128
|
+
|
129
|
+
.json-editor textarea {
|
130
|
+
width: 100%;
|
131
|
+
padding: 0.5rem;
|
132
|
+
border: 1px solid var(--border-color);
|
133
|
+
border-radius: 4px;
|
134
|
+
font-family: monospace;
|
135
|
+
font-size: 0.9rem;
|
136
|
+
resize: vertical;
|
137
|
+
}
|
138
|
+
|
139
|
+
.result {
|
140
|
+
background-color: #f0f7ff;
|
141
|
+
padding: 1rem;
|
142
|
+
border-radius: 4px;
|
143
|
+
margin-top: 1rem;
|
144
|
+
}
|
145
|
+
|
146
|
+
.result pre {
|
147
|
+
margin: 0;
|
148
|
+
white-space: pre-wrap;
|
149
|
+
font-family: monospace;
|
150
|
+
font-size: 0.9rem;
|
151
|
+
}
|
152
|
+
|
153
|
+
.info-section {
|
154
|
+
background-color: #f0f7ff;
|
155
|
+
border: 1px solid #e1e7fd;
|
156
|
+
border-radius: 8px;
|
157
|
+
padding: 1.5rem;
|
158
|
+
}
|
159
|
+
|
160
|
+
.info-section h2 {
|
161
|
+
color: var(--primary-color);
|
162
|
+
margin-top: 0;
|
163
|
+
}
|
164
|
+
|
165
|
+
.info-section ol {
|
166
|
+
padding-left: 1.5rem;
|
167
|
+
}
|
@@ -0,0 +1,64 @@
|
|
1
|
+
import { jsx, useState, useEffect } from 'frontend-hamroun';
|
2
|
+
import { loadGoWasm } from 'frontend-hamroun';
|
3
|
+
import WasmDemo from './components/WasmDemo';
|
4
|
+
|
5
|
+
export default function App() {
|
6
|
+
const [wasmLoaded, setWasmLoaded] = useState(false);
|
7
|
+
const [wasmInstance, setWasmInstance] = useState(null);
|
8
|
+
const [error, setError] = useState(null);
|
9
|
+
|
10
|
+
// Load the WASM module
|
11
|
+
useEffect(() => {
|
12
|
+
async function loadWasm() {
|
13
|
+
try {
|
14
|
+
console.log('Loading WASM module...');
|
15
|
+
const instance = await loadGoWasm('/wasm/example.wasm', {
|
16
|
+
goWasmPath: '/wasm/wasm_exec.js',
|
17
|
+
debug: true
|
18
|
+
});
|
19
|
+
|
20
|
+
console.log('WASM module loaded successfully');
|
21
|
+
setWasmInstance(instance);
|
22
|
+
setWasmLoaded(true);
|
23
|
+
} catch (err) {
|
24
|
+
console.error('Failed to load WASM:', err);
|
25
|
+
setError(err.message);
|
26
|
+
}
|
27
|
+
}
|
28
|
+
|
29
|
+
loadWasm();
|
30
|
+
}, []);
|
31
|
+
|
32
|
+
return (
|
33
|
+
<div className="app">
|
34
|
+
<header>
|
35
|
+
<h1>Frontend Hamroun + Go WebAssembly</h1>
|
36
|
+
<p>A powerful combination for high-performance web applications</p>
|
37
|
+
</header>
|
38
|
+
|
39
|
+
<main>
|
40
|
+
{error ? (
|
41
|
+
<div className="error">
|
42
|
+
<h2>Failed to load WebAssembly</h2>
|
43
|
+
<p>{error}</p>
|
44
|
+
<p>Make sure you've built the WASM modules with <code>npm run build:wasm</code></p>
|
45
|
+
</div>
|
46
|
+
) : wasmLoaded ? (
|
47
|
+
<WasmDemo wasm={wasmInstance} />
|
48
|
+
) : (
|
49
|
+
<div className="loading">
|
50
|
+
<p>Loading WebAssembly module...</p>
|
51
|
+
</div>
|
52
|
+
)}
|
53
|
+
</main>
|
54
|
+
|
55
|
+
<footer>
|
56
|
+
<p>
|
57
|
+
Built with <a href="https://github.com/hamroun/frontend-hamroun" target="_blank" rel="noopener noreferrer">
|
58
|
+
Frontend Hamroun
|
59
|
+
</a> and Go WebAssembly
|
60
|
+
</p>
|
61
|
+
</footer>
|
62
|
+
</div>
|
63
|
+
);
|
64
|
+
}
|
@@ -0,0 +1,119 @@
|
|
1
|
+
import { jsx, useState } from 'frontend-hamroun';
|
2
|
+
|
3
|
+
export default function WasmDemo({ wasm }) {
|
4
|
+
// Addition demo state
|
5
|
+
const [num1, setNum1] = useState(5);
|
6
|
+
const [num2, setNum2] = useState(7);
|
7
|
+
const [sum, setSum] = useState(null);
|
8
|
+
|
9
|
+
// Data processing demo state
|
10
|
+
const [processInput, setProcessInput] = useState(JSON.stringify({
|
11
|
+
name: 'Test data',
|
12
|
+
values: [10, 20, 30, 40, 50],
|
13
|
+
timestamp: new Date().toISOString()
|
14
|
+
}, null, 2));
|
15
|
+
const [processResult, setProcessResult] = useState(null);
|
16
|
+
|
17
|
+
// Error state
|
18
|
+
const [error, setError] = useState(null);
|
19
|
+
|
20
|
+
// Handle addition with Go WASM
|
21
|
+
const handleCalculate = () => {
|
22
|
+
try {
|
23
|
+
setError(null);
|
24
|
+
// Get the goAdd function from the WASM instance
|
25
|
+
const goAdd = wasm.functions.goAdd;
|
26
|
+
// Call the Go function and get the result
|
27
|
+
const result = goAdd(parseInt(num1), parseInt(num2));
|
28
|
+
setSum(result);
|
29
|
+
} catch (err) {
|
30
|
+
console.error('Error calling Go function:', err);
|
31
|
+
setError(`Error: ${err.message}`);
|
32
|
+
}
|
33
|
+
};
|
34
|
+
|
35
|
+
// Handle complex data processing with Go WASM
|
36
|
+
const handleProcessData = () => {
|
37
|
+
try {
|
38
|
+
setError(null);
|
39
|
+
// Parse the input JSON
|
40
|
+
const inputData = JSON.parse(processInput);
|
41
|
+
// Get the goProcessData function from the WASM instance
|
42
|
+
const goProcessData = wasm.functions.goProcessData;
|
43
|
+
// Call the Go function with the data
|
44
|
+
const result = goProcessData(inputData);
|
45
|
+
// Parse the returned JSON and format it
|
46
|
+
setProcessResult(JSON.parse(result));
|
47
|
+
} catch (err) {
|
48
|
+
console.error('Error processing data with Go:', err);
|
49
|
+
setError(`Error: ${err.message}`);
|
50
|
+
}
|
51
|
+
};
|
52
|
+
|
53
|
+
return (
|
54
|
+
<div className="wasm-demo">
|
55
|
+
{error && (
|
56
|
+
<div className="error-message">
|
57
|
+
{error}
|
58
|
+
</div>
|
59
|
+
)}
|
60
|
+
|
61
|
+
<section className="demo-section">
|
62
|
+
<h2>Simple Addition with Go</h2>
|
63
|
+
<p>Call a Go WASM function to add two numbers:</p>
|
64
|
+
<div className="input-row">
|
65
|
+
<input
|
66
|
+
type="number"
|
67
|
+
value={num1}
|
68
|
+
onChange={(e) => setNum1(e.target.value)}
|
69
|
+
/>
|
70
|
+
<span className="operator">+</span>
|
71
|
+
<input
|
72
|
+
type="number"
|
73
|
+
value={num2}
|
74
|
+
onChange={(e) => setNum2(e.target.value)}
|
75
|
+
/>
|
76
|
+
<button onClick={handleCalculate}>Calculate</button>
|
77
|
+
</div>
|
78
|
+
|
79
|
+
{sum !== null && (
|
80
|
+
<div className="result">
|
81
|
+
<h3>Result:</h3>
|
82
|
+
<pre>{sum}</pre>
|
83
|
+
</div>
|
84
|
+
)}
|
85
|
+
</section>
|
86
|
+
|
87
|
+
<section className="demo-section">
|
88
|
+
<h2>Complex Data Processing with Go</h2>
|
89
|
+
<p>Process JSON data using a Go WASM function:</p>
|
90
|
+
<div className="json-editor">
|
91
|
+
<textarea
|
92
|
+
value={processInput}
|
93
|
+
onChange={(e) => setProcessInput(e.target.value)}
|
94
|
+
rows={10}
|
95
|
+
/>
|
96
|
+
<button onClick={handleProcessData}>Process Data</button>
|
97
|
+
</div>
|
98
|
+
|
99
|
+
{processResult && (
|
100
|
+
<div className="result">
|
101
|
+
<h3>Processed Result:</h3>
|
102
|
+
<pre>{JSON.stringify(processResult, null, 2)}</pre>
|
103
|
+
</div>
|
104
|
+
)}
|
105
|
+
</section>
|
106
|
+
|
107
|
+
<section className="info-section">
|
108
|
+
<h2>How It Works</h2>
|
109
|
+
<p>This demo demonstrates the integration between Frontend Hamroun and Go WebAssembly:</p>
|
110
|
+
<ol>
|
111
|
+
<li>Go code is compiled to WebAssembly and loaded in the browser</li>
|
112
|
+
<li>JavaScript calls functions exported by the Go WASM module</li>
|
113
|
+
<li>Data can be passed back and forth between JavaScript and Go</li>
|
114
|
+
<li>Complex operations can be performed efficiently in Go</li>
|
115
|
+
</ol>
|
116
|
+
</section>
|
117
|
+
</div>
|
118
|
+
);
|
119
|
+
}
|
@@ -0,0 +1,75 @@
|
|
1
|
+
//go:build js && wasm
|
2
|
+
// +build js,wasm
|
3
|
+
|
4
|
+
package main
|
5
|
+
|
6
|
+
import (
|
7
|
+
"encoding/json"
|
8
|
+
"fmt"
|
9
|
+
"syscall/js"
|
10
|
+
)
|
11
|
+
|
12
|
+
// Example Go function to be called from JavaScript
|
13
|
+
func add(this js.Value, args []js.Value) interface{} {
|
14
|
+
if len(args) != 2 {
|
15
|
+
return js.ValueOf("Error: Expected two arguments")
|
16
|
+
}
|
17
|
+
|
18
|
+
a := args[0].Int()
|
19
|
+
b := args[1].Int()
|
20
|
+
return js.ValueOf(a + b)
|
21
|
+
}
|
22
|
+
|
23
|
+
// Process complex data in Go
|
24
|
+
func processData(this js.Value, args []js.Value) interface{} {
|
25
|
+
if len(args) == 0 {
|
26
|
+
return js.ValueOf("Error: Expected at least one argument")
|
27
|
+
}
|
28
|
+
|
29
|
+
// Get input data
|
30
|
+
data := args[0]
|
31
|
+
if data.Type() != js.TypeObject {
|
32
|
+
return js.ValueOf("Error: Expected JSON object")
|
33
|
+
}
|
34
|
+
|
35
|
+
// Convert JS object to Go map
|
36
|
+
jsonStr := js.Global().Get("JSON").Call("stringify", data).String()
|
37
|
+
var inputMap map[string]interface{}
|
38
|
+
if err := json.Unmarshal([]byte(jsonStr), &inputMap); err != nil {
|
39
|
+
return js.ValueOf(fmt.Sprintf("Error parsing JSON: %s", err.Error()))
|
40
|
+
}
|
41
|
+
|
42
|
+
// Add new fields
|
43
|
+
inputMap["processed"] = true
|
44
|
+
inputMap["processor"] = "Go WASM"
|
45
|
+
|
46
|
+
// Add some computed fields
|
47
|
+
if values, ok := inputMap["values"].([]interface{}); ok {
|
48
|
+
sum := 0.0
|
49
|
+
for _, v := range values {
|
50
|
+
if num, ok := v.(float64); ok {
|
51
|
+
sum += num
|
52
|
+
}
|
53
|
+
}
|
54
|
+
inputMap["sum"] = sum
|
55
|
+
}
|
56
|
+
|
57
|
+
// Convert back to JS
|
58
|
+
resultJSON, err := json.Marshal(inputMap)
|
59
|
+
if err != nil {
|
60
|
+
return js.ValueOf(fmt.Sprintf("Error generating JSON: %s", err.Error()))
|
61
|
+
}
|
62
|
+
|
63
|
+
return js.ValueOf(string(resultJSON))
|
64
|
+
}
|
65
|
+
|
66
|
+
func main() {
|
67
|
+
fmt.Println("Go WASM Module initialized")
|
68
|
+
|
69
|
+
// Register functions to be callable from JavaScript
|
70
|
+
js.Global().Set("goAdd", js.FuncOf(add))
|
71
|
+
js.Global().Set("goProcessData", js.FuncOf(processData))
|
72
|
+
|
73
|
+
// Keep the program running
|
74
|
+
<-make(chan bool)
|
75
|
+
}
|
@@ -0,0 +1,28 @@
|
|
1
|
+
import { defineConfig } from 'vite';
|
2
|
+
import { resolve } from 'path';
|
3
|
+
|
4
|
+
export default defineConfig({
|
5
|
+
// Configure JSX
|
6
|
+
esbuild: {
|
7
|
+
jsxFactory: 'jsx',
|
8
|
+
jsxFragment: 'Fragment'
|
9
|
+
},
|
10
|
+
|
11
|
+
// Configure build
|
12
|
+
build: {
|
13
|
+
outDir: 'dist',
|
14
|
+
emptyOutDir: true,
|
15
|
+
rollupOptions: {
|
16
|
+
input: {
|
17
|
+
main: resolve(__dirname, 'public/index.html')
|
18
|
+
}
|
19
|
+
}
|
20
|
+
},
|
21
|
+
|
22
|
+
// Resolve aliases
|
23
|
+
resolve: {
|
24
|
+
alias: {
|
25
|
+
'@': resolve(__dirname, 'src')
|
26
|
+
}
|
27
|
+
}
|
28
|
+
});
|