baraqex 2.0.6 → 2.0.8

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/wasm.d.ts CHANGED
@@ -15,7 +15,7 @@ export interface GoWasmInstance {
15
15
  functions: Record<string, Function>;
16
16
  }
17
17
  /**
18
- * Load Go WASM module in the browser (like your working frontend code)
18
+ * Load Go WASM module in the browser (cached per URL).
19
19
  */
20
20
  export declare function loadGoWasm(wasmUrl: string, options?: GoWasmOptions): Promise<GoWasmInstance>;
21
21
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"wasm.d.ts","sourceRoot":"","sources":["../src/wasm.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,GAAG,CAAC;IACnB,MAAM,CAAC,EAAE,CAAC,QAAQ,EAAE,cAAc,KAAK,IAAI,CAAC;CAC7C;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,WAAW,CAAC,QAAQ,CAAC;IAC/B,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC;IAC3B,OAAO,EAAE,WAAW,CAAC,OAAO,CAAC;IAC7B,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;CACrC;AAED;;GAEG;AACH,wBAAsB,UAAU,CAC9B,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,aAAkB,GAC1B,OAAO,CAAC,cAAc,CAAC,CAwEzB;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,GAAG,CAWtE;AAED;;GAEG;AACH,wBAAgB,WAAW,IAAI,OAAO,CASrC;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,EAAE,CAQ3C;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB;;;;;EAarE;AAGD,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,EAAE,EAAE,UAAU;YACZ,YAAY,EAAE,GAAG,CAAC;YAClB,GAAG,EAAE,CAAC,QAAQ,EAAE,WAAW,CAAC,QAAQ,KAAK,IAAI,CAAC;SAC/C,CAAC;QACF,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;KACpB;CACF"}
1
+ {"version":3,"file":"wasm.d.ts","sourceRoot":"","sources":["../src/wasm.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,GAAG,CAAC;IACnB,MAAM,CAAC,EAAE,CAAC,QAAQ,EAAE,cAAc,KAAK,IAAI,CAAC;CAC7C;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,WAAW,CAAC,QAAQ,CAAC;IAC/B,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC;IAC3B,OAAO,EAAE,WAAW,CAAC,OAAO,CAAC;IAC7B,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;CACrC;AAQD;;GAEG;AACH,wBAAgB,UAAU,CACxB,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,aAAkB,GAC1B,OAAO,CAAC,cAAc,CAAC,CAiBzB;AA2ED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,GAAG,CAWtE;AAED;;GAEG;AACH,wBAAgB,WAAW,IAAI,OAAO,CASrC;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,EAAE,CAQ3C;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB;;;;;EAarE;AAGD,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,EAAE,EAAE,UAAU;YACZ,YAAY,EAAE,GAAG,CAAC;YAClB,GAAG,EAAE,CAAC,QAAQ,EAAE,WAAW,CAAC,QAAQ,KAAK,IAAI,CAAC;SAC/C,CAAC;QACF,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;KACpB;CACF"}
package/dist/wasm.js CHANGED
@@ -1,8 +1,20 @@
1
1
  // src/wasm.ts
2
- async function loadGoWasm(wasmUrl, options = {}) {
2
+ var wasmCache = /* @__PURE__ */ new Map();
3
+ function loadGoWasm(wasmUrl, options = {}) {
3
4
  if (typeof window === "undefined") {
4
5
  throw new Error("loadGoWasm() is for browser use only. Use loadGoWasmFromFile() in Node.js.");
5
6
  }
7
+ const cached = wasmCache.get(wasmUrl);
8
+ if (cached)
9
+ return cached;
10
+ const request = loadGoWasmInternal(wasmUrl, options).catch((error) => {
11
+ wasmCache.delete(wasmUrl);
12
+ throw error;
13
+ });
14
+ wasmCache.set(wasmUrl, request);
15
+ return request;
16
+ }
17
+ async function loadGoWasmInternal(wasmUrl, options = {}) {
6
18
  try {
7
19
  if (!window.Go) {
8
20
  throw new Error("Go WASM runtime not available. Make sure wasm_exec.js is loaded.");
package/dist/wasm.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/wasm.ts"],
4
- "sourcesContent": ["/**\r\n * WebAssembly integration for Frontend Hamroun\r\n * Works in both browser and Node.js environments\r\n */\r\n\r\nexport interface GoWasmOptions {\r\n debug?: boolean;\r\n goWasmPath?: string;\r\n importObject?: any;\r\n onLoad?: (instance: GoWasmInstance) => void;\r\n}\r\n\r\nexport interface GoWasmInstance {\r\n instance: WebAssembly.Instance;\r\n module: WebAssembly.Module;\r\n exports: WebAssembly.Exports;\r\n functions: Record<string, Function>;\r\n}\r\n\r\n/**\r\n * Load Go WASM module in the browser (like your working frontend code)\r\n */\r\nexport async function loadGoWasm(\r\n wasmUrl: string,\r\n options: GoWasmOptions = {}\r\n): Promise<GoWasmInstance> {\r\n if (typeof window === 'undefined') {\r\n throw new Error('loadGoWasm() is for browser use only. Use loadGoWasmFromFile() in Node.js.');\r\n }\r\n\r\n try {\r\n // Check if Go WASM runtime is available (like your frontend code)\r\n if (!window.Go) {\r\n throw new Error('Go WASM runtime not available. Make sure wasm_exec.js is loaded.');\r\n }\r\n\r\n if (options.debug) {\r\n console.log('[WASM] Loading WASM from:', wasmUrl);\r\n }\r\n\r\n // Fetch the WASM file (exactly like your frontend code)\r\n const response = await fetch(wasmUrl);\r\n \r\n if (!response.ok) {\r\n throw new Error(`Failed to fetch WASM file: ${response.status}`);\r\n }\r\n\r\n const wasmBytes = await response.arrayBuffer();\r\n \r\n // Initialize Go runtime (exactly like your frontend code)\r\n const go = new window.Go();\r\n const wasmModule = await WebAssembly.instantiate(wasmBytes, go.importObject);\r\n \r\n // Run the Go program (exactly like your frontend code)\r\n go.run(wasmModule.instance);\r\n \r\n // Wait a bit for Go functions to be registered (like your frontend code)\r\n await new Promise(resolve => setTimeout(resolve, 100));\r\n \r\n if (options.debug) {\r\n console.log('[WASM] Go program started, checking for registered functions...');\r\n }\r\n\r\n // Extract exported functions from global scope (like your frontend code)\r\n const functions: Record<string, Function> = {};\r\n \r\n // Look for Go functions in global scope\r\n for (const key in window) {\r\n if (typeof window[key] === 'function' && key.startsWith('go')) {\r\n functions[key] = window[key] as Function;\r\n if (options.debug) {\r\n console.log(`[WASM] Found function: ${key}`);\r\n }\r\n }\r\n }\r\n\r\n const wasmInstance: GoWasmInstance = {\r\n instance: wasmModule.instance,\r\n module: wasmModule,\r\n exports: wasmModule.instance.exports,\r\n functions\r\n };\r\n\r\n if (options.onLoad) {\r\n options.onLoad(wasmInstance);\r\n }\r\n\r\n if (options.debug) {\r\n console.log(`[WASM] Module loaded successfully with ${Object.keys(functions).length} functions`);\r\n }\r\n\r\n return wasmInstance;\r\n\r\n } catch (error) {\r\n console.error('[WASM] Error loading Go WASM module:', error);\r\n throw error;\r\n }\r\n}\r\n\r\n/**\r\n * Call a Go WASM function (like your frontend code's callWasmFunction)\r\n */\r\nexport function callWasmFunction(funcName: string, ...args: any[]): any {\r\n if (typeof window === 'undefined') {\r\n throw new Error('callWasmFunction() is for browser use only.');\r\n }\r\n\r\n const func = (window as any)[funcName];\r\n if (typeof func !== 'function') {\r\n throw new Error(`Function ${funcName} not found. Make sure the WASM module is loaded.`);\r\n }\r\n \r\n return func(...args);\r\n}\r\n\r\n/**\r\n * Check if Go WASM is ready (like your frontend code's wasmReady state)\r\n */\r\nexport function isWasmReady(): boolean {\r\n if (typeof window === 'undefined') {\r\n return false;\r\n }\r\n\r\n // Check if Go runtime is available and at least one Go function exists\r\n return !!(window.Go && Object.keys(window).some(key => \r\n key.startsWith('go') && typeof window[key] === 'function'\r\n ));\r\n}\r\n\r\n/**\r\n * Get all available Go WASM functions\r\n */\r\nexport function getWasmFunctions(): string[] {\r\n if (typeof window === 'undefined') {\r\n return [];\r\n }\r\n\r\n return Object.keys(window).filter(key => \r\n key.startsWith('go') && typeof window[key] === 'function'\r\n );\r\n}\r\n\r\n/**\r\n * Hook for React components (like your frontend code's useEffect pattern)\r\n */\r\nexport function useGoWasm(wasmUrl: string, options: GoWasmOptions = {}) {\r\n if (typeof window === 'undefined') {\r\n throw new Error('useGoWasm() is for browser use only.');\r\n }\r\n\r\n // This would need to be implemented as a React hook in frontend-hamroun\r\n // For now, return the basic functionality\r\n return {\r\n loadWasm: () => loadGoWasm(wasmUrl, options),\r\n callFunction: callWasmFunction,\r\n isReady: isWasmReady,\r\n getFunctions: getWasmFunctions\r\n };\r\n}\r\n\r\n// Browser-specific type declarations\r\ndeclare global {\r\n interface Window {\r\n Go: new () => {\r\n importObject: any;\r\n run: (instance: WebAssembly.Instance) => void;\r\n };\r\n [key: string]: any;\r\n }\r\n}\r\n"],
5
- "mappings": ";AAsBA,eAAsB,WACpB,SACA,UAAyB,CAAC,GACD;AACzB,MAAI,OAAO,WAAW,aAAa;AACjC,UAAM,IAAI,MAAM,4EAA4E;AAAA,EAC9F;AAEA,MAAI;AAEF,QAAI,CAAC,OAAO,IAAI;AACd,YAAM,IAAI,MAAM,kEAAkE;AAAA,IACpF;AAEA,QAAI,QAAQ,OAAO;AACjB,cAAQ,IAAI,6BAA6B,OAAO;AAAA,IAClD;AAGA,UAAM,WAAW,MAAM,MAAM,OAAO;AAEpC,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,IAAI,MAAM,8BAA8B,SAAS,MAAM,EAAE;AAAA,IACjE;AAEA,UAAM,YAAY,MAAM,SAAS,YAAY;AAG7C,UAAM,KAAK,IAAI,OAAO,GAAG;AACzB,UAAM,aAAa,MAAM,YAAY,YAAY,WAAW,GAAG,YAAY;AAG3E,OAAG,IAAI,WAAW,QAAQ;AAG1B,UAAM,IAAI,QAAQ,aAAW,WAAW,SAAS,GAAG,CAAC;AAErD,QAAI,QAAQ,OAAO;AACjB,cAAQ,IAAI,iEAAiE;AAAA,IAC/E;AAGA,UAAM,YAAsC,CAAC;AAG7C,eAAW,OAAO,QAAQ;AACxB,UAAI,OAAO,OAAO,GAAG,MAAM,cAAc,IAAI,WAAW,IAAI,GAAG;AAC7D,kBAAU,GAAG,IAAI,OAAO,GAAG;AAC3B,YAAI,QAAQ,OAAO;AACjB,kBAAQ,IAAI,0BAA0B,GAAG,EAAE;AAAA,QAC7C;AAAA,MACF;AAAA,IACF;AAEA,UAAM,eAA+B;AAAA,MACnC,UAAU,WAAW;AAAA,MACrB,QAAQ;AAAA,MACR,SAAS,WAAW,SAAS;AAAA,MAC7B;AAAA,IACF;AAEA,QAAI,QAAQ,QAAQ;AAClB,cAAQ,OAAO,YAAY;AAAA,IAC7B;AAEA,QAAI,QAAQ,OAAO;AACjB,cAAQ,IAAI,0CAA0C,OAAO,KAAK,SAAS,EAAE,MAAM,YAAY;AAAA,IACjG;AAEA,WAAO;AAAA,EAET,SAAS,OAAO;AACd,YAAQ,MAAM,wCAAwC,KAAK;AAC3D,UAAM;AAAA,EACR;AACF;AAKO,SAAS,iBAAiB,aAAqB,MAAkB;AACtE,MAAI,OAAO,WAAW,aAAa;AACjC,UAAM,IAAI,MAAM,6CAA6C;AAAA,EAC/D;AAEA,QAAM,OAAQ,OAAe,QAAQ;AACrC,MAAI,OAAO,SAAS,YAAY;AAC9B,UAAM,IAAI,MAAM,YAAY,QAAQ,kDAAkD;AAAA,EACxF;AAEA,SAAO,KAAK,GAAG,IAAI;AACrB;AAKO,SAAS,cAAuB;AACrC,MAAI,OAAO,WAAW,aAAa;AACjC,WAAO;AAAA,EACT;AAGA,SAAO,CAAC,EAAE,OAAO,MAAM,OAAO,KAAK,MAAM,EAAE;AAAA,IAAK,SAC9C,IAAI,WAAW,IAAI,KAAK,OAAO,OAAO,GAAG,MAAM;AAAA,EACjD;AACF;AAKO,SAAS,mBAA6B;AAC3C,MAAI,OAAO,WAAW,aAAa;AACjC,WAAO,CAAC;AAAA,EACV;AAEA,SAAO,OAAO,KAAK,MAAM,EAAE;AAAA,IAAO,SAChC,IAAI,WAAW,IAAI,KAAK,OAAO,OAAO,GAAG,MAAM;AAAA,EACjD;AACF;AAKO,SAAS,UAAU,SAAiB,UAAyB,CAAC,GAAG;AACtE,MAAI,OAAO,WAAW,aAAa;AACjC,UAAM,IAAI,MAAM,sCAAsC;AAAA,EACxD;AAIA,SAAO;AAAA,IACL,UAAU,MAAM,WAAW,SAAS,OAAO;AAAA,IAC3C,cAAc;AAAA,IACd,SAAS;AAAA,IACT,cAAc;AAAA,EAChB;AACF;",
4
+ "sourcesContent": ["/**\r\n * WebAssembly integration for Frontend Hamroun\r\n * Works in both browser and Node.js environments\r\n */\r\n\r\nexport interface GoWasmOptions {\r\n debug?: boolean;\r\n goWasmPath?: string;\r\n importObject?: any;\r\n onLoad?: (instance: GoWasmInstance) => void;\r\n}\r\n\r\nexport interface GoWasmInstance {\r\n instance: WebAssembly.Instance;\r\n module: WebAssembly.Module;\r\n exports: WebAssembly.Exports;\r\n functions: Record<string, Function>;\r\n}\r\n\r\n/**\r\n * Cache loaded WASM instances per URL so visiting a route (or re-mounting a\r\n * component) doesn't re-fetch, re-compile, or re-run the module every time.\r\n */\r\nconst wasmCache = new Map<string, Promise<GoWasmInstance>>();\r\n\r\n/**\r\n * Load Go WASM module in the browser (cached per URL).\r\n */\r\nexport function loadGoWasm(\r\n wasmUrl: string,\r\n options: GoWasmOptions = {}\r\n): Promise<GoWasmInstance> {\r\n if (typeof window === 'undefined') {\r\n throw new Error('loadGoWasm() is for browser use only. Use loadGoWasmFromFile() in Node.js.');\r\n }\r\n\r\n const cached = wasmCache.get(wasmUrl);\r\n if (cached) return cached;\r\n\r\n const request = loadGoWasmInternal(wasmUrl, options)\r\n .catch((error) => {\r\n // Don't cache failures \u2014 allow a retry next time the module is requested.\r\n wasmCache.delete(wasmUrl);\r\n throw error;\r\n });\r\n\r\n wasmCache.set(wasmUrl, request);\r\n return request;\r\n}\r\n\r\nasync function loadGoWasmInternal(\r\n wasmUrl: string,\r\n options: GoWasmOptions = {}\r\n): Promise<GoWasmInstance> {\r\n try {\r\n // Check if Go WASM runtime is available (like your frontend code)\r\n if (!window.Go) {\r\n throw new Error('Go WASM runtime not available. Make sure wasm_exec.js is loaded.');\r\n }\r\n\r\n if (options.debug) {\r\n console.log('[WASM] Loading WASM from:', wasmUrl);\r\n }\r\n\r\n // Fetch the WASM file (exactly like your frontend code)\r\n const response = await fetch(wasmUrl);\r\n \r\n if (!response.ok) {\r\n throw new Error(`Failed to fetch WASM file: ${response.status}`);\r\n }\r\n\r\n const wasmBytes = await response.arrayBuffer();\r\n \r\n // Initialize Go runtime (exactly like your frontend code)\r\n const go = new window.Go();\r\n const wasmModule = await WebAssembly.instantiate(wasmBytes, go.importObject);\r\n \r\n // Run the Go program (exactly like your frontend code)\r\n go.run(wasmModule.instance);\r\n \r\n // Wait a bit for Go functions to be registered (like your frontend code)\r\n await new Promise(resolve => setTimeout(resolve, 100));\r\n \r\n if (options.debug) {\r\n console.log('[WASM] Go program started, checking for registered functions...');\r\n }\r\n\r\n // Extract exported functions from global scope (like your frontend code)\r\n const functions: Record<string, Function> = {};\r\n \r\n // Look for Go functions in global scope\r\n for (const key in window) {\r\n if (typeof window[key] === 'function' && key.startsWith('go')) {\r\n functions[key] = window[key] as Function;\r\n if (options.debug) {\r\n console.log(`[WASM] Found function: ${key}`);\r\n }\r\n }\r\n }\r\n\r\n const wasmInstance: GoWasmInstance = {\r\n instance: wasmModule.instance,\r\n module: wasmModule,\r\n exports: wasmModule.instance.exports,\r\n functions\r\n };\r\n\r\n if (options.onLoad) {\r\n options.onLoad(wasmInstance);\r\n }\r\n\r\n if (options.debug) {\r\n console.log(`[WASM] Module loaded successfully with ${Object.keys(functions).length} functions`);\r\n }\r\n\r\n return wasmInstance;\r\n\r\n } catch (error) {\r\n console.error('[WASM] Error loading Go WASM module:', error);\r\n throw error;\r\n }\r\n}\r\n\r\n/**\r\n * Call a Go WASM function (like your frontend code's callWasmFunction)\r\n */\r\nexport function callWasmFunction(funcName: string, ...args: any[]): any {\r\n if (typeof window === 'undefined') {\r\n throw new Error('callWasmFunction() is for browser use only.');\r\n }\r\n\r\n const func = (window as any)[funcName];\r\n if (typeof func !== 'function') {\r\n throw new Error(`Function ${funcName} not found. Make sure the WASM module is loaded.`);\r\n }\r\n \r\n return func(...args);\r\n}\r\n\r\n/**\r\n * Check if Go WASM is ready (like your frontend code's wasmReady state)\r\n */\r\nexport function isWasmReady(): boolean {\r\n if (typeof window === 'undefined') {\r\n return false;\r\n }\r\n\r\n // Check if Go runtime is available and at least one Go function exists\r\n return !!(window.Go && Object.keys(window).some(key => \r\n key.startsWith('go') && typeof window[key] === 'function'\r\n ));\r\n}\r\n\r\n/**\r\n * Get all available Go WASM functions\r\n */\r\nexport function getWasmFunctions(): string[] {\r\n if (typeof window === 'undefined') {\r\n return [];\r\n }\r\n\r\n return Object.keys(window).filter(key => \r\n key.startsWith('go') && typeof window[key] === 'function'\r\n );\r\n}\r\n\r\n/**\r\n * Hook for React components (like your frontend code's useEffect pattern)\r\n */\r\nexport function useGoWasm(wasmUrl: string, options: GoWasmOptions = {}) {\r\n if (typeof window === 'undefined') {\r\n throw new Error('useGoWasm() is for browser use only.');\r\n }\r\n\r\n // This would need to be implemented as a React hook in frontend-hamroun\r\n // For now, return the basic functionality\r\n return {\r\n loadWasm: () => loadGoWasm(wasmUrl, options),\r\n callFunction: callWasmFunction,\r\n isReady: isWasmReady,\r\n getFunctions: getWasmFunctions\r\n };\r\n}\r\n\r\n// Browser-specific type declarations\r\ndeclare global {\r\n interface Window {\r\n Go: new () => {\r\n importObject: any;\r\n run: (instance: WebAssembly.Instance) => void;\r\n };\r\n [key: string]: any;\r\n }\r\n}\r\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "baraqex",
3
- "version": "2.0.6",
3
+ "version": "2.0.8",
4
4
  "description": "A full-stack WebAssembly framework for building fast, modern web applications.",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",
@@ -43,9 +43,9 @@ function buildWasm() {
43
43
  execSync('go mod init wasm-example', { cwd: goDir, stdio: 'inherit' });
44
44
  }
45
45
 
46
- // Compile with the js/wasm target
46
+ // Compile with the js/wasm target; -s -w strips debug info to shrink the module
47
47
  execSync(
48
- `go build -o "${wasmFile}" main.go`,
48
+ 'go build -ldflags="-s -w" -o "' + wasmFile + '" main.go',
49
49
  {
50
50
  cwd: goDir,
51
51
  stdio: 'inherit',
@@ -104,7 +104,7 @@ async function buildServer() {
104
104
  target: ['node18'],
105
105
  format: 'esm',
106
106
  outfile: path.join(outdir, 'server.js'),
107
- external: ['express', 'cors', 'compression', 'socket.io', 'dotenv'],
107
+ external: ['express', 'cors', 'compression', 'socket.io', 'dotenv', 'postcss', 'tailwindcss', 'autoprefixer', 'chokidar'],
108
108
  plugins: [
109
109
  {
110
110
  name: 'external-all',
@@ -114,7 +114,8 @@ async function buildServer() {
114
114
  }
115
115
  ],
116
116
  define: { 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development') },
117
- sourcemap: false
117
+ sourcemap: false,
118
+ minify: process.env.NODE_ENV === 'production'
118
119
  });
119
120
  console.log('✅ Server build complete');
120
121
  }
@@ -8,7 +8,7 @@
8
8
  "start": "node dist/server.js",
9
9
  "prod": "npm run build && npm run start",
10
10
  "dev": "tsx server.ts",
11
- "build": "node build.mjs",
11
+ "build": "cross-env NODE_ENV=production node build.mjs",
12
12
  "build:wasm": "node build-wasm.js",
13
13
  "build:all": "node build-wasm.js && node build.mjs"
14
14
  },
@@ -28,7 +28,17 @@ const io = new SocketServer(httpServer, {
28
28
 
29
29
  app.use(express.json());
30
30
  app.use(express.urlencoded({ extended: true }));
31
- app.use(compression());
31
+ app.use(compression({
32
+ filter: (req, res) => {
33
+ const type = res.getHeader('Content-Type');
34
+ if (type === undefined) return true;
35
+ // Compress text-like responses plus binary assets that gzip well (wasm, svg, fonts)
36
+ if (/^(text\/|application\/(json|javascript|xml|wasm)|image\/svg|font\/)/i.test(String(type))) {
37
+ return true;
38
+ }
39
+ return compression.filter(req, res);
40
+ }
41
+ }));
32
42
  app.use(cors());
33
43
 
34
44
  // ---------------------------------------------------------------------------
@@ -78,9 +88,15 @@ app.get('/api/posts', (req: Request, res: Response) => {
78
88
  // ---------------------------------------------------------------------------
79
89
  // Static assets: built client bundle + public (incl. WASM output)
80
90
  // ---------------------------------------------------------------------------
81
- app.use('/build', express.static(path.join(__dirname, 'build')));
82
- app.use('/wasm', express.static(path.join(__dirname, 'public', 'wasm')));
83
- app.use(express.static(path.join(__dirname, 'public')));
91
+ // Dev must never cache rebuilt bundles; prod can cache them briefly. WASM files
92
+ // are rebuilt via `npm run build:wasm` and are safe to cache for a long time.
93
+ const buildCache = isDev
94
+ ? { setHeaders: (res: Response) => res.setHeader('Cache-Control', 'no-store') }
95
+ : { maxAge: '1h' };
96
+ const wasmCache = { maxAge: '1y', immutable: true };
97
+ app.use('/build', express.static(path.join(__dirname, 'build'), buildCache));
98
+ app.use('/wasm', express.static(path.join(__dirname, 'public', 'wasm'), wasmCache));
99
+ app.use(express.static(path.join(__dirname, 'public'), buildCache));
84
100
 
85
101
  // ---------------------------------------------------------------------------
86
102
  // Dev mode: esbuild context (bundles src + rebuilds on change)
@@ -135,23 +151,18 @@ async function buildStyles() {
135
151
  console.log('✅ styles.css built');
136
152
  }
137
153
 
138
- // Build the Tailwind stylesheet used by the SSR-rendered page (both modes)
139
- await buildStyles();
140
-
141
- // In dev, bundle the client with esbuild (rebuilds on change via the watcher below)
142
- if (isDev) {
143
- await setupEsbuild();
144
- }
154
+ // Build the Tailwind stylesheet and (in dev) rebuild it on change. In prod the
155
+ // file is already written by `npm run build`, so only (re)build when missing.
156
+ await Promise.all([
157
+ isDev || !existsSync(path.join(__dirname, 'build', 'styles.css')) ? buildStyles() : Promise.resolve(),
158
+ isDev ? setupEsbuild() : Promise.resolve()
159
+ ]);
145
160
 
146
- // Only load the Go runtime scripts when the WASM module has been built
147
- // (`npm run build:wasm` requires Go). Off by default so dev works without Go.
161
+ // Only used when the Go WASM module has been built (`npm run build:wasm`,
162
+ // requires Go). Off by default so dev works without Go.
148
163
  const hasWasm = existsSync(path.join(__dirname, 'public', 'wasm', 'example.wasm'))
149
164
  && existsSync(path.join(__dirname, 'public', 'wasm', 'wasm_exec.js'));
150
165
 
151
- const wasmScripts = hasWasm
152
- ? '<script src="/wasm/wasm_exec.js"></script>'
153
- : '<script>console.warn("Go WASM not built — run `npm run build:wasm` (requires Go)");</script>';
154
-
155
166
  // ---------------------------------------------------------------------------
156
167
  // SSR: render the App on the server, then hydrate on the client
157
168
  // ---------------------------------------------------------------------------
@@ -166,11 +177,20 @@ app.get('*', async (req: Request, res: Response, next: NextFunction) => {
166
177
  route,
167
178
  serverTime: new Date().toISOString(),
168
179
  serverRendered: true,
169
- users: store.users
180
+ users: store.users,
181
+ hasWasm
170
182
  };
171
183
 
172
184
  const content = await renderToString(jsx(App, { route, initialState }));
173
185
 
186
+ // Load the Go runtime only on the /wasm page — Home/About never pay for it.
187
+ // Direct visits get it server-side; SPA navigation loads it dynamically.
188
+ const wasmRuntimeScript = req.path.startsWith('/wasm')
189
+ ? (hasWasm
190
+ ? '<script src="/wasm/wasm_exec.js" defer></script>'
191
+ : '<script>console.warn("Go WASM not built — run `npm run build:wasm` (requires Go)");</script>')
192
+ : '';
193
+
174
194
  const html = `<!DOCTYPE html>
175
195
  <html lang="en">
176
196
  <head>
@@ -183,8 +203,8 @@ app.get('*', async (req: Request, res: Response, next: NextFunction) => {
183
203
  </head>
184
204
  <body>
185
205
  <div id="root">${content}</div>
186
- ${wasmScripts}
187
- ${isDev ? '<script src="/socket.io/socket.io.js"></script>' : ''}
206
+ ${wasmRuntimeScript}
207
+ ${isDev ? '<script src="/socket.io/socket.io.js" defer></script>' : ''}
188
208
  <script src="/build/main.js" type="module"></script>
189
209
  </body>
190
210
  </html>`;
@@ -215,6 +235,9 @@ if (isDev) {
215
235
  watcher.on('change', async (changedPath) => {
216
236
  console.log(`[Watcher] Changed: ${changedPath}`);
217
237
  try {
238
+ if (changedPath.endsWith('styles.css')) {
239
+ await buildStyles();
240
+ }
218
241
  await esbuildContext?.rebuild();
219
242
  io.emit('reload');
220
243
  console.log('[Watcher] Rebuild + reload sent');
@@ -18,11 +18,14 @@ function parseRoute(pathname: string): string {
18
18
  export function App({ route, initialState }: AppProps) {
19
19
  const [current, setCurrent] = useState<string>(parseRoute(route || (typeof window !== 'undefined' ? window.location.pathname : '/')));
20
20
 
21
- const navigate = (target: string) => {
21
+ const navigate = (e: any, target: string, href: string) => {
22
+ if (e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) {
23
+ return; // let the browser handle new-tab / new-window navigation
24
+ }
25
+ e.preventDefault();
22
26
  setCurrent(target);
23
27
  if (typeof window !== 'undefined') {
24
- const path = target === 'home' ? '/' : `/${target}`;
25
- window.history.pushState(null, '', path);
28
+ window.history.pushState(null, '', href);
26
29
  }
27
30
  };
28
31
 
@@ -36,22 +39,24 @@ export function App({ route, initialState }: AppProps) {
36
39
  <div className="min-h-screen flex flex-col bg-gray-50">
37
40
  <header className="bg-blue-700 text-white shadow">
38
41
  <div className="max-w-5xl mx-auto px-4 py-4 flex items-center justify-between">
39
- <button onClick={() => navigate('home')} className="text-xl font-bold hover:text-blue-100">
42
+ <a href="/" onClick={(e: any) => navigate(e, 'home', '/')} className="text-xl font-bold hover:text-blue-100">
40
43
  Baraqex Full-Stack
41
- </button>
44
+ </a>
42
45
  <nav>
43
46
  <ul className="flex space-x-6">
44
47
  {navItems.map((item) => (
45
48
  <li key={item.key}>
46
- <button
47
- onClick={() => navigate(item.key)}
49
+ <a
50
+ href={item.href}
51
+ onClick={(e: any) => navigate(e, item.key, item.href)}
52
+ aria-current={current === item.key ? 'page' : undefined}
48
53
  className={
49
54
  'hover:text-blue-200 ' +
50
55
  (current === item.key ? 'underline font-semibold' : '')
51
56
  }
52
57
  >
53
58
  {item.label}
54
- </button>
59
+ </a>
55
60
  </li>
56
61
  ))}
57
62
  </ul>
@@ -62,7 +67,7 @@ export function App({ route, initialState }: AppProps) {
62
67
  <main className="flex-grow max-w-5xl w-full mx-auto px-4 py-8">
63
68
  {current === 'home' && <HomePage initialState={initialState} />}
64
69
  {current === 'about' && <AboutPage />}
65
- {current === 'wasm' && <WasmDemo />}
70
+ {current === 'wasm' && <WasmDemo hasWasm={!!initialState?.hasWasm} />}
66
71
  </main>
67
72
 
68
73
  <footer className="bg-gray-800 text-white">
@@ -1,6 +1,5 @@
1
1
  import { hydrate, jsx } from 'baraqex';
2
2
  import { App } from './App';
3
- import './styles.css';
4
3
 
5
4
  declare global {
6
5
  interface Window {
@@ -1,4 +1,4 @@
1
- import { jsx, useState } from 'baraqex';
1
+ import { jsx, useState, useEffect } from 'baraqex';
2
2
 
3
3
  export interface HomeState {
4
4
  users?: any[];
@@ -6,19 +6,62 @@ export interface HomeState {
6
6
  serverTime?: string;
7
7
  }
8
8
 
9
+ let usersCache: any[] | null = null;
10
+ let usersRequest: Promise<any[]> | null = null;
11
+
12
+ async function fetchUsers(): Promise<any[]> {
13
+ if (usersRequest) return usersRequest;
14
+ usersRequest = fetch('/api/users').then((res) => {
15
+ if (!res.ok) throw new Error(`HTTP ${res.status}`);
16
+ return res.json();
17
+ }).finally(() => {
18
+ usersRequest = null;
19
+ });
20
+ return usersRequest;
21
+ }
22
+
9
23
  export function HomePage({ initialState }: { initialState?: any }) {
10
24
  const initial: HomeState = initialState || { users: [], posts: [] };
11
- const [users, setUsers] = useState<any[]>(initial.users || []);
25
+ const [users, setUsers] = useState<any[]>(usersCache || initial.users || []);
26
+ const [loading, setLoading] = useState(usersCache === null && !initial.users);
12
27
  const [message, setMessage] = useState('');
13
28
 
29
+ useEffect(() => {
30
+ if (usersCache) {
31
+ setUsers(usersCache);
32
+ return;
33
+ }
34
+ let cancelled = false;
35
+ setLoading(true);
36
+ fetchUsers()
37
+ .then((data) => {
38
+ if (cancelled) return;
39
+ usersCache = data;
40
+ setUsers(data);
41
+ setLoading(false);
42
+ })
43
+ .catch((e: any) => {
44
+ if (cancelled) return;
45
+ setLoading(false);
46
+ setMessage('Failed to load data: ' + e.message);
47
+ });
48
+ return () => {
49
+ cancelled = true;
50
+ };
51
+ }, []);
52
+
14
53
  const refresh = async () => {
54
+ setLoading(true);
55
+ setMessage('');
15
56
  try {
16
- const res = await fetch('/api/users');
17
- const data = await res.json();
57
+ usersCache = null;
58
+ const data = await fetchUsers();
18
59
  setUsers(data);
19
60
  setMessage('Data refreshed from /api/users');
20
61
  } catch (e: any) {
21
62
  setMessage('Failed to load data: ' + e.message);
63
+ } finally {
64
+ setLoading(false);
22
65
  }
23
66
  };
24
67
 
@@ -44,24 +87,29 @@ export function HomePage({ initialState }: { initialState?: any }) {
44
87
  <h2 className="text-xl font-semibold text-gray-800">Users (fetched via API)</h2>
45
88
  <button
46
89
  onClick={refresh}
47
- className="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700"
90
+ className="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700 disabled:opacity-40"
91
+ disabled={loading}
48
92
  >
49
- Refresh
93
+ {loading ? 'Loading…' : 'Refresh'}
50
94
  </button>
51
95
  </div>
52
96
  {message && <p className="text-green-700 text-sm mb-3">{message}</p>}
53
- <ul className="divide-y divide-gray-200">
54
- {(users || []).map((user: any) => (
55
- <li key={user.id} className="py-2 flex items-center justify-between">
56
- <span className="font-medium">{user.name}</span>
57
- <span className="text-sm text-gray-500">{user.email}</span>
58
- </li>
59
- ))}
60
- </ul>
61
- {(users || []).length === 0 && (
62
- <p className="text-gray-500 text-sm">No users loaded yet. Click Refresh.</p>
97
+ {loading && users.length === 0 ? (
98
+ <p className="text-gray-500 text-sm">Loading users…</p>
99
+ ) : (
100
+ <ul className="divide-y divide-gray-200">
101
+ {(users || []).map((user: any) => (
102
+ <li key={user.id} className="py-2 flex items-center justify-between">
103
+ <span className="font-medium">{user.name}</span>
104
+ <span className="text-sm text-gray-500">{user.email}</span>
105
+ </li>
106
+ ))}
107
+ </ul>
108
+ )}
109
+ {!loading && (users || []).length === 0 && !message && (
110
+ <p className="text-gray-500 text-sm">No users loaded yet.</p>
63
111
  )}
64
112
  </section>
65
113
  </div>
66
114
  );
67
- }
115
+ }
@@ -1,18 +1,39 @@
1
1
  import { jsx, useState, useEffect, batchUpdates } from 'baraqex';
2
2
  import { loadGoWasm } from 'baraqex';
3
3
 
4
- export function WasmDemo() {
4
+ /**
5
+ * Ensure the Go runtime (wasm_exec.js) is available before loading the module.
6
+ * The SSR page preloads it on direct visits; SPA navigation loads it on demand.
7
+ */
8
+ function ensureWasmRuntime(): Promise<void> {
9
+ const w = window as any;
10
+ if (w.Go) return Promise.resolve();
11
+ return new Promise((resolve, reject) => {
12
+ const script = document.createElement('script');
13
+ script.src = '/wasm/wasm_exec.js';
14
+ script.async = true;
15
+ script.onload = () => resolve();
16
+ script.onerror = () => reject(new Error('/wasm/wasm_exec.js could not be loaded'));
17
+ document.head.appendChild(script);
18
+ });
19
+ }
20
+
21
+ export function WasmDemo({ hasWasm = false }: { hasWasm?: boolean }) {
5
22
  const [ready, setReady] = useState(false);
6
- const [status, setStatus] = useState('Loading Go WASM...');
7
- const [output, setOutput] = useState('');
23
+ const [status, setStatus] = useState(hasWasm ? 'Preparing Go WASM…' : 'Go WASM not built');
24
+ const [output, setOutput] = useState(hasWasm ? '' : 'Run `npm run build:wasm` (requires Go) to enable this page.');
8
25
  const [a, setA] = useState('5');
9
26
  const [b, setB] = useState('7');
10
27
  const [n, setN] = useState('10');
11
28
 
12
29
  useEffect(() => {
30
+ if (!hasWasm) return;
13
31
  let cancelled = false;
14
32
  (async () => {
15
33
  try {
34
+ setStatus('Loading Go WASM module…');
35
+ await ensureWasmRuntime();
36
+ if (cancelled) return;
16
37
  await loadGoWasm('/wasm/example.wasm');
17
38
  if (cancelled) return;
18
39
  batchUpdates(() => {