Show HN: Build progressively enhanced reactive HTML apps using Go and Alpine.js
livefir.fly.devFir leverages Golang’s standard library html/template package and a bit of alpinejs to allow building reactive UIs. You start with plain old html and use alpinejs to enhance it to bring no-page-reload interactivity to web apps.
The Fir toolkit is designed for Go developers with moderate html/css & js skills who want to progressively build reactive web apps without mastering complex web frameworks. It includes a Go library and an Alpine.js plugin.
How it works ?
On receiving user-interactions the fir server re-renders html templates and sends it over the wire where the fir client library selectively updates the changed areas.
When a user event is received by a Fir route, an array of html templates are rendered on the server and returned as an array of DOM events to the browser. The DOM events are consumed by the alpinejs plugin and dispatched within the DOM where listeners attached to elements can use the event to update the DOM.
See the demo and quickstart here: https://livefir.fly.dev/ The idea of using Go and Alpine.js together for building reactive web apps seems promising. As you mentioned, Fir is targeting devs with moderate HTML/CSS & JS skills. How does Fir handle more complex scenarios such as nested components, handling form submissions with client-side validation, and integrating third-party APIs or libraries? Does the toolkit offer any built-in functionality or guidelines for handling these cases, or is the developer expected to handle them using custom code and Alpine.js plugins? Also the site is super slow! This example has most of the scenarios you have called out: https://github.com/livefir/fir/tree/main/examples/fira. Fir aims to limit itself to rendering templates on the server and making it available for all subscribers as a browser CustomEvent which is consumed by alpine.js for more complex interactivity. The expectation is the that the developer handles it via either alpine.js plugins or standard JS code. [edit] This is still a work-in-progress so I will certainly add better guides and documentation moving forward. Although its good to get feedback that this approach might be interesting for at least some people. I think this is adding unnecessary complexity. One of the reasons developers gravitate towards a framework like Alpine or HTMX is to write less JS and go back to enjoying HTML. Of course there are a lot of use cases that require custom JS scripting. But bootstrapping a project with another Go web framework and adding Alpine is also trivial. But keep going and follow your vision. I love these types of projects. Check this one out: It's got some unique ideas. Hey. I have checked out pushup before. Its great. I guess I am taking a niche approach which not many would find useful. To clarify: What is adding more complexity? alpinejs ? Interesting stuff; is this intended to be an experiment or a longer-term project? I think a straight-forward comparison of Fir and things like HTMX (htmx.org) would be a good addition to the demo page or docs. I’m not one, but from what I gather many golang enthusiasts like using the std http features of the language and other libraries like HTMX seem more appealing as they live just in the html templates. It’d help get a quick idea of how it fits in with existing libraries. For instance, the pubsub feature would be a distinction. It is intended as a longer-term project originating from the previous experiment: https://github.com/adnaan/gomodest. You are right, a better selection criteria for the target audience should be enlisted. I have been working on this for a while so I just got greedy for some early feedback. The one thing that golang really needs is a templating library that doesn't suck, Html bindings in this language feel more like an after thought and this is coming from a person that really likes this language. Have you tried this: https://templ.guide/ ? This is a very simple and clean Go templating library. I’m really looking forward to IntelliJ support I spend most of my time in the JavaScript ecosystem, but I've worked with Go and Rails and have been working with Django recently and my take is that this seems to be true for most other languages/frameworks. There are plenty of valid criticisms of React/etc, but the one thing they got really really right was making "templates" be normal functions that return a data structure representing the HTML. Logic is way less awkward, no global variables spanning partials in different files and it's impossible to write incorrectly nested markup. I really wish backend-only frameworks would steal that idea. Next.js very literally does by running React on the backend too! The second example counter is jumping around instead of incrementing/decrementing by 1. Is state being shared between users or somesuch? Or is it because I first clicked the full reload example several times? iOS The state is shared between users for the demo. Its possible to separate state in the library per user but I haven't enabled it. It’s a rather confusing demo. If that’s the intended behavior, I think you need to think of a less surprising use of it that can be understood as a demo, and perhaps even comes across as a benefit rather than a bug. Seems like everyone is just pushing the red button. Let me give some love to green button. I pressed the green button a bunch. Like, a LOT. Zero is such a nice, healthy, round number. As a sibling said, this is not a bug, but a feature, if explained as such. I wonder if it slow because of the locking, because other than that it shouldn't use much resources to run this. Anyway I am lazy, so I would probably just use HTMX boosting: Its locking and the state is shared. Didn’t expect a lot of interest for this or I would have built a better demo :) htmx is great! Is there a tl;dr on why I’d want to boost? Vs say normal browser behaviour So that the things that change only appear to update, not a flash of the entire screen. If the request is slow, this makes a bigger difference of course. I'm currently working with Alpine.js in order to try to build "Universal Components" or "Hypermedia Components". Where you just hit a URL and get your component like /components/infinite-canvas or /components/svg-2-base64 or /components/lib-somelib. [1] ilse.ink/components(It's not ready yet) Sounds interesting. ilse.ink/components didn't work. Could you post a link to it? I'm still working in it, but that's going to be the link. Trying to make universal components is hard, like, I wanted to make all components available trough a "filter" where you could re-use React.js, Vue.js, Svelt, Solid components with each other. When you think about it, components are just I/O with maybe some libraries. I'm thinking this is field is right for some standardization. Do you know about shoelace? Interesting Thanks! This is very cool. I'm working on a side project right now with a go back end and alpine front end. One of the things I've had to overcome is handling cookies and CORS since not everything is served from localhost. I ended up packaging my frontend in an nginx container and using that same nginx container as a proxy for the backend but the whole time I thought maybe this small project would be easier if everything was served by go. Will definitely keep an eye on this for future stuff. I've also used alpineJS, Golang and tailwindCSS to build gocial [1]. The source code is also publicly available [2]. The whole project is hosted at netlify as a big Lambda function. But I think for future projects I might use HTMX + Tailwind. I'm building a platform using GoFiber + AlpineJS and it's wonderful. I have to go through the Fir project because I'm trying to figure out what problem it solves. Wouldn't it be just as easy as using the vanilla net library + Alpine or one of the more established Go frameworks + Alpine? Honest question. If Fir has a value proposition that's unique im still in a position to pivot. The (claimed) value proposition is leveraging block/template to decompose the html page and bind its computation to browser events over a pubsub channel. Its a toolkit and not a framework so one can still use their favourite framework. The Go library isn’t doing anything earth shattering but re-implementing the aforesaid design would still need to be done in any framework. Been using Alpine.js in a Ruby on Rails app for about 6 months now. It's a very cool, lightweight js library that I rarely see talked about. Counter doesn't work properly on Android Chrome FYI just reloads the page. The first step counter button is supposed to reload the page. The second step buttons update the page w/o reload The second counter adds and subtracts values other than 1 and therefore seems broken. That's because there are hundreds of people coming from hacker news clicking the button. if you just refresh the page you can see the number change. The current total seems to be saved server side This is exactly what I need! I use Laravel mostly (with htmx and alpine) but wanted to build some stuff in Go. Thank you for your work! Hope this is constructive feedback: I’m located in México and it takes around 20 seconds to load. The app was on a 256mb instance. I have scaled it to 2gb. Let's hope its sufficient for now I think it's just getting the HN hug of death. I'm in the US on fiber and seeing timeouts and 30+ second load times. The hug of death doesn't bode well for the approach. Yeah I was afraid of that. Websockets are costly. Thankfully the approach doesn't completely depend on websockets so I have disabled it for now on the site. Yes! This is the project I’ve been waiting for. I'm on Arc (Chromium) and pressing any of the buttons in the first example jumps to the top of the page.
<div hx-boost="true">
// traditional code goes here
</div>