September 4th, 2024

Goja: A Golang JavaScript Runtime

Goja is a JavaScript runtime library for Go, enabling easy integration and manipulation of data, supporting exception handling, sandboxing, and optimizing performance through sync.Pool for VM initialization.

Read original articleLink Icon
Goja: A Golang JavaScript Runtime

Goja is a JavaScript runtime library designed for the Go programming language, enabling seamless integration of JavaScript within Go applications. It addresses challenges faced when manipulating large datasets, particularly with complex JSON responses. The author initially considered other scripting languages like Lua, Expr, V8, and Starlark but found Goja to be the most effective due to its ability to automatically infer Go struct fields and methods, allowing for straightforward interaction between Go and JavaScript. The article provides examples demonstrating how to pass data between Go and JavaScript, handle exceptions, and manage Go structs within the JavaScript environment. It also discusses the use of a sync.Pool to optimize the initialization of Goja VMs, which can be resource-intensive. The author emphasizes the importance of sandboxing user-provided code to avoid variable declaration conflicts, suggesting the use of anonymous functions to encapsulate user scripts. Overall, Goja offers a flexible and efficient solution for embedding JavaScript in Go applications, enhancing performance and user experience.

- Goja allows seamless integration of JavaScript in Go applications.

- It simplifies data manipulation and interaction between Go and JavaScript.

- The library automatically infers Go struct fields and methods for easy access.

- Goja supports exception handling and sandboxing of user code.

- Using sync.Pool can optimize the performance of Goja VM initialization.

Link Icon 9 comments
By @nchmy - about 1 month
I just dug through a lot of the issues and PRs in Goja, and eventually found that the grafana/k6 team recently forked Goja as Sobek [1], because the Goja dev has not been able to dedicate sufficient time to their PRs - namely ES Modules support [2], which was one of the only modern (ES6+) JS features outstanding [3]

So, Sobek seems to be the way forward...

[1] https://github.com/grafana/sobek/

[2] https://github.com/dop251/goja/pull/430

[3] https://github.com/dop251/goja/milestone/1

By @alixanderwang - about 1 month
I work on the D2 project ([0]) and we switched from other Javascript runners (v8go) to Goja. Using a JS runtime with a dependency on cgo means your Go program loses the (huge) benefit of cross-compiling to different architectures, since at build time it gets linked to the current system's libc.

If you're interested in some production code with Goja, this is our code for calling RoughJS ([1]) from Go in order to produce the hand-drawn diagram look: [2]

[0] https://github.com/terrastruct/d2

[1] https://roughjs.com/

[2] https://github.com/terrastruct/d2/blob/master/d2renderers/d2...

By @nine_k - about 1 month
In short: Goja is an ES5 interpreter written in pure Go and seamlessly integrating with it. You pass a struct, the JS side receives an object, you update it, and the Go side seamlessly gets an updated struct. No cgo overhead.
By @throwaway13337 - about 1 month
This is the runtime pocketbase uses to allow javascript interop.

Pocketbase is the framework that makes me want to switch to golang. It just makes a lot of sense.

One thing that concerned me, though. How do I debug goja? It doesn't seem like I can set breakpoints as usual.

https://pocketbase.io/

By @nchmy - about 1 month
The examples in the article seem awfully contrived. Can someone please explain what a real-world use case for something like this would be? Why not just do it all in Go?

Or is the point of it to be able to use existing JS scripts within a Go application?

By @bitwize - about 1 month
You know, back when I got started as a Schemer, I remember people complaining about how many implementations of Scheme there were and how difficult it was to port between them. Today in JavaScript land we have Node, Deno, Bun, Goja, Sobek, Nashorn, whatever the browsers have, QML, GNOME, all of them subtly different. But instead of complaining, which people seem inclined to do when they encounter nested parens, people bro down and wrote code necessary to make them all interoperate if necessary -- despite JS having even less of a core language standard than Scheme does.

I guess it's the Lisp Curse or something, I dunno.

By @donatj - about 1 month
I've been a pretty happy Otto[1] user for a number of years now.

The article makes no comparisons seemingly? I don't think there's even a never. I find that pretty odd.

I'm curious if there'd be any reason to switch.

https://github.com/robertkrimen/otto

By @dialogbox - about 1 month
The name looks a obvious choice but... Ouch. It's a very funny name for Korean. It means eunuch. Lol
By @siamese_puff - about 1 month
Great article. I was looking for something like this last week.