Go
High-Performance Go Engines in the Browser via Wasm 'Reactor Mode'
Published:
•
Duration: 6:39
0:00
0:00
Transcript
Host: Hey everyone, welcome back to Allur, your home for all things PHP, Laravel, Go, and the ever-evolving world of mobile and web dev. I’m your host, Alex Chan.
Host: I am so excited to welcome Marcus Thorne to the show. Marcus is a Principal Engineer who’s spent the last decade building high-scale distributed systems, and lately, he’s been obsessed with pushing the boundaries of what Go can do outside of the traditional server environment. Marcus, thanks for hopping on Allur!
Guest: Thanks for having me, Alex! It’s great to be here. I’ve been a long-time listener, so it’s a bit surreal to be on the other side of the mic.
Host: Oh, that’s so cool to hear! So, Marcus, let’s jump right in. We’ve been hearing about Wasm for years, and Go has had Wasm support for a while. But why has it felt a little... I don’t know, "heavy" until now?
Guest: Yeah, that’s a great way to put it. Historically, when you compiled Go to Wasm using the standard `js/wasm` target, you weren’t just sending your logic to the browser. You were sending the entire Go runtime. We’re talking about the garbage collector, the scheduler—the whole nine yards. Plus, you needed this `wasm_exec.js` helper script to glue it all together. The result was these multi-megabyte files for even a "Hello World" app. It was persistent, it was bulky, and it just didn’t feel "web-native," you know?
Host: Exactly! It felt like you were trying to boot up a tiny OS just to run a function. So, what is this "Reactor Mode" then? Is it just a smaller runtime?
Guest: It’s actually a fundamental shift in how the code executes. Reactor Mode—which you enable with the `GOEXPERIMENT=wasgo` flag—moves away from that persistent, "always-on" runtime. Instead of the Wasm module taking over the execution flow, it treats the Go code as a library of discrete functions that you can just... call. It’s "single-shot" and non-persistent.
Host: Oh! So it’s more like a collection of tools rather than a whole worker process?
Guest: Exactly. You export specific Go functions directly to JavaScript. Once the module is instantiated, those Go functions look and act almost like native JS functions. You don’t have that massive overhead of the full Go scheduler running in the background constantly. This leads to way smaller binaries and—this is the big one—insanely fast cold start times.
Host: That is huge. I mean, actually being able to use a Go library for a specific task without making the user download a 10MB binary... that changes the math on whether it’s worth it. What kind of "aha" moments did you have when you first started playing with this?
Guest: Honestly, the "aha" moment for me was seeing a full-scale web scraping engine running in the browser. There was a post on Reddit recently where a developer did exactly this. Usually, if you want to scrape a site, you do it on the server because the logic is complex and you need the performance. But with Reactor Mode, they moved that whole Go engine into the client.
Host: Wait, really? A scraper in the browser? Doesn’t that get complicated with CORS and all that?
Guest: Well, sure, you still have to deal with the web’s security model, but the *processing*—parsing the DOM, extracting specific data points, running complex regex—that all happens at native Go speeds on the user's machine. You aren't sending raw HTML back to your server, paying for the bandwidth, and then paying for the CPU cycles to parse it. You offload all that cost to the client. It’s basically free scaling.
Host: That’s brilliant. It’s like the ultimate edge computing. You’re not even at the "edge" node; you’re literally on the device. Are there other use cases besides scraping?
Guest: Oh, tons. Think about heavy data processing. If you have a financial dashboard that needs to run complex simulations or a machine learning model for real-time text analysis, doing that in pure JavaScript can be... slow. Or it can make the UI janky because JS is single-threaded. By offloading that to a Go-powered Wasm module via Reactor Mode, you get that performance boost without the server round-trip. I’ve even seen people using it for client-side image manipulation and custom DSL parsers.
Host: I love that. But it can’t be all sunshine and roses, right? I’m imagining that passing data between JavaScript and Go must be a bit of a headache.
Guest: [Laughs] You hit the nail on the head. That is definitely the "struggle" part of the journey. Since Wasm and JS live in different memory spaces, you can’t just pass a Go struct to a JS object. You usually end up serializing data—often as JSON—into a string, passing that string over the fence, and then deserializing it on the other side.
Host: Ugh, the classic "JSON tax."
Guest: Exactly! If you're doing that a thousand times a second for tiny bits of data, the serialization overhead might actually eat up your performance gains. The secret is to keep the "heavy" work inside Go. You want to pass a big chunk of data once, let Go chew on it for a while, and then return the final result.
Host: That makes total sense. So, for the devs listening who want to try this out—I think you mentioned a flag earlier? What does the actual workflow look like?
Guest: Right, so you’ll need a recent Go version—1.21 or newer is best. You set your environment variables: `GOOS=js`, `GOARCH=wasm`, and the magic one is `GOEXPERIMENT=wasgo`. Then you just run `go build`. On the JavaScript side, you use the standard `WebAssembly.instantiateStreaming` API. No more `wasm_exec.js` required for Reactor Mode, which is a blessing.
Host: And can you touch the DOM from Go in this mode?
Guest: Actually, no—and that’s a common misconception. Reactor Mode is really designed for "engines." It’s for logic, math, and data. If you want to change the color of a button, stick to JavaScript. You want to keep your Go code "pure"—focused on the computation. You call it from JS, get the result, and then let JS handle the UI updates.
Host: Interesting! So it’s almost like having a high-performance "sidecar" for your JavaScript.
Guest: That is the perfect analogy. It’s a sidecar. It’s not there to replace your frontend framework; it’s there to give it superpowers when things get computationally expensive.
Host: I’m curious, Marcus—where do you see this going? Is this going to stay "experimental" forever, or do you see a future where every major Go library has a "wasm-reactor" version?
Guest: I think we’re heading toward a more modular web. With the upcoming Wasm Component Model, this kind of interoperability is only going to get easier. I think we’ll start seeing Go developers publishing packages that are specifically optimized to run in this "Reactor Mode," allowing frontend devs to pull in high-performance Go logic as easily as they pull in an NPM package. It’s going to bridge the gap between backend and frontend teams in a really cool way.
Host: It really feels like the "full-stack" definition is shifting again. Marcus, this has been fascinating. I’ve definitely had a few "aha" moments myself today. Before we wrap up, where can people go to learn more or see some examples?
Guest: Definitely check out the official Go GitHub and look for the `wasgo` experiment notes. There are also some great threads on the Gopher Slack and Reddit—specifically that scraping engine thread we mentioned. It’s a great time to be a Gopher in the browser!
Host: Awesome. Marcus, thank you so much for joining us on Allur and sharing your expertise.
Guest: My pleasure, Alex. Thanks for having me!
Host: What a cool look into the future of Go. I love the idea of "Reactor Mode" essentially turning our Go code into high-speed plugins for the browser. It really changes how we think about what the "backend" actually is.
Tags
Go
Golang
Frontend
web development
performance
webassembly
reactor mode