Hacker News new | past | comments | ask | show | jobs | submit login
StimulusReflex, or LiveView for Rails (stimulusreflex.com)
198 points by nanna on Jan 15, 2021 | hide | past | favorite | 85 comments



Russ Hanneman feels positive about stimulus reflex https://www.youtube.com/watch?v=utxCm3uLhIE


Ha that was well worth the watch, ty!


How did they get the actor to play this, amazing.


Assuming Cameo?


It‘s called „money“


It's worth pointing out that the Phoenix Web Framework (which LiveView is built on) came into being because the creator Chris McCord tried to build something like LiveView in Ruby and eventually ran into fundamental limitations due to how concurrency was handled. He looked around, discovered Elixir and the rest is history.

I'm very interested to learn what has changed since then that made this possible, or made it work better. Or whether those problems are just being "lived with".


There's a project called AnyCable which replaces ActionCable to give Rails the real-time performance equivalent of LiveView.

See this https://evilmartians.com/chronicles/anycable-actioncable-on-...

Looks like having 20,000 idle clients connected to a server sits at only 380MB and Erlang is at 737MB.


Thanks for posting this. I need to try it out. I'm specifically curious about how it performs when a certain amount of those 20k connections are busy and generating traffic. If I'm understanding, the anycable-go connection to ruby is over RPC? So individual websocket messages generate requests to ruby? I could see this performing better for idle connections, that's for sure.


I’m really excited for Ractors in this content and how/if they could improve the Ruby side


I've had good success with AnyCable


> Looks like having 20,000 idle clients connected to a server sits at only 380MB and Erlang is at 737MB.

That's with Go, versus with anycable itself. Anycable-go looks like 798?


I remember there were still latency issues, with 99th percentile being well over 100ms.

Cant find the link to the article though.


I love that Rails continues to evolve. I've invested so much time in it that it's good to know that Rails is still a viable choice for modern work. If someone's creating new cool stuff like this, then I'm not the only one.


I feel the same. I'm invested and I actually like developing on it (biased of course). I don't see any reason to worry about Rails jobs disappearing, Rails is here to stay. It's soon turning 20 forchrissake!


To me, this looks like one of the few real ways out of the madness that is modern frontend development. Excited to see the approach gaining adoption!


I don’t think this holds up anymore. Tooling has come so far.

I have never in my life been as productive as I am inside of a Vue/Tailwind code base at this point.

One of my clients is a fairly vanilla Rails 4 app (which is arguably a friendly place to be - although slow) and it’s not even close. I miss Vue and having a full “app” environment on the front-end side constantly. Jumping back and forth between these projects is like going from a hot and steamy comfy jacuzzi into an icy cold pool.


> I have never in my life been as productive as I am inside of a Vue/Tailwind code base at this point.

For what kind of app? Crud, frontend to a SaaS, something else?

I am still finding form-heavy apps needing frontend+backend form validation to be faster to write entirely server-side. Which is painful as more and more I have field types that are best off as JS widgets, and enhancing server-rendered forms is a pain.


You can certainly still use tailwind here.

Otherwise, the point is that you won’t have to jump back and forth—you can just stay on the backend. I’ve actually never used Stimulus Reflex, but in LiveView, I’m writing very small bits of JS maybe 2% of the time.


Speaking of, DHH looks like he's using tailwind with Rails, so the use-case is getting some love! DHH created this gem:

https://github.com/rails/tailwindcss-rails


I agree with you, but it took a long, long time to get that good and comfortable with react (in my case) years actually since I don't only do frontend.

For people who haven't already climbed that mountain and learned a new "language" I agree with GP. This could be a game changer.

My only regret is that for a while now JavaScript had basically been the standard. As good a development as I think this is, it will really in more fragmentation and less general purpose devs.

Nevertheless I think it's good, and web assembly was always going to do this to JavaScript ecosystem anyway.


The JavaScript framework era always felt like a bandaid while we figure out something better. I’m convinced liveview is the future.


I would give up my entire salary to be able server render views again. It is more than twice as efficient.


Using StimulusReflex in my latest project, been a good experience to work with. The community on Discord is very active and helpful, and the docs are top-notch.

Check the StimulusReflex Expo for interactive demos w/ code samples: https://expo.stimulusreflex.com/


> This entire round-trip allows us to update the UI in 20-30ms without flicker or expensive page loads.

A lot of people have much worse ping times than that. Try using this on a satellite connection for example, and your experience won't be very pleasant.

On my internet connection, which is pretty average by polish standards, the best ping I can get is 30ms, and that only happens when the server I ping is just one or two hops away. I probably won't be able to go under 100ms when the server is in the US.

