gowm 1.0.0 → 1.0.1

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/CHANGELOG.md CHANGED
@@ -2,6 +2,19 @@
2
2
 
3
3
  Toutes les modifications notables de ce projet seront documentées dans ce fichier.
4
4
 
5
+ ## [1.0.1] - 2025-05-29
6
+
7
+ ### Corrigé
8
+ - **Compatibilité navigateur** : Résolution du problème avec les modules Node.js `fs` et `path` qui empêchaient l'utilisation dans React/Vue/navigateur
9
+ - Importation conditionnelle des modules Node.js uniquement en environnement serveur
10
+ - Ajout de points d'entrée séparés pour Node.js et navigateur dans `package.json`
11
+ - Création de versions navigateur dédiées (`loader-browser.js`, `bridge-browser.js`, `browser.js`)
12
+
13
+ ### Ajouté
14
+ - Support ES modules pour les environnements navigateur
15
+ - Configuration `package.json` avec champs `browser`, `module`, et `exports`
16
+ - Documentation sur la résolution du problème de compatibilité (`BROWSER_SUPPORT.md`)
17
+
5
18
  ## [1.0.0] - 2025-05-28
6
19
 
7
20
  ### Ajouté
package/package.json CHANGED
@@ -1,9 +1,21 @@
1
1
  {
2
2
  "name": "gowm",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "Go WebAssembly Manager - Simplifiez l'intégration de modules WebAssembly Go dans vos projets JavaScript",
5
5
  "main": "src/index.js",
6
+ "browser": "src/browser.js",
7
+ "module": "src/browser.js",
6
8
  "types": "types/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "node": "./src/index.js",
12
+ "browser": "./src/browser.js",
13
+ "import": "./src/browser.js",
14
+ "require": "./src/index.js"
15
+ },
16
+ "./hooks": "./hooks/useWasm.js",
17
+ "./composables": "./composables/useWasm.js"
18
+ },
7
19
  "files": [
8
20
  "src/",
9
21
  "types/",
@@ -0,0 +1,157 @@
1
+ export default class WasmBridge {
2
+ constructor(wasmModule, options = {}) {
3
+ this.module = wasmModule;
4
+ this.callbacks = new Map();
5
+ this.name = options.name || 'unnamed';
6
+ }
7
+
8
+ // Appel de fonction avec gestion d'erreurs
9
+ call(funcName, ...args) {
10
+ try {
11
+ // Vérifier d'abord dans les exports WASM
12
+ if (this.module.exports && this.module.exports[funcName]) {
13
+ return this.module.exports[funcName](...args);
14
+ }
15
+ // Puis dans les fonctions globales JavaScript (pour Go WASM)
16
+ else if (globalThis[funcName] && typeof globalThis[funcName] === 'function') {
17
+ return globalThis[funcName](...args);
18
+ }
19
+ else {
20
+ throw new Error(`Function ${funcName} not found`);
21
+ }
22
+ } catch (error) {
23
+ console.error(`Error calling ${funcName}:`, error);
24
+ throw error;
25
+ }
26
+ }
27
+
28
+ // Appel asynchrone de fonction
29
+ async callAsync(funcName, ...args) {
30
+ return new Promise((resolve, reject) => {
31
+ try {
32
+ const result = this.call(funcName, ...args);
33
+ if (result instanceof Promise) {
34
+ result.then(resolve).catch(reject);
35
+ } else {
36
+ resolve(result);
37
+ }
38
+ } catch (error) {
39
+ reject(error);
40
+ }
41
+ });
42
+ }
43
+
44
+ // Créer un buffer en mémoire WASM
45
+ createBuffer(data) {
46
+ let buffer;
47
+ let size;
48
+
49
+ if (data instanceof Float64Array) {
50
+ buffer = data;
51
+ size = data.length * 8; // 8 bytes par float64
52
+ } else if (data instanceof Uint8Array) {
53
+ buffer = data;
54
+ size = data.length;
55
+ } else if (typeof data === 'string') {
56
+ const encoder = new TextEncoder();
57
+ buffer = encoder.encode(data);
58
+ size = buffer.length;
59
+ } else {
60
+ throw new Error('Unsupported data type for buffer');
61
+ }
62
+
63
+ // Allouer de la mémoire dans WASM
64
+ const ptr = this.call('malloc', size);
65
+ if (!ptr) {
66
+ throw new Error('Failed to allocate memory in WASM');
67
+ }
68
+
69
+ // Copier les données dans la mémoire WASM
70
+ const wasmMemory = new Uint8Array(this.module.exports.memory.buffer, ptr, size);
71
+ wasmMemory.set(buffer);
72
+
73
+ return {
74
+ ptr,
75
+ buffer: wasmMemory,
76
+ size,
77
+ free: () => {
78
+ try {
79
+ this.call('free', ptr);
80
+ } catch (e) {
81
+ // Ignorer les erreurs de libération
82
+ }
83
+ }
84
+ };
85
+ }
86
+
87
+ // Enregistrer un callback JavaScript appelable depuis WASM
88
+ registerCallback(name, callback) {
89
+ this.callbacks.set(name, callback);
90
+ globalThis[`__gowm_callback_${name}`] = callback;
91
+ }
92
+
93
+ // Désinscrire un callback
94
+ unregisterCallback(name) {
95
+ this.callbacks.delete(name);
96
+ delete globalThis[`__gowm_callback_${name}`];
97
+ }
98
+
99
+ // Obtenir la liste des fonctions disponibles
100
+ getAvailableFunctions() {
101
+ const functions = [];
102
+
103
+ // Fonctions exports WASM
104
+ if (this.module.exports) {
105
+ Object.keys(this.module.exports).forEach(key => {
106
+ if (typeof this.module.exports[key] === 'function') {
107
+ functions.push(key);
108
+ }
109
+ });
110
+ }
111
+
112
+ // Fonctions globales (pour Go WASM)
113
+ Object.keys(globalThis).forEach(key => {
114
+ if (typeof globalThis[key] === 'function' && !key.startsWith('__gowm_')) {
115
+ functions.push(key);
116
+ }
117
+ });
118
+
119
+ return [...new Set(functions)].sort();
120
+ }
121
+
122
+ // Vérifier si une fonction existe
123
+ hasFunction(funcName) {
124
+ return (
125
+ (this.module.exports && typeof this.module.exports[funcName] === 'function') ||
126
+ (typeof globalThis[funcName] === 'function')
127
+ );
128
+ }
129
+
130
+ // Obtenir les statistiques du module
131
+ getStats() {
132
+ return {
133
+ ready: this.module.ready,
134
+ functions: this.getAvailableFunctions(),
135
+ callbacks: Array.from(this.callbacks.keys()),
136
+ memoryUsage: this.module.exports.memory ? this.module.exports.memory.buffer.byteLength : 0,
137
+ name: this.name
138
+ };
139
+ }
140
+
141
+ // Nettoyage des ressources
142
+ cleanup() {
143
+ // Désinscrire tous les callbacks
144
+ for (const name of this.callbacks.keys()) {
145
+ this.unregisterCallback(name);
146
+ }
147
+
148
+ // Arrêter le runtime Go si possible
149
+ if (this.module.go && typeof this.module.go.exit === 'function') {
150
+ try {
151
+ this.module.go.exit(0);
152
+ } catch (e) {
153
+ // Ignorer les erreurs
154
+ }
155
+ }
156
+ }
157
+ }
package/src/browser.js ADDED
@@ -0,0 +1,77 @@
1
+ // Version navigateur de GOWM sans dépendances Node.js
2
+ import WasmLoader from './loader-browser.js';
3
+ import WasmBridge from './bridge-browser.js';
4
+
5
+ class GoWM {
6
+ constructor() {
7
+ this.loader = new WasmLoader();
8
+ this.modules = new Map();
9
+ }
10
+
11
+ async load(wasmPath, options = {}) {
12
+ const module = await this.loader.loadModule(wasmPath, options);
13
+ const bridge = new WasmBridge(module, options);
14
+
15
+ const moduleId = options.name || 'default';
16
+ this.modules.set(moduleId, { module, bridge });
17
+
18
+ return bridge;
19
+ }
20
+
21
+ get(name = 'default') {
22
+ const entry = this.modules.get(name);
23
+ return entry ? entry.bridge : null;
24
+ }
25
+
26
+ async loadFromNPM(packageName, options = {}) {
27
+ // Pour le navigateur, on assume que le fichier est dans /wasm/{packageName}.wasm
28
+ const wasmPath = `/wasm/${packageName}.wasm`;
29
+ return this.load(wasmPath, { ...options, name: packageName });
30
+ }
31
+
32
+ unload(name = 'default') {
33
+ const entry = this.modules.get(name);
34
+ if (entry) {
35
+ entry.bridge.cleanup();
36
+ this.loader.unloadModule(name);
37
+ return this.modules.delete(name);
38
+ }
39
+ return false;
40
+ }
41
+
42
+ listModules() {
43
+ return Array.from(this.modules.keys());
44
+ }
45
+
46
+ getStats() {
47
+ const stats = {};
48
+ for (const [name, entry] of this.modules) {
49
+ stats[name] = entry.bridge.getStats();
50
+ }
51
+ return stats;
52
+ }
53
+
54
+ unloadAll() {
55
+ for (const name of this.modules.keys()) {
56
+ this.unload(name);
57
+ }
58
+ }
59
+ }
60
+
61
+ // Instance globale
62
+ const gowm = new GoWM();
63
+
64
+ // API simplifiée
65
+ export const load = (wasmPath, options) => gowm.load(wasmPath, options);
66
+ export const get = (name) => gowm.get(name);
67
+ export const loadFromNPM = (packageName, options) => gowm.loadFromNPM(packageName, options);
68
+ export const unload = (name) => gowm.unload(name);
69
+ export const listModules = () => gowm.listModules();
70
+ export const getStats = () => gowm.getStats();
71
+ export const unloadAll = () => gowm.unloadAll();
72
+
73
+ // Export des classes
74
+ export { GoWM, WasmLoader, WasmBridge };
75
+
76
+ // Export par défaut
77
+ export default gowm;
@@ -0,0 +1,113 @@
1
+ export default class WasmLoader {
2
+ constructor() {
3
+ this.modules = new Map();
4
+ this.isNode = false; // Toujours faux en environnement navigateur
5
+ }
6
+
7
+ async loadModule(wasmPath, options = {}) {
8
+ const moduleId = options.name || wasmPath.split('/').pop().replace('.wasm', '');
9
+
10
+ if (this.modules.has(moduleId)) {
11
+ return this.modules.get(moduleId);
12
+ }
13
+
14
+ try {
15
+ // Charger wasm_exec.js si nécessaire
16
+ if (!globalThis.Go) {
17
+ await this.loadGoRuntime(options.goRuntimePath);
18
+ }
19
+
20
+ const go = new globalThis.Go();
21
+
22
+ const response = await fetch(wasmPath);
23
+ if (!response.ok) {
24
+ throw new Error(`Failed to fetch WASM file: ${response.status} ${response.statusText}`);
25
+ }
26
+ const wasmBytes = await response.arrayBuffer();
27
+
28
+ const result = await WebAssembly.instantiate(wasmBytes, go.importObject);
29
+
30
+ // Pré-initialisation pour optimiser les performances
31
+ if (options.preInit !== false) {
32
+ // Démarrer Go en arrière-plan pour éviter le blocage
33
+ go.run(result.instance);
34
+
35
+ // Attendre que le module soit prêt
36
+ await this.waitForReady(moduleId);
37
+ }
38
+
39
+ const module = {
40
+ instance: result.instance,
41
+ go: go,
42
+ exports: result.instance.exports,
43
+ ready: true
44
+ };
45
+
46
+ this.modules.set(moduleId, module);
47
+ return module;
48
+
49
+ } catch (error) {
50
+ throw new Error(`Failed to load WASM module ${moduleId}: ${error.message}`);
51
+ }
52
+ }
53
+
54
+ async waitForReady(moduleId, timeout = 5000) {
55
+ const startTime = Date.now();
56
+
57
+ return new Promise((resolve, reject) => {
58
+ const checkReady = () => {
59
+ // Vérifier plusieurs signaux de prêt
60
+ const isReady = globalThis.__gowm_ready ||
61
+ (globalThis.Go && globalThis.Go._initialized) ||
62
+ (globalThis.add && typeof globalThis.add === 'function');
63
+
64
+ if (isReady || Date.now() - startTime > timeout) {
65
+ if (isReady) {
66
+ resolve();
67
+ } else {
68
+ reject(new Error(`Module ${moduleId} failed to initialize within ${timeout}ms`));
69
+ }
70
+ } else {
71
+ setTimeout(checkReady, 10);
72
+ }
73
+ };
74
+ checkReady();
75
+ });
76
+ }
77
+
78
+ async loadGoRuntime(customPath) {
79
+ const runtimePath = customPath || '/wasm_exec.js';
80
+ await this.loadScript(runtimePath);
81
+ }
82
+
83
+ loadScript(src) {
84
+ return new Promise((resolve, reject) => {
85
+ const script = document.createElement('script');
86
+ script.src = src;
87
+ script.onload = resolve;
88
+ script.onerror = reject;
89
+ document.head.appendChild(script);
90
+ });
91
+ }
92
+
93
+ getModule(name) {
94
+ return this.modules.get(name);
95
+ }
96
+
97
+ unloadModule(name) {
98
+ const module = this.modules.get(name);
99
+ if (module && module.go) {
100
+ // Nettoyage des ressources Go
101
+ try {
102
+ module.go.exit(0);
103
+ } catch (e) {
104
+ // Ignorer les erreurs de nettoyage
105
+ }
106
+ }
107
+ return this.modules.delete(name);
108
+ }
109
+
110
+ listModules() {
111
+ return Array.from(this.modules.keys());
112
+ }
113
+ }
package/src/loader.js CHANGED
@@ -1,14 +1,17 @@
1
- const fs = require('fs');
2
- const path = require('path');
3
-
4
1
  class WasmLoader {
5
2
  constructor() {
6
3
  this.modules = new Map();
7
4
  this.isNode = typeof window === 'undefined';
5
+
6
+ // Importer les modules Node.js seulement en environnement Node.js
7
+ if (this.isNode) {
8
+ this.fs = require('fs');
9
+ this.path = require('path');
10
+ }
8
11
  }
9
12
 
10
13
  async loadModule(wasmPath, options = {}) {
11
- const moduleId = options.name || path.basename(wasmPath, '.wasm');
14
+ const moduleId = options.name || (this.isNode ? this.path.basename(wasmPath, '.wasm') : wasmPath.split('/').pop().replace('.wasm', ''));
12
15
 
13
16
  if (this.modules.has(moduleId)) {
14
17
  return this.modules.get(moduleId);
@@ -24,10 +27,10 @@ class WasmLoader {
24
27
  let wasmBytes;
25
28
 
26
29
  if (this.isNode) {
27
- if (!fs.existsSync(wasmPath)) {
30
+ if (!this.fs.existsSync(wasmPath)) {
28
31
  throw new Error(`WASM file not found: ${wasmPath}`);
29
32
  }
30
- wasmBytes = fs.readFileSync(wasmPath);
33
+ wasmBytes = this.fs.readFileSync(wasmPath);
31
34
  } else {
32
35
  const response = await fetch(wasmPath);
33
36
  if (!response.ok) {
@@ -91,11 +94,11 @@ class WasmLoader {
91
94
 
92
95
  if (this.isNode) {
93
96
  // Vérifier que le fichier existe
94
- if (!fs.existsSync(runtimePath)) {
97
+ if (!this.fs.existsSync(runtimePath)) {
95
98
  console.warn(`Go runtime not found at ${runtimePath}, using fallback`);
96
99
  // Utiliser le fallback du dossier runtime
97
- const fallbackPath = path.join(__dirname, '../runtime/wasm_exec.js');
98
- if (fs.existsSync(fallbackPath)) {
100
+ const fallbackPath = this.path.join(__dirname, '../runtime/wasm_exec.js');
101
+ if (this.fs.existsSync(fallbackPath)) {
99
102
  require(fallbackPath);
100
103
  } else {
101
104
  throw new Error(`Go runtime not found. Please ensure wasm_exec.js is available`);
@@ -110,7 +113,7 @@ class WasmLoader {
110
113
 
111
114
  getDefaultRuntimePath() {
112
115
  if (this.isNode) {
113
- return path.join(__dirname, '../runtime/wasm_exec.js');
116
+ return this.path.join(__dirname, '../runtime/wasm_exec.js');
114
117
  }
115
118
  return '/wasm_exec.js';
116
119
  }