frontend-hamroun 1.2.75 → 1.2.77
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/batch/package.json +16 -0
- package/dist/client-router/package.json +16 -0
- package/dist/component/package.json +16 -0
- package/dist/context/package.json +16 -0
- package/dist/event-bus/package.json +16 -0
- package/dist/forms/package.json +16 -0
- package/dist/hooks/package.json +16 -0
- package/dist/jsx-runtime/package.json +16 -0
- package/dist/lifecycle-events/package.json +16 -0
- package/dist/package.json +71 -0
- package/dist/render-component/package.json +16 -0
- package/dist/renderer/package.json +16 -0
- package/dist/router/package.json +16 -0
- package/dist/server/package.json +17 -0
- package/dist/server/src/client-router.d.ts +60 -0
- package/dist/server/src/client-router.js +210 -0
- package/dist/server/src/client-router.js.map +1 -0
- package/dist/server/src/component.js +1 -1
- package/dist/server/src/event-bus.d.ts +23 -0
- package/dist/server/src/event-bus.js +75 -0
- package/dist/server/src/event-bus.js.map +1 -0
- package/dist/server/src/forms.d.ts +40 -0
- package/dist/server/src/forms.js +148 -0
- package/dist/server/src/forms.js.map +1 -0
- package/dist/server/src/hooks.js +2 -2
- package/dist/server/src/index.js +19 -11
- package/dist/server/src/lifecycle-events.d.ts +108 -0
- package/dist/server/src/lifecycle-events.js +177 -0
- package/dist/server/src/lifecycle-events.js.map +1 -0
- package/dist/server/src/renderComponent.js +1 -1
- package/dist/server/src/renderer.js +3 -3
- package/dist/server/src/router.d.ts +55 -0
- package/dist/server/src/router.js +166 -0
- package/dist/server/src/router.js.map +1 -0
- package/dist/server/src/server/index.d.ts +75 -2
- package/dist/server/src/server/index.js +224 -8
- package/dist/server/src/server/index.js.map +1 -1
- package/dist/server/src/server/server.js +1 -1
- package/dist/server/src/server/templates.d.ts +28 -0
- package/dist/server/src/server/templates.js +204 -0
- package/dist/server/src/server/templates.js.map +1 -0
- package/dist/server/src/server/utils.d.ts +70 -0
- package/dist/server/src/server/utils.js +156 -0
- package/dist/server/src/server/utils.js.map +1 -0
- package/dist/server/src/server-renderer.js +1 -1
- package/dist/server/src/store.d.ts +41 -0
- package/dist/server/src/store.js +99 -0
- package/dist/server/src/store.js.map +1 -0
- package/dist/server/src/utils.d.ts +46 -0
- package/dist/server/src/utils.js +144 -0
- package/dist/server/src/utils.js.map +1 -0
- package/dist/server/tsconfig.server.tsbuildinfo +1 -1
- package/dist/server-renderer/package.json +16 -0
- package/dist/store/package.json +16 -0
- package/dist/types/package.json +16 -0
- package/dist/utils/package.json +16 -0
- package/dist/vdom/package.json +16 -0
- package/dist/wasm/package.json +16 -0
- package/package.json +14 -13
- package/templates/complete-app/build.js +284 -0
- package/templates/complete-app/package.json +40 -0
- package/templates/complete-app/public/styles.css +345 -0
- package/templates/complete-app/src/api/index.js +31 -0
- package/templates/complete-app/src/client.js +93 -0
- package/templates/complete-app/src/components/App.js +66 -0
- package/templates/complete-app/src/components/Footer.js +19 -0
- package/templates/complete-app/src/components/Header.js +38 -0
- package/templates/complete-app/src/pages/About.js +59 -0
- package/templates/complete-app/src/pages/Home.js +54 -0
- package/templates/complete-app/src/pages/WasmDemo.js +136 -0
- package/templates/complete-app/src/server.js +186 -0
- package/templates/complete-app/src/wasm/build.bat +16 -0
- package/templates/complete-app/src/wasm/build.sh +16 -0
- package/templates/complete-app/src/wasm/example.go +101 -0
- package/templates/fullstack-app/build/main.css +225 -15
- package/templates/fullstack-app/build/main.css.map +2 -2
- package/templates/fullstack-app/build/main.js +657 -372
- package/templates/fullstack-app/build/main.js.map +4 -4
- package/templates/fullstack-app/build.ts +3 -4
- package/templates/fullstack-app/public/styles.css +222 -15
- package/templates/fullstack-app/server.ts +46 -12
- package/templates/fullstack-app/src/components/ClientHome.tsx +0 -0
- package/templates/fullstack-app/src/components/ErrorBoundary.tsx +36 -0
- package/templates/fullstack-app/src/components/Layout.tsx +23 -26
- package/templates/fullstack-app/src/components/StateDemo.tsx +207 -0
- package/templates/fullstack-app/src/components/UserList.tsx +30 -13
- package/templates/fullstack-app/src/data/api.ts +173 -38
- package/templates/fullstack-app/src/main.tsx +88 -154
- package/templates/fullstack-app/src/middleware.ts +28 -0
- package/templates/fullstack-app/src/pages/404.tsx +28 -0
- package/templates/fullstack-app/src/pages/[id].tsx +0 -0
- package/templates/fullstack-app/src/pages/_app.tsx +11 -0
- package/templates/fullstack-app/src/pages/_document.tsx +25 -0
- package/templates/fullstack-app/src/pages/_error.tsx +45 -0
- package/templates/fullstack-app/src/pages/about.tsx +71 -0
- package/templates/fullstack-app/src/pages/api/users/[id].ts +73 -0
- package/templates/fullstack-app/src/pages/api/users/index.ts +43 -0
- package/templates/fullstack-app/src/pages/index.tsx +97 -20
- package/templates/fullstack-app/src/pages/users/[id].tsx +153 -0
- package/templates/fullstack-app/src/pages/wasm-demo.tsx +1 -0
- package/templates/go/example.go +99 -86
- package/templates/go-wasm-app/babel.config.js +8 -2
- package/templates/go-wasm-app/build.config.js +62 -0
- package/templates/go-wasm-app/build.js +218 -0
- package/templates/go-wasm-app/package.json +21 -12
- package/templates/go-wasm-app/server.js +59 -510
- package/templates/go-wasm-app/src/app.js +173 -0
- package/templates/go-wasm-app/vite.config.js +16 -5
- package/templates/ssr-template/client.js +54 -26
- package/templates/ssr-template/server.js +5 -28
- package/templates/ssr-template/vite.config.js +21 -5
- package/dist/server/wasm.d.ts +0 -7
- package/dist/wasm.d.ts +0 -37
@@ -0,0 +1,93 @@
|
|
1
|
+
// Support both ESM and CommonJS importing styles
|
2
|
+
const frontendHamroun =
|
3
|
+
typeof require !== 'undefined'
|
4
|
+
? require('frontend-hamroun')
|
5
|
+
: await import('frontend-hamroun');
|
6
|
+
|
7
|
+
// Destructure the imports from either ESM or CJS modules
|
8
|
+
const {
|
9
|
+
hydrate,
|
10
|
+
render,
|
11
|
+
jsx,
|
12
|
+
useState,
|
13
|
+
useEffect,
|
14
|
+
loadGoWasm,
|
15
|
+
createContext,
|
16
|
+
useContext
|
17
|
+
} = frontendHamroun;
|
18
|
+
|
19
|
+
// Import components
|
20
|
+
import App from './components/App.js';
|
21
|
+
|
22
|
+
// Initialize the app
|
23
|
+
async function initApp() {
|
24
|
+
console.log('Initializing client-side app...');
|
25
|
+
|
26
|
+
// Check if we need to hydrate (SSR) or do a fresh render
|
27
|
+
const rootElement = document.getElementById('app');
|
28
|
+
const shouldHydrate = rootElement.hasAttribute('data-ssr');
|
29
|
+
|
30
|
+
try {
|
31
|
+
// Pre-load any WASM modules if needed
|
32
|
+
let wasmModule = null;
|
33
|
+
try {
|
34
|
+
wasmModule = await loadGoWasm('/wasm/example.wasm', {
|
35
|
+
debug: false,
|
36
|
+
goWasmPath: '/wasm/wasm_exec.js'
|
37
|
+
});
|
38
|
+
console.log('WASM module loaded successfully');
|
39
|
+
} catch (error) {
|
40
|
+
console.warn('WASM module loading skipped:', error.message);
|
41
|
+
}
|
42
|
+
|
43
|
+
// Create initial state from SSR data if available
|
44
|
+
const initialDataElement = document.getElementById('__INITIAL_DATA__');
|
45
|
+
const initialData = initialDataElement
|
46
|
+
? JSON.parse(initialDataElement.textContent || '{}')
|
47
|
+
: {};
|
48
|
+
|
49
|
+
// Setup global context values
|
50
|
+
const appContext = {
|
51
|
+
wasm: wasmModule,
|
52
|
+
initialData,
|
53
|
+
// Add any other global values
|
54
|
+
};
|
55
|
+
|
56
|
+
// Render or hydrate the app
|
57
|
+
if (shouldHydrate) {
|
58
|
+
console.log('Hydrating app from server-rendered HTML');
|
59
|
+
await hydrate(<App context={appContext} />, rootElement);
|
60
|
+
} else {
|
61
|
+
console.log('Rendering app from scratch (client-only)');
|
62
|
+
await render(<App context={appContext} />, rootElement);
|
63
|
+
}
|
64
|
+
|
65
|
+
console.log('App initialization complete');
|
66
|
+
} catch (error) {
|
67
|
+
console.error('Failed to initialize app:', error);
|
68
|
+
|
69
|
+
// Fallback to basic error display
|
70
|
+
rootElement.innerHTML = `
|
71
|
+
<div style="color: red; padding: 20px; border: 1px solid red; margin: 20px;">
|
72
|
+
<h2>Error Initializing App</h2>
|
73
|
+
<pre>${error.message}\n${error.stack}</pre>
|
74
|
+
</div>
|
75
|
+
`;
|
76
|
+
}
|
77
|
+
}
|
78
|
+
|
79
|
+
// Start the app when the DOM is ready
|
80
|
+
if (document.readyState === 'loading') {
|
81
|
+
document.addEventListener('DOMContentLoaded', initApp);
|
82
|
+
} else {
|
83
|
+
initApp();
|
84
|
+
}
|
85
|
+
|
86
|
+
// Export key utilities for components
|
87
|
+
export {
|
88
|
+
jsx,
|
89
|
+
useState,
|
90
|
+
useEffect,
|
91
|
+
createContext,
|
92
|
+
useContext
|
93
|
+
};
|
@@ -0,0 +1,66 @@
|
|
1
|
+
import { jsx, useState, useEffect, createContext, useContext } from '../client.js';
|
2
|
+
import Header from './Header.js';
|
3
|
+
import Footer from './Footer.js';
|
4
|
+
import Home from '../pages/Home.js';
|
5
|
+
import About from '../pages/About.js';
|
6
|
+
import WasmDemo from '../pages/WasmDemo.js';
|
7
|
+
|
8
|
+
// Create context for global state
|
9
|
+
export const AppContext = createContext({});
|
10
|
+
|
11
|
+
// Simple router implementation
|
12
|
+
function useRouter() {
|
13
|
+
const { initialData } = useContext(AppContext);
|
14
|
+
const [path, setPath] = useState(initialData?.path || '/');
|
15
|
+
|
16
|
+
useEffect(() => {
|
17
|
+
// Update path when URL changes
|
18
|
+
const handlePopState = () => {
|
19
|
+
setPath(window.location.pathname);
|
20
|
+
};
|
21
|
+
|
22
|
+
// Listen for navigation events
|
23
|
+
window.addEventListener('popstate', handlePopState);
|
24
|
+
|
25
|
+
// Cleanup
|
26
|
+
return () => {
|
27
|
+
window.removeEventListener('popstate', handlePopState);
|
28
|
+
};
|
29
|
+
}, []);
|
30
|
+
|
31
|
+
// Navigation function
|
32
|
+
const navigate = (to) => {
|
33
|
+
window.history.pushState(null, '', to);
|
34
|
+
setPath(to);
|
35
|
+
};
|
36
|
+
|
37
|
+
return { path, navigate };
|
38
|
+
}
|
39
|
+
|
40
|
+
// Define available routes
|
41
|
+
const routes = {
|
42
|
+
'/': Home,
|
43
|
+
'/about': About,
|
44
|
+
'/wasm': WasmDemo
|
45
|
+
};
|
46
|
+
|
47
|
+
// Main App component
|
48
|
+
export default function App({ context }) {
|
49
|
+
// Get current path from router
|
50
|
+
const { path, navigate } = useRouter();
|
51
|
+
|
52
|
+
// Find the component for the current route
|
53
|
+
const PageComponent = routes[path] || routes['/'];
|
54
|
+
|
55
|
+
return (
|
56
|
+
<AppContext.Provider value={{ ...context, navigate }}>
|
57
|
+
<div className="app">
|
58
|
+
<Header />
|
59
|
+
<main className="content">
|
60
|
+
<PageComponent />
|
61
|
+
</main>
|
62
|
+
<Footer />
|
63
|
+
</div>
|
64
|
+
</AppContext.Provider>
|
65
|
+
);
|
66
|
+
}
|
@@ -0,0 +1,19 @@
|
|
1
|
+
import { jsx } from '../client.js';
|
2
|
+
|
3
|
+
export default function Footer() {
|
4
|
+
return (
|
5
|
+
<footer className="app-footer">
|
6
|
+
<div className="footer-content">
|
7
|
+
<p>© {new Date().getFullYear()} Baraqex Framework</p>
|
8
|
+
<div className="footer-links">
|
9
|
+
<a href="https://github.com/hamroun/frontend-hamroun" target="_blank" rel="noopener">
|
10
|
+
GitHub
|
11
|
+
</a>
|
12
|
+
<a href="https://pfe-documantation-mohamedx2s-projects.vercel.app/" target="_blank" rel="noopener">
|
13
|
+
Documentation
|
14
|
+
</a>
|
15
|
+
</div>
|
16
|
+
</div>
|
17
|
+
</footer>
|
18
|
+
);
|
19
|
+
}
|
@@ -0,0 +1,38 @@
|
|
1
|
+
import { jsx } from '../client.js';
|
2
|
+
import { AppContext } from './App.js';
|
3
|
+
|
4
|
+
export default function Header() {
|
5
|
+
const { navigate } = AppContext;
|
6
|
+
|
7
|
+
const handleNavClick = (e, path) => {
|
8
|
+
e.preventDefault();
|
9
|
+
navigate(path);
|
10
|
+
};
|
11
|
+
|
12
|
+
return (
|
13
|
+
<header className="app-header">
|
14
|
+
<div className="logo">
|
15
|
+
<h1>Baraqex Complete App</h1>
|
16
|
+
</div>
|
17
|
+
<nav className="main-nav">
|
18
|
+
<ul>
|
19
|
+
<li>
|
20
|
+
<a href="/" onClick={(e) => handleNavClick(e, '/')}>
|
21
|
+
Home
|
22
|
+
</a>
|
23
|
+
</li>
|
24
|
+
<li>
|
25
|
+
<a href="/about" onClick={(e) => handleNavClick(e, '/about')}>
|
26
|
+
About
|
27
|
+
</a>
|
28
|
+
</li>
|
29
|
+
<li>
|
30
|
+
<a href="/wasm" onClick={(e) => handleNavClick(e, '/wasm')}>
|
31
|
+
WASM Demo
|
32
|
+
</a>
|
33
|
+
</li>
|
34
|
+
</ul>
|
35
|
+
</nav>
|
36
|
+
</header>
|
37
|
+
);
|
38
|
+
}
|
@@ -0,0 +1,59 @@
|
|
1
|
+
import { jsx, useEffect } from '../client.js';
|
2
|
+
|
3
|
+
export default function About() {
|
4
|
+
useEffect(() => {
|
5
|
+
document.title = 'About - Baraqex Complete App';
|
6
|
+
}, []);
|
7
|
+
|
8
|
+
return (
|
9
|
+
<div className="about-page">
|
10
|
+
<h1>About Baraqex Framework</h1>
|
11
|
+
|
12
|
+
<section className="about-section">
|
13
|
+
<h2>Framework Architecture</h2>
|
14
|
+
<p>
|
15
|
+
Baraqex is a lightweight full-stack JavaScript framework designed for modern web applications.
|
16
|
+
It features a virtual DOM implementation, hooks-based state management, server-side rendering,
|
17
|
+
and WebAssembly integration.
|
18
|
+
</p>
|
19
|
+
</section>
|
20
|
+
|
21
|
+
<section className="about-section">
|
22
|
+
<h2>Key Features</h2>
|
23
|
+
<ul>
|
24
|
+
<li>
|
25
|
+
<strong>Virtual DOM:</strong> Efficient DOM updates through a lightweight virtual DOM implementation.
|
26
|
+
</li>
|
27
|
+
<li>
|
28
|
+
<strong>Hooks:</strong> React-like hooks including useState, useEffect, useContext, and more.
|
29
|
+
</li>
|
30
|
+
<li>
|
31
|
+
<strong>Server-Side Rendering:</strong> Improve SEO and initial load performance with SSR.
|
32
|
+
</li>
|
33
|
+
<li>
|
34
|
+
<strong>WebAssembly Integration:</strong> Run high-performance Go code in the browser.
|
35
|
+
</li>
|
36
|
+
<li>
|
37
|
+
<strong>API Routing:</strong> Express-based API with file-based routing.
|
38
|
+
</li>
|
39
|
+
<li>
|
40
|
+
<strong>Development Tools:</strong> CLI tools for project scaffolding and component generation.
|
41
|
+
</li>
|
42
|
+
</ul>
|
43
|
+
</section>
|
44
|
+
|
45
|
+
<section className="about-section">
|
46
|
+
<h2>Use Cases</h2>
|
47
|
+
<p>
|
48
|
+
Baraqex is ideal for:
|
49
|
+
</p>
|
50
|
+
<ul>
|
51
|
+
<li>Web applications requiring high performance</li>
|
52
|
+
<li>Projects that need SEO optimization</li>
|
53
|
+
<li>Applications with computation-heavy features</li>
|
54
|
+
<li>Full-stack JavaScript applications</li>
|
55
|
+
</ul>
|
56
|
+
</section>
|
57
|
+
</div>
|
58
|
+
);
|
59
|
+
}
|
@@ -0,0 +1,54 @@
|
|
1
|
+
import { jsx, useState, useEffect, useContext } from '../client.js';
|
2
|
+
import { AppContext } from '../components/App.js';
|
3
|
+
|
4
|
+
export default function Home() {
|
5
|
+
const { initialData } = useContext(AppContext);
|
6
|
+
const [count, setCount] = useState(0);
|
7
|
+
|
8
|
+
useEffect(() => {
|
9
|
+
document.title = 'Home - Baraqex Complete App';
|
10
|
+
}, []);
|
11
|
+
|
12
|
+
return (
|
13
|
+
<div className="home-page">
|
14
|
+
<section className="hero">
|
15
|
+
<h1>Welcome to Baraqex Framework</h1>
|
16
|
+
<p className="subtitle">A complete JavaScript framework for modern web applications</p>
|
17
|
+
|
18
|
+
<div className="features">
|
19
|
+
<div className="feature">
|
20
|
+
<h3>Server-Side Rendering</h3>
|
21
|
+
<p>Initial page was rendered on the server at: {initialData?.timestamp}</p>
|
22
|
+
</div>
|
23
|
+
|
24
|
+
<div className="feature">
|
25
|
+
<h3>State Management</h3>
|
26
|
+
<div className="counter">
|
27
|
+
<button onClick={() => setCount(c => c - 1)}>-</button>
|
28
|
+
<span>{count}</span>
|
29
|
+
<button onClick={() => setCount(c => c + 1)}>+</button>
|
30
|
+
</div>
|
31
|
+
</div>
|
32
|
+
|
33
|
+
<div className="feature">
|
34
|
+
<h3>API Integration</h3>
|
35
|
+
<button className="api-button" onClick={fetchRandomData}>
|
36
|
+
Fetch Random Data
|
37
|
+
</button>
|
38
|
+
</div>
|
39
|
+
</div>
|
40
|
+
</section>
|
41
|
+
</div>
|
42
|
+
);
|
43
|
+
|
44
|
+
async function fetchRandomData() {
|
45
|
+
try {
|
46
|
+
const response = await fetch('/api/random');
|
47
|
+
const data = await response.json();
|
48
|
+
alert(`Random value: ${data.value}`);
|
49
|
+
} catch (error) {
|
50
|
+
console.error('Error fetching data:', error);
|
51
|
+
alert('Failed to fetch data. See console for details.');
|
52
|
+
}
|
53
|
+
}
|
54
|
+
}
|
@@ -0,0 +1,136 @@
|
|
1
|
+
import { jsx, useState, useEffect, useContext } from '../client.js';
|
2
|
+
import { AppContext } from '../components/App.js';
|
3
|
+
|
4
|
+
export default function WasmDemo() {
|
5
|
+
const { wasm } = useContext(AppContext);
|
6
|
+
|
7
|
+
// State for error display
|
8
|
+
const [error, setError] = useState(null);
|
9
|
+
|
10
|
+
// State for calculation form
|
11
|
+
const [num1, setNum1] = useState(5);
|
12
|
+
const [num2, setNum2] = useState(7);
|
13
|
+
const [result, setResult] = useState(null);
|
14
|
+
|
15
|
+
// State for JSON form
|
16
|
+
const [jsonInput, setJsonInput] = useState('{"name": "Baraqex", "version": "1.0"}');
|
17
|
+
const [jsonResult, setJsonResult] = useState(null);
|
18
|
+
|
19
|
+
useEffect(() => {
|
20
|
+
document.title = 'WebAssembly Demo - Baraqex Complete App';
|
21
|
+
|
22
|
+
// Demonstrate a calculation on mount if WASM is available
|
23
|
+
if (wasm && wasm.functions.goAdd) {
|
24
|
+
try {
|
25
|
+
const sum = wasm.functions.goAdd(5, 7);
|
26
|
+
setResult(sum);
|
27
|
+
} catch (err) {
|
28
|
+
console.error('Error in initial WASM calculation:', err);
|
29
|
+
}
|
30
|
+
}
|
31
|
+
}, [wasm]);
|
32
|
+
|
33
|
+
// Function to calculate using WASM
|
34
|
+
const calculateResult = () => {
|
35
|
+
if (!wasm || !wasm.functions.goAdd) {
|
36
|
+
setError('WASM module not loaded or function not available');
|
37
|
+
return;
|
38
|
+
}
|
39
|
+
|
40
|
+
try {
|
41
|
+
// Call the WASM function
|
42
|
+
const sum = wasm.functions.goAdd(parseInt(num1), parseInt(num2));
|
43
|
+
setResult(sum);
|
44
|
+
setError(null);
|
45
|
+
} catch (err) {
|
46
|
+
console.error('Error calling WASM function:', err);
|
47
|
+
setError('Error calling WASM function: ' + err);
|
48
|
+
}
|
49
|
+
};
|
50
|
+
|
51
|
+
// Function to parse JSON using WASM
|
52
|
+
const parseJsonWithWasm = () => {
|
53
|
+
if (!wasm || !wasm.functions.goParseJSON) {
|
54
|
+
setError('WASM module not loaded or JSON parsing function not available');
|
55
|
+
return;
|
56
|
+
}
|
57
|
+
|
58
|
+
try {
|
59
|
+
// Call the WASM function
|
60
|
+
const parsed = wasm.functions.goParseJSON(jsonInput);
|
61
|
+
setJsonResult(JSON.stringify(parsed, null, 2));
|
62
|
+
setError(null);
|
63
|
+
} catch (err) {
|
64
|
+
console.error('Error parsing JSON with WASM:', err);
|
65
|
+
setError('Error parsing JSON with WASM: ' + err);
|
66
|
+
}
|
67
|
+
};
|
68
|
+
|
69
|
+
return (
|
70
|
+
<div className="wasm-demo-page">
|
71
|
+
<h1>WebAssembly Integration Demo</h1>
|
72
|
+
|
73
|
+
{!wasm && (
|
74
|
+
<div className="wasm-status error">
|
75
|
+
<h3>WASM Not Available</h3>
|
76
|
+
<p>WebAssembly module could not be loaded. Please check the console for details.</p>
|
77
|
+
</div>
|
78
|
+
)}
|
79
|
+
|
80
|
+
{error && (
|
81
|
+
<div className="wasm-status error">
|
82
|
+
<h3>Error:</h3>
|
83
|
+
<pre>{error}</pre>
|
84
|
+
</div>
|
85
|
+
)}
|
86
|
+
|
87
|
+
{wasm && (
|
88
|
+
<div className="wasm-status success">
|
89
|
+
<h3>WASM Module Loaded Successfully</h3>
|
90
|
+
<p>The Go WebAssembly module has been loaded and is ready to use.</p>
|
91
|
+
</div>
|
92
|
+
)}
|
93
|
+
|
94
|
+
<div className="demo-section">
|
95
|
+
<h2>WASM Addition</h2>
|
96
|
+
<div className="calculator">
|
97
|
+
<input
|
98
|
+
type="number"
|
99
|
+
value={num1}
|
100
|
+
onChange={(e) => setNum1(e.target.value)}
|
101
|
+
/>
|
102
|
+
<span> + </span>
|
103
|
+
<input
|
104
|
+
type="number"
|
105
|
+
value={num2}
|
106
|
+
onChange={(e) => setNum2(e.target.value)}
|
107
|
+
/>
|
108
|
+
<button onClick={calculateResult}>Calculate</button>
|
109
|
+
<div className="result">
|
110
|
+
Result: <strong>{result}</strong>
|
111
|
+
</div>
|
112
|
+
</div>
|
113
|
+
|
114
|
+
<h2>WASM JSON Parsing</h2>
|
115
|
+
<div className="json-parser">
|
116
|
+
<textarea
|
117
|
+
rows="5"
|
118
|
+
value={jsonInput}
|
119
|
+
onChange={(e) => setJsonInput(e.target.value)}
|
120
|
+
/>
|
121
|
+
<button onClick={parseJsonWithWasm}>Parse JSON</button>
|
122
|
+
{jsonResult && (
|
123
|
+
<pre className="json-result">{jsonResult}</pre>
|
124
|
+
)}
|
125
|
+
</div>
|
126
|
+
|
127
|
+
<h2>Available WASM Functions</h2>
|
128
|
+
<ul className="function-list">
|
129
|
+
{wasm && Object.keys(wasm.functions).map(funcName => (
|
130
|
+
<li key={funcName}>{funcName}</li>
|
131
|
+
))}
|
132
|
+
</ul>
|
133
|
+
</div>
|
134
|
+
</div>
|
135
|
+
);
|
136
|
+
}
|
@@ -0,0 +1,186 @@
|
|
1
|
+
import express from 'express';
|
2
|
+
import path from 'path';
|
3
|
+
import fs from 'fs';
|
4
|
+
import { fileURLToPath } from 'url';
|
5
|
+
import compression from 'compression';
|
6
|
+
import cors from 'cors';
|
7
|
+
import { Server as SocketServer } from 'socket.io';
|
8
|
+
import http from 'http';
|
9
|
+
import dotenv from 'dotenv';
|
10
|
+
|
11
|
+
// Import from frontend-hamroun
|
12
|
+
import {
|
13
|
+
renderToString,
|
14
|
+
loadGoWasmFromFile,
|
15
|
+
initNodeWasm
|
16
|
+
} from 'frontend-hamroun/server';
|
17
|
+
|
18
|
+
// Import components
|
19
|
+
import App from './components/App.js';
|
20
|
+
import { ApiRouter } from './api/index.js';
|
21
|
+
|
22
|
+
// Load environment variables
|
23
|
+
dotenv.config();
|
24
|
+
|
25
|
+
// Get __dirname equivalent in ESM
|
26
|
+
const __filename = fileURLToPath(import.meta.url);
|
27
|
+
const __dirname = path.dirname(__filename);
|
28
|
+
|
29
|
+
// Server configuration
|
30
|
+
const PORT = process.env.PORT || 3000;
|
31
|
+
const PUBLIC_DIR = path.join(__dirname, 'public');
|
32
|
+
const isProd = process.env.NODE_ENV === 'production';
|
33
|
+
|
34
|
+
// Initialize the express app
|
35
|
+
const app = express();
|
36
|
+
const server = http.createServer(app);
|
37
|
+
const io = new SocketServer(server);
|
38
|
+
|
39
|
+
// WASM state
|
40
|
+
let wasmInstance = null;
|
41
|
+
|
42
|
+
// Middleware
|
43
|
+
app.use(compression()); // Compress responses
|
44
|
+
app.use(express.json()); // Parse JSON request bodies
|
45
|
+
app.use(express.urlencoded({ extended: true })); // Parse URL-encoded request bodies
|
46
|
+
app.use(cors()); // Enable CORS
|
47
|
+
|
48
|
+
// Serve static files
|
49
|
+
app.use(express.static(PUBLIC_DIR));
|
50
|
+
|
51
|
+
// Setup API routes
|
52
|
+
app.use('/api', ApiRouter);
|
53
|
+
|
54
|
+
// Setup Socket.IO
|
55
|
+
io.on('connection', (socket) => {
|
56
|
+
console.log('New client connected');
|
57
|
+
|
58
|
+
socket.on('message', (data) => {
|
59
|
+
console.log('Message received:', data);
|
60
|
+
io.emit('message', data); // Broadcast to all clients
|
61
|
+
});
|
62
|
+
|
63
|
+
socket.on('disconnect', () => {
|
64
|
+
console.log('Client disconnected');
|
65
|
+
});
|
66
|
+
});
|
67
|
+
|
68
|
+
// Initialize WASM
|
69
|
+
async function initWasm() {
|
70
|
+
try {
|
71
|
+
// Initialize Node WASM environment
|
72
|
+
await initNodeWasm();
|
73
|
+
|
74
|
+
// Check if WASM file exists
|
75
|
+
const wasmPath = path.join(__dirname, 'public/wasm/example.wasm');
|
76
|
+
if (fs.existsSync(wasmPath)) {
|
77
|
+
// Load WASM module
|
78
|
+
wasmInstance = await loadGoWasmFromFile(wasmPath, {
|
79
|
+
debug: false,
|
80
|
+
goWasmPath: path.join(__dirname, 'public/wasm/wasm_exec.js')
|
81
|
+
});
|
82
|
+
|
83
|
+
console.log('Server WASM module loaded successfully');
|
84
|
+
} else {
|
85
|
+
console.log('WASM file not found, skipping WASM initialization');
|
86
|
+
}
|
87
|
+
} catch (error) {
|
88
|
+
console.error('Failed to initialize WASM:', error);
|
89
|
+
}
|
90
|
+
}
|
91
|
+
|
92
|
+
// Handle all other requests with SSR
|
93
|
+
app.get('*', async (req, res) => {
|
94
|
+
try {
|
95
|
+
// Prepare context for rendering
|
96
|
+
const context = {
|
97
|
+
url: req.url,
|
98
|
+
wasm: wasmInstance,
|
99
|
+
initialData: {
|
100
|
+
// Add any data needed for initial render
|
101
|
+
path: req.path,
|
102
|
+
query: req.query,
|
103
|
+
timestamp: new Date().toISOString()
|
104
|
+
}
|
105
|
+
};
|
106
|
+
|
107
|
+
// Render app to string
|
108
|
+
const appHtml = renderToString(<App context={context} />);
|
109
|
+
|
110
|
+
// Format the initial data as JSON for client hydration
|
111
|
+
const initialDataScript = `
|
112
|
+
<script id="__INITIAL_DATA__" type="application/json">
|
113
|
+
${JSON.stringify(context.initialData).replace(/</g, '\\u003c')}
|
114
|
+
</script>
|
115
|
+
`;
|
116
|
+
|
117
|
+
// Generate full HTML
|
118
|
+
const html = `
|
119
|
+
<!DOCTYPE html>
|
120
|
+
<html lang="en">
|
121
|
+
<head>
|
122
|
+
<meta charset="UTF-8">
|
123
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
124
|
+
<title>Complete Baraqex App</title>
|
125
|
+
<link rel="stylesheet" href="/styles.css">
|
126
|
+
</head>
|
127
|
+
<body>
|
128
|
+
<div id="app" data-ssr>${appHtml}</div>
|
129
|
+
${initialDataScript}
|
130
|
+
<script type="module" src="/client.js"></script>
|
131
|
+
</body>
|
132
|
+
</html>
|
133
|
+
`;
|
134
|
+
|
135
|
+
res.send(html);
|
136
|
+
} catch (error) {
|
137
|
+
console.error('Error rendering page:', error);
|
138
|
+
|
139
|
+
// Send error page
|
140
|
+
res.status(500).send(`
|
141
|
+
<!DOCTYPE html>
|
142
|
+
<html>
|
143
|
+
<head>
|
144
|
+
<title>Server Error</title>
|
145
|
+
<style>
|
146
|
+
body { font-family: system-ui, sans-serif; padding: 2rem; line-height: 1.5; }
|
147
|
+
.error { background: #fff0f0; border: 1px solid #ffcaca; border-radius: 4px; padding: 1rem; }
|
148
|
+
pre { background: #f5f5f5; padding: 1rem; overflow: auto; border-radius: 4px; }
|
149
|
+
</style>
|
150
|
+
</head>
|
151
|
+
<body>
|
152
|
+
<h1>Server Error</h1>
|
153
|
+
<div class="error">
|
154
|
+
<p>${error.message}</p>
|
155
|
+
${isProd ? '' : `<pre>${error.stack}</pre>`}
|
156
|
+
</div>
|
157
|
+
</body>
|
158
|
+
</html>
|
159
|
+
`);
|
160
|
+
}
|
161
|
+
});
|
162
|
+
|
163
|
+
// Start the server
|
164
|
+
async function startServer() {
|
165
|
+
// Initialize WASM
|
166
|
+
await initWasm();
|
167
|
+
|
168
|
+
// Start listening
|
169
|
+
server.listen(PORT, () => {
|
170
|
+
console.log(`
|
171
|
+
┌─────────────────────────────────────────────────────┐
|
172
|
+
│ │
|
173
|
+
│ Complete Baraqex App Server running! │
|
174
|
+
│ │
|
175
|
+
│ - Local: http://localhost:${PORT} │
|
176
|
+
│ - API: http://localhost:${PORT}/api │
|
177
|
+
│ │
|
178
|
+
│ Mode: ${isProd ? 'production' : 'development'} │
|
179
|
+
│ │
|
180
|
+
└─────────────────────────────────────────────────────┘
|
181
|
+
`);
|
182
|
+
});
|
183
|
+
}
|
184
|
+
|
185
|
+
// Run the server
|
186
|
+
startServer().catch(console.error);
|
@@ -0,0 +1,16 @@
|
|
1
|
+
@echo off
|
2
|
+
echo Building Go WASM module...
|
3
|
+
|
4
|
+
set GOOS=js
|
5
|
+
set GOARCH=wasm
|
6
|
+
go build -o example.wasm example.go
|
7
|
+
|
8
|
+
if %ERRORLEVEL% NEQ 0 (
|
9
|
+
echo Error: Failed to build Go WASM module
|
10
|
+
exit /b 1
|
11
|
+
)
|
12
|
+
|
13
|
+
for /f "tokens=*" %%g in ('go env GOROOT') do (set GOROOT=%%g)
|
14
|
+
copy "%GOROOT%\misc\wasm\wasm_exec.js" .
|
15
|
+
|
16
|
+
echo Build complete!
|
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
echo "Building Go WASM module..."
|
3
|
+
|
4
|
+
# Set environment variables for Go to compile to WASM
|
5
|
+
GOOS=js GOARCH=wasm go build -o example.wasm example.go
|
6
|
+
|
7
|
+
if [ $? -ne 0 ]; then
|
8
|
+
echo "Error: Failed to build Go WASM module"
|
9
|
+
exit 1
|
10
|
+
fi
|
11
|
+
|
12
|
+
# Get Go WASM exec runtime
|
13
|
+
GOROOT=$(go env GOROOT)
|
14
|
+
cp "$GOROOT/misc/wasm/wasm_exec.js" .
|
15
|
+
|
16
|
+
echo "Build completed!"
|