It seems like this approach sacrifices runtime performance for development speed. I feel like it might often be a good tradeoff to make, but it's a tradeoff nevertheless, and we should recognize that. Separate layers for frontend and backend introduce complexity, but client side code is client side code, you can't go much faster than that.


I can imagine this simplifying the development of B2B SaaS tools that are primarily about presenting and interacting with data. The bit about broadcasting to a large number of clients is harder to see the value of in a Rails application when so many approaches work simply enough already.

As for replacing rich frontend rendering libraries in more complex apps - it seems dicey. Part of the virtue of React is that it simplifies the visual presentation of the frontend based on a constellation of data. Things like highlighted elements, hover states, and dragging items. It seems difficult to enable that level of polish while the backend is making dom-level changes based on the explicit data that you have to deliberately send over the network.


was looking for this sort of comment to confirm my bias. I'm trying to figure out what is it about how I feel about reflex: the idea that even with this you still have to reach for js libs or am I just being lazy. I guess a little bit of both maybe.

But it's true, even though our app is pretty straight forward crud, we still need things like autocomplete, drag and drop, tabs, modals, form validation etc. Just having js being js and ruby being ruby seems easier for me to parse and work with.


Wish I had the time to really study Phoenix's LiveView and implement the same in Java.

AFAIK there's no equivalent for this in Java and I mean the same not kinda-the-same but not really like Vaadin or God forbid GWT.


Good luck. Liveview depends strongly on features of the erlang VM that you won't get right without a deeper understanding of erlang (how do you clean up a websocket connection when the actor exits early, say due to throwing an exception - that's zero lines of code in lv), you're probably better of taking inspiration and writing it from scratch.


So in your opinion in Java land resources are always leaked when some exception occurs? That’s a bit far from the truth


No, I think the point was that you would have be aware of these types of cases - and cleaning up after exceptions isn't the only one - and deal with it in your code. Maybe it's trivial to do in Java, but still it has to be done.

Whereas with Elixir, it's handled by the way failed processes are handled which is to just "let it die". Another one will come along and replace it. (I'm greatly simplifying here)


My point was more: The way to handle resource cleanup is "let it die".


Wish?


thks


As someone who has barely done any web development in his life but having a fairly interactive side project in mind I wanted to work on, is Rails and StimulusReflex a solid thing to start out with right now, or would you recommend just going with React, Vue and so on? Navigating all those frameworks seems very complex.


Rails is great!


Closing the gap between server and client in terms of app development is definitely the answer. Also agree with the pitch that the currently popular approach of simply moving everything to the client has made tooling incredibly complex (although it's getting better). It's great to see new tools like this being built.

Moving everything to the server instead also closes the gap, but the obvious problem is that this introduces a lot of latency for UI interactions. Ajax page loads/Turbolinks works so well because it actually makes things faster with almost zero effort. Introducing a similar method for every UI interaction though is a different matter, and I don't see how the latency won't be noticeable.

For instance, The TodoMVC example's server seems to be far enough way from my location that creating a task has noticeable lag. Sure it's just an example, but without introducing some client-side/optimistic rendering, that's going to be hard to avoid (and that would defeat the purpose of having all your logic in one place, on the server). Not sure how this is addressed here?


In the Phoenix LiveView world, the solution has been to use Alpine.js for user interactions that don't involve loading data from the server [1]. Alpine and LiveView are the AL in the "PETAL stack" [2]

[1] https://dockyard.com/blog/2020/12/21/optimizing-user-experie...

[2] https://changelog.com/posts/petal-the-end-to-end-web-stack


Even with tooling getting better, you're still faced with creating an API to the backend that has a high chance of your frontend being the only ever consumer of it. You're also faced with duplicating logic on both front and backends in many scenarios (though of course this can be mitigated with a node backend? I don't know... I've never used node).

As for latency, this is over websockets. It becomes a problem if you are connecting to a server across the ocean but otherwise, it's incredibly fast and feels just as snappy as JS. I actually also haven't used Stimulus Reflex, just Phoenix LiveView so I'm not sure if they are exactly the same, but the TL;DR is that they are sending VERY tiny payloads over websockets. This video explains it well (though it's also a demo of LiveView): https://www.youtube.com/watch?v=MZvmYaFkNJI


Oh definitely, totally agree the status quo of duplicating logic is unnecessary.

And I realize this is using websockets, and that the payloads are tiny, but you can't fight the speed of light ;), so it's more of a latency concern (vs bandwidth). So in order to truly keep all the state and rendering with the server, even the smallest UI interaction would require a round-trip, and unless you'll have end nodes all across the country, that seems like it will noticeable.

