[HN Gopher] StimulusReflex, or LiveView for Rails ___________________________________________________________________ StimulusReflex, or LiveView for Rails Author : nanna Score : 179 points Date : 2021-01-15 11:41 UTC (11 hours ago) (HTM) web link (docs.stimulusreflex.com) (TXT) w3m dump (docs.stimulusreflex.com) | cpursley wrote: | 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? | freedomben wrote: | 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 | hpvic03 wrote: | The Ruby/Rails ecosystem is massive, and remains extremely | productive and pleasant to work with. | sodapopcan wrote: | 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. | fareesh wrote: | 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. | [deleted] | wim wrote: | 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? | sodapopcan wrote: | 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 | nickjj wrote: | > 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. | e12e wrote: | > 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?). | Existenceblinks wrote: | 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. | sodapopcan wrote: | 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). | wim wrote: | 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. | sodapopcan wrote: | 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. | [deleted] | benzible wrote: | 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 | heleninboodler wrote: | 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. | rolae wrote: | That was a regression in version 3.4, fixed here: | https://github.com/hopsoft/stimulus_reflex/pull/418 | adenozine wrote: | Does python have anything like this? | adparadox wrote: | 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. | julianrubisch wrote: | https://pypi.org/project/django-sockpuppet/ | | It's a SR clone, the maintainers are actually very active in | our community :-) | shinryuu wrote: | or link to actual repo -> | https://github.com/jonathan-s/django-sockpuppet | | (I'm the maintainer). | m4r71n wrote: | Django does: https://github.com/edelvalle/reactor | tbran wrote: | 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-... | rkangel wrote: | This comment I have just made applies equally to Python as to | Ruby I think: | | https://news.ycombinator.com/item?id=25791181 | theptip wrote: | 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. | rkangel wrote: | 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. | Robin_Message wrote: | 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.) | hpvic03 wrote: | 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. | Robin_Message wrote: | 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. | treis wrote: | 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. | sodapopcan wrote: | 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!) | k__ wrote: | Isn't Reflex a Haskell framework? | | Switching from React to Reflex isn't just switching a | framework, but a whole stack. | [deleted] | cargoshipit wrote: | 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. | thomasjk wrote: | 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/ | [deleted] | augustl wrote: | 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) | IggleSniggle wrote: | > 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. | lawwantsin17 wrote: | The docs are so full of opinions and sales speak it's disgusting. | miki123211 wrote: | > 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. | akanet wrote: | 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. | amoitnga wrote: | 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. | tra3 wrote: | 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. | joelbluminator wrote: | 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! | raffomania wrote: | 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! | whalesalad wrote: | 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. | freedomben wrote: | 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. | rorykoehler wrote: | The JavaScript framework era always felt like a bandaid | while we figure out something better. I'm convinced | liveview is the future. | sodapopcan wrote: | 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. | ericb wrote: | 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 | porker wrote: | > 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. | anonygler wrote: | 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. | rkangel wrote: | 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". | bestinterest wrote: | 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. | deedubaya wrote: | I've had good success with AnyCable | jakswa wrote: | 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. | julianrubisch wrote: | I'm really excited for Ractors in this content and how/if | they could improve the Ruby side | ksec wrote: | I remember there were still latency issues, with 99th | percentile being well over 100ms. | | Cant find the link to the article though. | bpicolo wrote: | > 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? | PedroBatista wrote: | 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. | scns wrote: | Wish? | PedroBatista wrote: | thks | dnautics wrote: | 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. | entangled999 wrote: | So in your opinion in Java land resources are always leaked | when some exception occurs? That's a bit far from the truth | pibefision wrote: | Russ Hanneman feels positive about stimulus reflex | https://www.youtube.com/watch?v=utxCm3uLhIE | wes-k wrote: | Ha that was well worth the watch, ty! | bithavoc wrote: | How did they get the actor to play this, amazing. | [deleted] | arusahni wrote: | Assuming Cameo? | julianrubisch wrote: | It's called ,,money" | sudhirj wrote: | DHH recently introduced Hotwire https://hotwire.dev/ which | already does something similar. Any idea what the difference is? | julianrubisch wrote: | in one word: morphdom (https://github.com/patrick-steele- | idem/morphdom) | | also, StimulusReflex predates Hotwire for 1 year and is already | pretty hardened :-) | sudhirj wrote: | 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? | nickjj wrote: | > 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. | julianrubisch wrote: | 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 | rolae wrote: | 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. | joelbluminator wrote: | Well Hotwire is running on Basecamp (or Hey?) , its not some | half arsed solution... | julianrubisch wrote: | For sure! It just doesn't really overlap. | [deleted] | HorizonShadow wrote: | 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. | agd wrote: | 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). | freedomben wrote: | 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. ___________________________________________________________________ (page generated 2021-01-15 23:02 UTC)