[HN Gopher] Goja: A Golang JavaScript Runtime
___________________________________________________________________
Goja: A Golang JavaScript Runtime
Author : mihaitodor
Score : 97 points
Date : 2024-09-04 13:45 UTC (3 days ago)
(HTM) web link (jtarchie.com)
(TXT) w3m dump (jtarchie.com)
| throwaway13337 wrote:
| 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/
| thangngoc89 wrote:
| Actually I decided to learn golang for extending using Golang
| for better DX (type hints and compiler errors)
| throwaway13337 wrote:
| It's certainly a good idea to know golang while using
| something like pocketbase.
|
| However, one of the strengths of pocketbase, I think, is that
| the creator chose to add bindings for a very well known
| scripting language (js) to allow projects to be rapidly
| developed. It feels like django rethought.
|
| Using go for the base of your project and then gluing things
| together via scripting seems like a good idea. It's quite a
| big feature of the framework.
| skeeter2020 wrote:
| performance seems pretty solid too, removing one of my
| prime motivators for switching to Go for extension work.
| PocketBase just seems to have made a lot of great decisions
| based on the conceptual integrity of the project goals.
| jtarchie wrote:
| I've used Pocketbase for some other projects. A quick
| small web app, but it was so easy.
| nine_k wrote:
| 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.
| chrsig wrote:
| It's definitely cool, and and accomplishment. I think it's a
| bit strange to compare it to "no cgo overhead" though
|
| I say that because it's an interpreter rather than a jit, and
| doesn't have nearly as many person hours put into it as v8.
|
| I can see the argument that if you just need to evaluate a
| quick expression or maybe some user supplied script or
| something, it could be very handy, but I have a hard time
| believing that the cgo overhead is a factor when using cgo to
| invoke v8 compared to the parse/jit overhead that v8 will do.
|
| This is all armchair speculation of course. I use go regularly,
| but have no taste for javascript, so I have no dogs in that
| race. Definitely cool that there's an interpreter focused on
| correctness though.
| mappu wrote:
| Calling a C function with Cgo has a certain overhead if you
| compare it to calling a Go function. But cgo overheads are
| completely negligible as soon as the function does any kind of
| real work. (A bigger reason to avoid cgo would be if you want
| easier cross-compilation.)
| randomdata wrote:
| cgo execution overhead is a nothingburger, but the programmer
| overhead to convert between Go types and C->Javascript types,
| and vice versa, as required by the use of a third-party
| engine (v8, etc.) is still significant as compared to what
| Goja offers. That is what the parent is talking about.
| siamese_puff wrote:
| Great article. I was looking for something like this last week.
| jtarchie wrote:
| I'm glad it was helpful. It was a list of things I had known
| before I used it. So it was meant to be a quick getting started
| like doc.
| nchmy wrote:
| 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?
| BobVawter wrote:
| I've been using goja in a logical replication tool to make it
| field-programmable by the end users. No two deployments look
| alike, so a great deal of flexibility is needed for ETL uses.
| There's a tendency for configuration languages to become
| Turing-complete, so we started with a Turing-complete language
| for configuration.
|
| JS, or in Replicator's case, TypeScript (shout-out to esbuild),
| is sufficiently well-known that any dev group will have some
| experience with it. On the whole, I've been very impressed with
| how straightforward it's been to have user-scripts integrated
| into the processing pipeline.
|
| https://github.com/cockroachdb/replicator/wiki/User-Scripts
| nchmy wrote:
| Ah, that makes a lot of sense - far easier to expose a JS api
| for user-extension than Golang (which is probably not even
| all that possible, except for via wasm, which would still be
| challenging)
|
| And, I suppose my initial hunch is probably correct - for the
| dev/application to be able to use existing JS libraries (be
| it part of your broader application/system or external)
| within a Go app.
|
| Check out my other comment [1] in this post for a newer,
| better version/fork of Goja - from the grafana/k6 team.
|
| [1] https://news.ycombinator.com/item?id=41470601
| jtarchie wrote:
| Not doing it all, Go allows my API endpoint to accept sandboxed
| javascript code to enable users to run more complex queries
| against my data. It is also faster because they don't have to
| make individual API calls for each data set. Therefore, more
| data is required to be sent over the wire to them.
| nchmy wrote:
| Thanks. Ive been exploring all of this for the past many
| hours and definitely see the appeal and various use cases for
| it now.
|
| Thanks for opening me up to it all - it will definitely solve
| a problem that I'm about to start working on!
| nchmy wrote:
| I just found this excellent comment in an relevant Reddit
| post[1], which clarifies things quite nicely for me.
|
| ---
|
| Let's set up the scenario. You have a program that a user can
| manage via a config file. That tune knobs and dials, and
| everything works. They then ask you one day, "I'd like to add
| some custom logic for they have."
|
| Do you add another option to the configuration file to support
| their one use case? Or provide a mechanism for them actually to
| write some code?
|
| If it's the latter, do you want them to have to recompile your
| program to be able to run that custom code? Or do you have a
| runtime in your application for that custom code?
|
| The latter is what a browser does. You can write JavaScript for
| a website without recompiling the browser just for the website.
| The user doesn't have to worry about your event loops, SDKs,
| APIs, wiring code in rust/C, etc. This feature allows others to
| add custom logic to your application's runtime.
|
| This is the purpose of embedding JavaScript into an
| application. It's not the whole program, but it allows someone
| to provide code in your program event loop to do something
| custom. Not every program needs this. Sometimes, a config file
| of YAML or command line arguments works, too.
|
| [1]
| https://www.reddit.com/r/golang/comments/1d78d3j/what_script...
| artpar wrote:
| I am using otto[0] (similar to goja) in the headless cms I
| maintain [1] in "actions" api [2]. So one can customize actions
| according to needs by writing JS. The JS is executed inside a
| transaction. Sort of a mini-lambda kind of api
|
| [0] https://github.com/robertkrimen/otto [1]
| https://github.com/daptin/daptin [2]
| https://daptin.github.io/docs/actions/actions/
| joostdecock wrote:
| For a real-worl use case, look towards the 'script' processor
| in Elastic' Beats family of data shippers [1] (example is from
| Metricbeat but it exists in other Beats too)
|
| They can be configured to mutate the data with some basic DSL
| syntax, but if you have more advanced needs, you can break out
| to JavaScript and transform the JSON any way you want.
|
| This is very useful because now any transformation becomes
| possible. And because this is the user of your product who
| writes that JavaScript more as configuration than code. And
| since there's no build step, it is just part if the
| configuration loaded at startup.
|
| [1]
| https://www.elastic.co/guide/en/beats/metricbeat/current/pro...
| solatic wrote:
| On top of the previous comments describing how to use JS as an
| embedded scripting language, I've seen in production (series B
| startup) an architecture where:
|
| a) non-technical users describe, in plain English, what they
| would like from the data; b) an LLM with lots and lots of
| prompt-engineering massaging translates the English into JS, c)
| the JS gets executed in a sandbox, d) the results get returned
| to the user
| bastawhiz wrote:
| I didn't use Goja (this was maybe a decade ago) but I used
| Otto, which is the same concept.
|
| I used it for game scripting. Lots of stuff is just easier to
| write in a high level language. I was able to use inheritance
| to compose behaviors for entities, and I could restart entities
| with new code without having to restart the server.
| dialogbox wrote:
| The name looks a obvious choice but... Ouch. It's a very funny
| name for Korean. It means eunuch. Lol
| michaelsbradley wrote:
| Then there's Ejacs
|
| https://github.com/emacsattic/ejacs
|
| http://steve-yegge.blogspot.com/2008/11/ejacs-javascript-int...
| jtarchie wrote:
| Someone on Reddit mentioned in Norwegian, it means "nothing."
| t3rra wrote:
| I actually came to comments to say that.. lol.
| alixanderwang wrote:
| 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...
| donatj wrote:
| 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
| jtarchie wrote:
| I just wanted to share the details of my experience with Goja.
| It was not relevant to compare Otto.
| nchmy wrote:
| 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
| jtarchie wrote:
| I did see that. I'm going to let the fork simmer for awhile. I
| didn't require module support for my runtime. Since its meant
| to be very basic ETL runtime.
| nchmy wrote:
| Fair enough! Though they're quite clearly a much more
| serious/focused/resourced team than the goja dev, and they've
| fully integrated it into the K6 codebase now. I expect it'll
| have a bright future.
|
| Since you're doing ETL, did you consider something like
| Conduit, which is written in Golang and also allows for JS
| processing in the pipeline? Or is that overkill for what
| youre doing?
|
| https://conduit.io/docs/processors/builtin/custom.javascript
| bitwize wrote:
| 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.
___________________________________________________________________
(page generated 2024-09-07 23:01 UTC)