With some actions like "search", "save" or "reload" I would expect a spinner and delay anyway, so that's not a problem. But if opening a dropdown menu or adding an item to a list (like in the example) feels slow that might not be the best user experience. But perhaps it's not a problem in practice, I haven't seen too many examples.


Yep, it definitely can be a concern! It takes a lot of distance before latency starts to be noticeable so it all depends on our use-case. These tools aren't one-size-fits-all. Lots of people are building things that aren't going global—at least not right off the bat—so these tools provide a way of moving very quickly out of the gate (no need to build an API for yourself, no need to duplicate any frontend and backend logic). If you do go global, you're probably in a good place to start serving your global customers from servers closer to them—the company I work, for example, for has to do regardless. And that fits under "a nice problem to have" which can be solved after your business has been validated.

But yes, there are many cases where this will not work. It's just a verrrrry attractive option when it can.


> the TL;DR is that they are sending VERY tiny payloads over websockets

If you have a server in NY and you happen to live in Germany it's going to take about 100-120ms to do a network round trip in a best case scenario (high quality wired cable connection) even with a 1 byte payload. For most websites running in 1 datacenter that means a massive population of the world is going to feel that latency.

That's why I'm not sold on using LV and websockets for everything (such as transitioning from page A to B, etc.). Hotwire Turbo Drive / Frame uses HTTP which means you can cache responses and send back 304s when the content doesn't change. HTTP feels like the right protocol to do this, and then you can save Websockets for when you need to broadcast relatively small amounts of new / updated / removed content to 1 or more connected clients. That's what the Hotwire model provides.


Yeah, am silently on your side on this point everywhere you go! Because I already said once and done a good fight.

Stateful (I mean really keep things in assigns) sounds like an inefficient caching. Not all assigns are per user, caching the same things on each process is redundant. And to share these things as one set of data is to put them somewhere else, most likely in a process under the root supervision tree. And there's less point for using LV.

Folks forgot how fast Phoenix.View rendered from controller was (a hello page is microsecond!) it's pretty damn good.


> which means you can cache responses and send back 304s when the content doesn't change.

Unless I misunderstand - that's still a round-trip to fetch and return a 304? Or are you thinking an edge cache closer to the end-user?

(I don't disagree that websockets aren't a universal solution - but if used as server push - it's difficult to see how plain http could have lower latency? Long polling would be similar, but probably (even) harder to scale if you want 10k+ open connections?).


I addressed this in another reply but TL;DR, these solutions are totally use-case dependent and they don't pretend to be one-size-fits-all (or at least LiveView doesn't).


In many ways, this is very cool.

But, I have to admit, I don't love it. I would love to have an integrated environment where client/server doesn't matter, but I don't think this gets far enough. Working in a spread of html.erb with special tags plus some Javascript doesn't feel great to me compared to React.

I like their TodoMVC app, since that gives a simple, minimal starting point. Getting persistence in that few lines of code is nice.

However, it has also at least one bug compared to canonical TodoMVC. I think the problem of this kind of too-clever binding is that it makes this kind of bug easy to introduce; whereas something with clear one-way data-binding like React, for all it can be verbose and annoying, tends to make it easier to get this sort of thing right.

(The bug? Click an existing todo to edit it, start typing, then press escape. The edit is meant to be discarded, but instead you'll see a flash of the old value and then the new value is persisted. It's not the worst bug ever, but shows that even in a simple app, experts can subtly screw up important behaviour.)


Here comes the classic HN middle-brow dismissal :)

TodoMVC is meant to be a minimalist demo, not a battle-hardened app.

We switched from React to Reflex 7 months ago. We have fewer bugs than we did with React, and we ship things about 3 times faster.

5/5 of us strongly prefer Reflex over React. Including one of us who was a big React aficionado beforehand.

Just wanted to put that out there for anyone considering Reflex, a bug in TodoMVC is not a harbinger of a bad framework.


That may be fair :)

Personally, I enjoy React on the front-end but don't currently like any back-end framework, so Reflux may well be better in aggregate.

(FWIW, I have a PhD in computer science and big part of that was on web applications and frameworks for them, combined with ~15 years commercial experience mastering web development, so this wasn't meant to be a middle-brow dismissal. As I said, it is exciting, I'm just not convinced.

I think there is some merit in the argument that too much cleverness can be dangerous. Battle-hardened is tricky; I agree TodoMVC is meant to be a minimalist demo, but if a minimal demo can have subtle bugs caused by the cleverness of the data binding, how much more so a real app with a much more complex data model?

But I guess it does eliminate whole other classes of bug, so I can believe it works less buggy and more productive better than React+some back end.

I certainly find the current front/back split endlessly painful. I am also excited by the new React Server Components which might be another good solution to that.)

