Integración de la biblioteca Go en una página web JavaScript con WebAssembly
Con WebAssembly puedes integrar diferentes lenguajes de programación. Esto abre nuevas posibilidades para utilizar grandes bibliotecas escritas en un lenguaje en otra plataforma diferente. En este artículo quiero mostrar cómo integrar una librería Go para la tokenización de frases en una página web JavaScript. Normalmente, no se puede ejecutar código Go en un navegador web, pero con la tecnología WebAssembly sí se puede.
WebAssembly
WebAssembly es una especificación del W3C que define un formato binario y de texto para programas ejecutables que se pueden ejecutar en el navegador pero también de forma autónoma. Los programas WebAssembly se ejecutan en una máquina virtual (MV) basada en pilas. Tomando su nombre del lenguaje de programación ensamblador, muy cercano al hardware real, WebAssembly define un lenguaje más independiente del dispositivo que el ensamblador, pero sigue siendo de muy bajo nivel.
En el momento de escribir este artículo, WebAssembly es compatible con el 97,11 % de todos los navegadores del mundo (caniuse.com). Existen varias extensiones a la especificación WebAssembly del W3C que tienen diferentes niveles de soporte entre los navegadores.
Sentences Go Library
Sentences es una librería Go para la tokenización de sentencias escrita por Eric Bower y publicada como código abierto en GitHub. Dado que no se puede ejecutar código Go en el navegador de forma nativa, sólo JavaScript, existe la idea de utilizar WebAssembly para integrar la librería en un sitio web.
Exponer la biblioteca de sentencias a JavaScript
Puedes integrar la librería Sentences escribiendo una aplicación Go wrapper que aproveche el paquete syscall/js de Go. Es parte de la librería estándar de Go. Ten en cuenta, que en el momento de escribir este artículo, este paquete está etiquetado como "experimental". En concreto, utilizaremos la función js.FuncOf
. ¡Aquí está el código fuente completo de la aplicación Go:
package main
import (
"fmt"
"strings"
"syscall/js"
"github.com/neurosnap/sentences/english"
)
func sentenceWrapper() js.Func {
sentenceFunc := js.FuncOf(func(this js.Value, args []js.Value) any {
if len(args) != 1 {
return "Invalid no of arguments passed"
}
inputSentence := args[0].String()
fmt.Printf("input %s\n", inputSentence)
tokenizer, err := english.NewSentenceTokenizer(nil)
if err != nil {
panic(err)
}
sentences := tokenizer.Tokenize(inputSentence)
for _, s := range sentences {
fmt.Println(s.Text)
}
var sentenceTexts []string
for _, s := range sentences {
trimmedText := strings.TrimSpace(s.Text)
sentenceTexts = append(sentenceTexts, trimmedText)
}
allSentences := strings.Join(sentenceTexts, "\n") // Join all sentences separated by a space
return allSentences
})
return sentenceFunc
}
func main() {
fmt.Println("Go Web Assembly")
js.Global().Set("tokenizeSentence", sentenceWrapper())
<-make(chan struct{})
}
Ves que ahora la función sentenceWrapper
se expone como la función tokenizeSentence
en JavaScript. Espera como argumento una cadena a tokenizar y devuelve la cadena tokenizada. La integración real con la librería sentences ocurre dentro de la función pasada a js.FuncOf
.
Compilar Wrapper
Compila la aplicación a WebAssembly usando el siguiente comando Go build:
GOOS=js GOARCH=wasm go build -o main.wasm
Si todo ha ido bien, deberías encontrar el archivo main.wasm
como salida en tu carpeta. Este es el binario WebAssembly que se cargará en la aplicación JavaScript.
Integrar la librería Go WebAssembly en la página web
Para cargar el archivo main.wasm
en la página web, necesitas el siguiente código:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<script src="wasm_exec.js"></script>
<script>
const go = new Go();
WebAssembly.instantiateStreaming(
fetch("./main.wasm"),
go.importObject
).then((result) => {
go.run(result.instance);
});
</script>
</head>
<body>
<textarea id="sentenceinput" name="jsoninput" cols="80" rows="20"></textarea>
<input
id="button"
type="submit"
name="button"
value="tokenize"
onclick="tokenize(sentenceinput.value)"
/>
<textarea id="jsonoutput" name="jsonoutput" cols="80" rows="20"></textarea>
</body>
<script>
var tokenize = function (input) {
jsonoutput.value = tokenizeSentence(input);
};
</script>
</html>
Cuando ejecute esta página web en el navegador, también necesitará el archivo de utilidad JavaScript wasm_exec.js
en el directorio actual. Puede obtener el archivo de:
cp "$(go env GOROOT)/misc/wasm/wasm_exec.js" .
Como puedes ver en el código JavaScript, la función expuesta tokenizeSentence()
es llamada desde JavaScript cuando se pulsa el botón "tokenize". El contenido del campo de entrada se utiliza como argumento de la función y el valor de retorno se escribe en el campo de texto de la derecha. Tenga en cuenta que necesita ejecutar un servidor web para poder ejecutar la página web en su navegador. Puedes usar este código para construir un servidor web en Go:
server/server.go
package main
import (
"fmt"
"net/http"
)
func main() {
err := http.ListenAndServe(":9090", http.FileServer(http.Dir("../")))
if err != nil {
fmt.Println("Failed to start server", err)
return
}
}
Después de iniciar el servidor web, puedes acceder a la página en tu navegador bajo: http://localhost:9090
.
Gracias a Naveen Ramanathan de golangbot.com por su inspiración para este artículo.
Conclusión
Como siempre, espero que este artículo te haya ayudado de alguna manera a mantener la curiosidad. WebAssembly es una tecnología que tiene un gran potencial para integrar los diferentes ecosistemas de lenguajes entre sí.
Referencias
-
WebAssembly.org: https://webassembly.org
-
Especificación de WebAssembly: https://github.com/WebAssembly/spec
-
Biblioteca de sentencias Go: https://github.com/neurosnap/sentences
-
Paquete Syscall/js: https://pkg.go.dev/syscall/js
-
Golangbot Webassembly usando Go: https://golangbot.com/webassembly-using-go
Photo by Venti Views on Unsplash
Publicado el
6 jul. 2024