mirror of
https://github.com/LukeHagar/wasm-overhead-research.git
synced 2025-12-06 04:22:06 +00:00
Initial commit: JavaScript to WebAssembly compilation comparison
- 5 different JS-to-WASM implementations analyzed - QuickJS (283KB) and Javy Static (519KB) are Wasmer-compatible - Comprehensive size analysis and runtime compatibility testing - Complete documentation and build automation - Wasmer v6.1.0-rc.2 dynamic linking analysis included
This commit is contained in:
130
implementations/goja/main.go
Normal file
130
implementations/goja/main.go
Normal file
@@ -0,0 +1,130 @@
|
||||
//go:build js && wasm
|
||||
// +build js,wasm
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"syscall/js"
|
||||
|
||||
"github.com/dop251/goja"
|
||||
)
|
||||
|
||||
// promisify wraps a Go function to return a JavaScript Promise
|
||||
func promisify(fn func([]js.Value) (string, error)) js.Func {
|
||||
return js.FuncOf(func(this js.Value, args []js.Value) interface{} {
|
||||
// Create a new Promise
|
||||
handler := js.FuncOf(func(this js.Value, promiseArgs []js.Value) interface{} {
|
||||
resolve := promiseArgs[0]
|
||||
reject := promiseArgs[1]
|
||||
|
||||
// Run the function in a goroutine
|
||||
go func() {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
errorConstructor := js.Global().Get("Error")
|
||||
errorObj := errorConstructor.New(fmt.Sprintf("panic occurred: %v", r))
|
||||
reject.Invoke(errorObj)
|
||||
}
|
||||
}()
|
||||
|
||||
// Pass the original args to the function, not the promise args
|
||||
result, err := fn(args)
|
||||
if err != nil {
|
||||
errorConstructor := js.Global().Get("Error")
|
||||
errorObj := errorConstructor.New(err.Error())
|
||||
reject.Invoke(errorObj)
|
||||
} else {
|
||||
resolve.Invoke(result)
|
||||
}
|
||||
}()
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
promiseConstructor := js.Global().Get("Promise")
|
||||
return promiseConstructor.New(handler)
|
||||
})
|
||||
}
|
||||
|
||||
// transformData takes a JSON string and JavaScript code, processes it using Goja JavaScript engine, and returns a JSON string
|
||||
func transformData(args []js.Value) (string, error) {
|
||||
js.Global().Get("console").Call("log", "🔄 transformData called with", len(args), "arguments")
|
||||
|
||||
if len(args) < 2 {
|
||||
return "", fmt.Errorf("expected two arguments: JSON string and JavaScript code")
|
||||
}
|
||||
|
||||
// Get the input JSON string
|
||||
inputJSON := args[0].String()
|
||||
js.Global().Get("console").Call("log", "📥 Input JSON:", inputJSON)
|
||||
|
||||
// Get the JavaScript transformation code
|
||||
transformJS := args[1].String()
|
||||
js.Global().Get("console").Call("log", "📜 JavaScript code length:", len(transformJS), "characters")
|
||||
|
||||
// Parse the input JSON
|
||||
var inputData interface{}
|
||||
if err := json.Unmarshal([]byte(inputJSON), &inputData); err != nil {
|
||||
return "", fmt.Errorf("failed to parse input JSON: %v", err)
|
||||
}
|
||||
|
||||
// Create a new Goja runtime
|
||||
vm := goja.New()
|
||||
|
||||
// Execute the JavaScript code to define the transform function
|
||||
_, err := vm.RunString(transformJS)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to execute JavaScript transformation code: %v", err)
|
||||
}
|
||||
|
||||
// Get the transform function
|
||||
transformFunc, ok := goja.AssertFunction(vm.Get("transform"))
|
||||
if !ok {
|
||||
return "", fmt.Errorf("transform function not found in JavaScript code")
|
||||
}
|
||||
|
||||
// Convert Go data to Goja value
|
||||
gojaInput := vm.ToValue(inputData)
|
||||
|
||||
// Call the JavaScript transform function
|
||||
result, err := transformFunc(goja.Undefined(), gojaInput)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("JavaScript transformation failed: %v", err)
|
||||
}
|
||||
|
||||
// Export the result back to Go
|
||||
transformedData := result.Export()
|
||||
|
||||
// Convert back to JSON
|
||||
outputJSON, err := json.Marshal(transformedData)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to marshal output JSON: %v", err)
|
||||
}
|
||||
|
||||
resultStr := string(outputJSON)
|
||||
js.Global().Get("console").Call("log", "📤 Output JSON:", resultStr)
|
||||
|
||||
return resultStr, nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
js.Global().Get("console").Call("log", "🚀 Go WASM module loaded (Goja implementation)")
|
||||
|
||||
// Expose the transformData function to JavaScript
|
||||
js.Global().Set("transformData", promisify(transformData))
|
||||
|
||||
// Add a simple health check function
|
||||
js.Global().Set("healthCheck", promisify(func(args []js.Value) (string, error) {
|
||||
js.Global().Get("console").Call("log", "💓 Health check called")
|
||||
return `{"status": "healthy", "message": "Go WASM module with Goja is running"}`, nil
|
||||
}))
|
||||
|
||||
js.Global().Get("console").Call("log", "✅ Functions exposed to JavaScript:")
|
||||
js.Global().Get("console").Call("log", " - transformData(jsonString, jsCode)")
|
||||
js.Global().Get("console").Call("log", " - healthCheck()")
|
||||
|
||||
// Keep the program running
|
||||
<-make(chan bool)
|
||||
}
|
||||
Reference in New Issue
Block a user