EDIT TO ADD: I guess what I was trying to say is: I found this interesting, and I looked at it, and then I found this bug in the example, and I wonder if this framework might make a bug like that more likely because the power of making some things easier is obscuring what is happening in some cases, and I don't know if that trade-off is worth it.


My experience bears this out as well. Things that "just work" usually don't do that and/or come with a list of significant caveats.


I love hearing this story! I'm not in the job market since I love where I work at the moment (though don't love our tech stack) but I'm really hoping to find something, preferably using LiveView, for my next move. It's really nice to hear about companies having success with this kind of tech! It's the first tech I've been really excited about since learning Rails eight years ago (which was far too late!)


Isn't Reflex a Haskell framework?

Switching from React to Reflex isn't just switching a framework, but a whole stack.


I appreciate the work put into this, glad to see SPA alternatives and can understand using this for existing Rails projects.

I'm curious why would one would choose this over Phoenix LiveView for a new project? How are the two different?


I use Phoenix primarily (for web apps) so I of course agree with you, but the obvious answer is "anyone doing rails can add this easily without changing languages/stacks." That alone addresses a massive segment, probably much much larger than Phoenix


The Ruby/Rails ecosystem is massive, and remains extremely productive and pleasant to work with.


I would love it if Elixir grew in popularity but I’m also happy other ecosystems are hopping aboard this ship. I absolutely love working this way and hope it becomes more of the norm.


DHH recently introduced Hotwire https://hotwire.dev/ which already does something similar. Any idea what the difference is?


in one word: morphdom (https://github.com/patrick-steele-idem/morphdom)

also, StimulusReflex predates Hotwire for 1 year and is already pretty hardened :-)


Well Hotwire is running on Basecamp (or Hey?) , its not some half arsed solution...


For sure! It just doesn’t really overlap.


So this receives the full HTML page and does a near-zero-damage “morphing” as opposed to Hotwire which either does full page dumb replacement or asks you to define which sections to replace? Does that sound right?


> as opposed to Hotwire which either does full page dumb replacement or asks you to define which sections to replace

It's not that dumb in practice because for a lot of things Hotwire uses HTTP instead of WebSockets which means you can take advantage of what HTTP has to offer such as caching.

That means if you decide to dynamically load a menu's contents with a Hotwire Turbo Frame then it's only sent over the wire once and assuming its content doesn't change, it'll serve a 304 content not modified for future requests.

For pushing updates with Turbo Stream which is done over WebSockets, I'm pretty sure it'll push that snippet of HTML (let's say a user's comment) over WebSockets and then either append or prepend it to the DOM based on however you configured it to be inserted. And if you edited that comment later on, it will replace that snippet of HTML that was previously sent (since it's the same ERB template). It won't re-render the full page.


There are a lot of wonderful upsides to this approach, yes.

It’s just... people think those technologies are congruent but the overlaps are actually minimal.

For any rather sophisticated UI you can (and will want) to use both.

For example: repaint a data visualization. With Hotwire you can only replace it and start fresh, with SR you can just surgically morph data attributes without disconnecting your stimulus controllers


Exactly.

Basically all you to is to call a remote procedure, which you can do by adding a simple `data-reflex="click->Todo#toggle`. In the remote method you change something about the state (for example db, redis). The server rerenders the page and morphs the difference.

If you need more control you can get it by defining which elements to render and to morph.


They don't really have any overlap.

Hotwire is for replacing frames with content when navigating through anchors or form posts.

StimulusReflex is performing RPC, then diffs the old page and the new page, updating changed elements.


One difference is that liveview / reflex are stateful whereas Hotwire (turbo) is not. This has varying performance implications. Turbo will do repeat work server side and payloads will typically be bigger, however development may be simpler due to lack of state and memory usage server side may be lower.

Turbo also has the possibility to gracefully degrade when js is not available (although I doubt this will be taken advantage of much in practice).


This is a great point. Plus not all platforms, hosts, and proxies for that matter will allow web sockets.

Especially for an established rails app, allowing web sockets can require architecture changes.


I hope their form validation demo is just a toy and not an actual example of real email validation code, because it doesn't handle '+' in the localpart, which is a very commonly used character. I don't see any custom validation code in the demo source, though, so it kind of looks like they have a builtin "email" validator that's broken, which makes me question the production-readiness of this thing.


That was a regression in version 3.4, fixed here: https://github.com/hopsoft/stimulus_reflex/pull/418


FWIW, I'd add a word of caution for this architecture. Coming from an SPA, it feels just like your average react/redux app, except you put your redux state on the server. Your server now maintains the state of all active clients, and you get network lag on all stateful UI interactions.

Now that Google will index SPAs, I'd strongly consider a SPA where the server just generates meta tags (for SoMe link previews etc)


> you get network lag on all stateful UI interactions

Isn't this kind of a good thing, though? Now your UI can't lie to you about the true application state, making you think something worked or completed when in fact it's still interacting with the server. /s

I like SPAs because they can work offline / on spotty network connections. I don't like SPAs because they are often unclear about whether or not they are fully synchronized with their backend. I kinda wish people writing SPAs just wrote totally offline apps first that then had an independent synchronization mechanism with their respective backends as a general rule.


Does python have anything like this?


https://pypi.org/project/django-sockpuppet/

It's a SR clone, the maintainers are actually very active in our community :-)


or link to actual repo -> https://github.com/jonathan-s/django-sockpuppet

(I'm the maintainer).


More of a port of Laravel's Livewire (so only AJAX calls, no websockets), but I've been working on something similar for Django at https://www.django-unicorn.com/. I also detail other options at https://www.django-unicorn.com/docs/#related-projects.



This comment I have just made applies equally to Python as to Ruby I think:

https://news.ycombinator.com/item?id=25791181


What’s the missing feature? Native M:N green threads? Seems to me that Python’s async is a fair bit more mature than Ruby, so the comparison here is not obvious to me.


The conclusion I have come to is that the way you interact with the concurrency model is just as important as what the model is underneath. Erlang (and Elixir) have got both levels right - M:N scheduling underneath, and the actor model (with excellent library support) on top to best take advantage of it.


htmx [1] (formerly intercooler) is sort of similar, although the server instead returns html fragments.

Here's an example [2] of using it for infinite scroll (instead of pagination).

I'm pretty excited to try out django-sockpuppet from an adjacent comment!

[1]: https://htmx.org/ [2]: https://engineering.instawork.com/iterating-with-simplicity-...


Instinctively this looks like something that works great for simple concepts. Does anyone have any experience integrating this for a complex project or UI? Would love to hear more.


Has anyone used LiveView and this enough to give a comparison of the dev UX? I've mainly used LiveView for a side project and have quite enjoyed it.


In my experience, the latency is just too great on 3G or 4G with congestion.

It's 500ms to 1000ms for something that ought to be instantaneous like clicking on a tab that I have already seen.

React websites might be a larger initial download, but its only an extra 3 seconds wait to begin with, then near instant reactivity afterwards for everything that doesn't require a network call.

Ironically, the browser cache is much faster than 500ms so the tab demo would have been faster if implemented as a full page refresh.


Honest question - what’s the difference between this and Hotwire?


A tiny payload from the world's slowest backend framework.

The Rails community has spent years resisting the future. Ember was an attempt to jam Rails into JavaScript and it's been a miserable, confusing, slow mess that every team utterly regrets.

Rails has spent years and years pushing server-side rendered partials. Now the Rails community has yet another "new" approach that involves writing yet more Ruby instead of JavaScript.

If you adopt any of these Ruby-for-frontend solutions, your future efforts to scale will be severely hampered as you've glued so much stuff down in Ruby. Plus you'll have trouble hiring JS developers, because who wants to learn something so unserious as this?

Write your web frontend in JavaScript. Either be a polyglot or create silos.


Imagine that there are companies (like the one I work for) and projects that are absolutely NOT going to scale (maybe because they're somebody else's internal apps, which is what I do) and the company behind them will not have trouble hiring JS developers, because they're a Ruby shop.

So they like writing more Ruby instead of JavaScript. They've enjoyed Rails pushing server-side rendered partials.

And the person that comes demanding they rewrite all their frontend in the current JS framework-du-jour (possibly to be rewritten again in a couple of years) will be told to fuck right off.


You've just described my company! I struggled through rewrites of JS from jQuery -> Backbone -> Vue -> Webpacker + Vue until the "head of IT" went off to do marketing where he was better suited. Now that I have the reigns, we've been slowly removing as much JS as makes sense and we've never been happier, more productive and relatively bug-free.

But we still have the requirement of "near instant" front-end for certain things. And this is precisely the sort of thing that a team of RoR devs can really get behind and do well. Rather than try and cram yet another JS paradigm and DSL into their heads only to be forgotten when the next one rolls into town.

Personally I'm a Phoenix/LiveView champion, but we're a Rails shop and I know better than attempt The Big Rewrite. So this really fits the bill.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: