11 ms·
I think one of the unsolved problems of client-side interactivity on websites is how difficult it is to add it just a little bit of extra client-side functional
by Zanfa 5y ago
I think one of the unsolved problems of client-side interactivity on websites is how difficult it is to add it just a little bit of extra client-side functionality to a traditional server rendered website. For example, recently I had to deal with photo uploads on a Rails app, which works fine out of the box at first, until you want to show progress bars and uploaded previews etc. Then you add a couple of client-side Stimulus controllers, maybe a Turbo frame here and there and it works, but then you get to browser navigation and you're screwed, because none of this works if somebody were to submit the form, then navigate back. Now you have to implement lifecycle handling to account for navigation and once you're done, you've basically implemented a SPA, except it's broken into a mix of tightly-coupled Javascript, Ruby and ERB templates.
- beaconstudios 5y agoProgressive enhancement was largely solved before SPAs became a thing. Its quite easy to enhance the client side incrementally, but SPAs started out as useful for full on Web apps and now everybody uses them by default for some reason.
- hombre_fatal 5y agoExactly. I've been in the position various times where I'm embedding a JS app on a page to help the user do something highly interactive, usually creating/editing content. And then as it's expanding to integrate with other things on the site, I start to wish more of the site was in the JS-app side of things. Sometimes I realize a SPA would have simply served the user better, and it doesn't necessarily take much to be in that predicament. Too many people hate on SPAs by, presumably, just imagining static read-only content like blogs and news. Though I'm also a bit tired of "SPAs suck amirite, HN?" Put the user first, consider the trade-offs that work towards that goal, and see what shakes out.
- midrus 5y ago> Put the user first, consider the trade-offs that work towards that goal, and see what shakes out. In my experience, every single team I've been part of that was building an SPA was because they put the developer experience and desires first, even if in the mid/long term the dev experience ends up being worse as the project grows.
- Closi 5y agoI think the fundamental issue with SPAs is that it's building on multiple levels of technology that fundamentally weren't designed to support being a single page application. The browser <-> multiple pages paradigm is pretty much how the web evolved, so SPA's just end up being one giant hack to get everything working. UWP/WPF/any other desktop app framework demonstrates how easy developing a 'single page application' can be without all the cruft you have to add to make a SPA work because it's actually a sort-of-massive-workaround.
- efdee 5y agoIn my opinion, UWP/WPF/aodaf makes it easy because it just doesn't implement the things a user is used to in a browser (bookmarkability, back button, ...). If you ignore those things in your SPA, much of the "cruft" is negligible.
- kaba0 5y agoThis is pretty in line with grandparent’s comment in that the browser was simply not made for this - aka SPAs are sort of a hack on the traditional page-based approach.
- mike_hearn 5y agoMany desktop apps have back buttons, and of course mobile apps always have them. They're also more reliable; there is no desktop/mobile equivalent of the "warning: need to re-POST this form" problem. As for bookmarks, that's semi-right, but the web platform conflates the back button with bookmark-ability in ways that are quite confusing. If you want the back button to get the user out of your settings screen, then you must push a new URL onto the history stack using JavaScript, but then if the user bookmarks your site they'll bookmark the settings screen specifically even though that's very unlikely to be what they wanted. Non-web apps that have enough content to need something like bookmarks often implement a similar mechanism that's more predictable, albeit less general. The OPs article is really a common lament amongst web developers - they're (ab)using a tool that was never meant for what they're using it for. It's a real and very serious problem in our industry. The whole SPA vs multi-page dichotomy really emerges because the web doesn't have sufficiently rich, modular or low level APIs. If you look at non-web frameworks like iOS or Java then you get a huge number of APIs (usually classes) tackling the low levels of a problem, then more classes building on the lower levels to give you higher level solutions. Those classes can usually be customized in many different ways, so the amount of control a developer has is enormous. If you start with a high level helper class and find you can't customize it to meet your needs, you can reimplement it using the lower level building blocks. The web isn't like this. Web APIs are an absolute pigs ear of very high level function calls and classes designed in more or less random ways to quickly hack together a solution to whatever need a browser maker had at the time. HTML5 supports peer-to-peer video streaming and augmented reality but not a virtualized table view. In many cases it's obvious that little or no thought went into the APIs, e.g. XMLHTTPRequest has nothing to do with XML, you can open a URL for a custom URL handler but not detect if that URL will work ahead of time, nor even if opening that URL worked once you try it, and so on. Instead of starting with low level APIs and composing them into high level APIs, browsers start with high level APIs and then introduce entirely orthogonal low level APIs decades later, or never. These sorts of problems just don't occur when writing desktop apps with professionally designed frameworks - even in the rare cases that you hit some limit of the framework, you can (these days) just patch it directly and ship a fixed version with your app. If you hit a problem in the browser you're just SOL and have to hack around it. Our industry needs to reinvigorate desktop apps. Attempting to convert browsers into Qt/Java/.NET competitors has: a. Made HTML5 unimplementable, even by Microsoft. It's not so much a spec anymore as a guide to whatever Chrome happens to do on the day you read it (hopefully). b. Created tons of security holes. c. Yielded an atrocious and steadily decaying developer experience.
- 9wzYQbTYsAIc 5y ago> Exactly. I've been in the position various times This is why React is such a popular JavaScript framework of libraries.
- vlunkr 5y agoThe other thing people who hate SPAs need to think about is that rendering blogs/news/static sites isn't a problem that developers really work on anymore. Businesses will just pick from the huge pile of existing CMSs or hosted solutions because it's easier and cheaper. So if you're wondering why all these developers are building SPAs, it's because we're building custom applications, not blogs.
- michaelchisari 5y agoSetting limits for future features to keep the code base clean and manageable is something developers could be more vocal about. Acquiescing to every demand product designers and management throw into the mix is what turns beautiful, easily-maintained codebases into nightmares. What people are talking about here is writing web apps as a series of small, tightly-coupled spas who manage state within very specific parameters. And that's a great way to build software. Until someone comes in and asks you to draw in the state from one section into two other sections. You have the choice to say a) no and explain why, to b) create a clever "glue" that will be hard to maintain and difficult to explain, or to c) take the time to refactor the code into something more general and complex to allow for the feature on a more abstract level. Guess which one almost always gets chosen. The upshot is this: The solution to front-end complexity may not be a technical one, it may not require a new framework or library. It may be a shift in what we expect out of the web. We could always temper our expectations in order to keep our code clean.
- themanmaran 5y agoThe end goal of writing code isn't always a "clean and manageable" codebase. Likewise the solution to SPAs isn't "say no to features".
- michaelchisari 5y agoI'm aware, but the discussion about the failures of spas always center around their failures in maintainable code. So if one's issues with SPAs are codebases becoming unmanageable, the solution won't be technical, it's going to be managerial. A start would be devs communicating to product & design what the technical limits are to the current approach so that it informs their decisions.
- thr0wawayf00 5y agoThis is my biggest gripe with the direction of Rails. I completely understand the historic reasons for wanting to keep JS to a minimum and stay within ERB/Ruby, but the JS component-driven UI pattern feels like the correct front end architecture for most commercial projects these days, especially now with better JS tools like Svelte, which feels like rails for the front end to me. I started playing around with InertiaJS recently and I absolutely fell in love with it. I was surprised to see how niche it still is because it's pretty much what I've dreamed what writing JS with Rails could be for the last 5 years.
- te_chris 5y agoPhoenix LiveView really does solve a lot of these problems.
- ordinaryradical 5y agoI was just going to say this sounds like a great example of something that Elixir, LiveView, plus maybe a little Alpine.js could handle...
- myfavoritedog 5y ago
- jeremyjh 5y agoIt does and it has lots of work-alikes on other platforms (though some are not nearly as good). For almost any app that is inherently useless when not connected to the server, its a pretty good fit.
- rk06 5y agofor simple cases, you can use alpine.js, petite-vue etc. However, if you are considering "routing", then it is no longer a "little bit".
- xwdv 5y agoThis problem you described is exactly why SPAs will continue to dominate over the traditional server rendered websites. Often when I see people arguing against SPAs, they are peddling trivial toy websites that don’t do much and don’t change much. When you need to build a serious application on the web with quickly growing feature sets and complex state management, just use a SPA. It’s 2022.
- jmconfuzeus 5y agoThe Basecamp guys created Hey which is a mail app not implemented as a SPA. It's probably the fastest mail app I've ever seen while delivering around 40kb of javascript. If Hey is a toy app you then you must be working on some truly alien projects from the future or something.
- enra 5y agoWhile it might be fast, it feels you’re like using Rails app with turbo links. Page loads. Feels barely interactive. Compare native Mail app and Hey. If anything should be a SPA, it’s an email app. Also who cares how much kb of JavaScript your mail app uses? It’s completely wrong metric to optimize for an app someone uses every day, multiple times a day and likely has the app open all the time. (Also haven’t heard people using Hey much since the launch)
- boomlinde 5y agoSPAs dominate? Off the top of my head I can't think of a single SPA that I actually use regularly. I worked in a niche a few years back where they seemed common (configuration interfaces for embedded systems) but looking at my own habits and the sites that dominate in terms of web traffic, that's thankfully not something that has caught on generally. I can sort of see the point if the "A" part of "SPA" actually applies to your product, but for the dominant players that doesn't seem to be the case.
- mattwad 5y agoI feel like most people that hate SPAs never have to deal with this type of thing, or even only have to work on the backend. They just don't get it. Of course, if you're using a SPA for a static website, you're also doing it wrong but that doesn't mean SPA itself is a bad thing.
- zippergz 5y agoI'm living proof that it is possible to simultaneously hate SPAs and understand why they are popular. I've built and worked on a number of them, I don't have a better alternative to recommend, and yet I still hate them because I think they are a clunky solution to the problem. We need something better, but I'm not smart enough to come up with what that should be.
- deleted 5y ago[deleted]
- kitsunesoba 5y agoI don't think I'm any more smart when it comes to this particular issue, but my thought is that the answer probably has something to do with more primitives that are suited for web applications being provided by web browsers, so it's both easier to build a web app without some huge gangly framework and so frameworks have more to build on top of and less manual footwork introducing room for error.
- rosenjcb 5y agoI agree. These people hating on SPAs are mostly not frontend developers. They're backend devs that think returning an HTML page is all you need to do. Modern websites are very complex.
- WillPostForFood 5y agoOr users who hate watching a whole application load to display some text.
- CPLX 5y agoYeah can someone fix this please. I'm experiencing the same thing with a rails app I'm currently building. In all seriousness it feels like there must be an elegant way to do more responsive modern functions while keeping the core server rendering concept. It's 2022 after all. But no I don't know a good solution either.
- adfm 5y agoHTMX lets you update the url with hx-push-url=“true”
- garyrob 5y ago"I think one of the unsolved problems of client-side interactivity on websites is how difficult it is to add it just a little bit of extra client-side functionality to a traditional server rendered website. " I've started using django-unicorn lately and I'm hopeful that it may solve that problem for many use-cases.
- ysavir 5y ago> Then you add a couple of client-side Stimulus controllers, maybe a Turbo frame here and there and it works fine, but then you get to browser navigation and you're screwed, because none of this works out of the box if somebody were to submit the form, then navigate back. Now you have to implement lifecycle handling to account for navigation and once you're done, you've basically implemented a SPA, except it's broken into a mix of tightly-coupled Javascript, Ruby and ERB templates. Where in this process did you need to start adding navigation via JS? Did that functionality really require JS, or was it implemented that way just because other parts are JS, and the trend was continued? Could you have used Stimulus controllers to manage functionality on the page itself, but when it came time to navigate to a new page, just done a basic browser redirect? Saying that SPAs is a mistake doesn't mean that a strong dependence on JS or frameworks in a mistake. It just means that trying to make an entire site fit into a single page load introduces more costs than savings. You can still have pages controlled via React or Vue or Stimulus, but forgoing the router functionality. In my own apps, I use Vue and VueX to control page behaviors, but each URL is its own Rails page. For example, I have a search page that uses Vue and VueX to asynchronously load, filter, and display search results. Clicking on a result is a basic browser redirect, taking you to the result's page, doing a full Rails page load, and again using Vue and VueX to manage any dynamic state (any static content is rendered via ERB files). This has created a very clear and simple structure that allows each page to have any dynamic functionality it needs, but no complications from having to maintain navigation or browser history via JS. The browser already does that natively, and I get to spend my time working only on actual features--not recreating the browser's built-in functionality, or debugging my own take on it.
- Zanfa 5y ago> Where in this process did you need to start adding navigation via JS? Did that functionality really require JS, or was it implemented that way just because other parts are JS, and the trend was continued? Could you have used Stimulus controllers to manage functionality on the page itself, but when it came time to navigate to a new page, just done a basic browser redirect? In my specific example, the navigation itself didn't happen through JS, but you need to hook into navigation APIs to handle backing into a partially-filled form after submitting to rebuild the UI to reflect the state before the user hit submit. To make things even more fun, Turbo/Stimulus (sometimes?) breaks bfcache in Safari & Firefox so they behave different from Chrome. Personally, I detest the vast majority of SPAs, especially the ones from Google, Facebook and Linkedin. Not even sure what they do to make them so horribly slow to use.
- amelius 5y agoYes. The fitness of an architecture can be partially measured by looking at the cost of feature updates.
- kaba0 5y agoIt was probably never too beautiful of a technique, but JSF does solve this problem splendidly. You basically have a view-flow besides the usual ones and it can act in many of the ways SPAs can.
- embwbam 5y agoI agree. I've been thinking about this lately, and have implemented something I think is interesting in Haskell. https://github.com/seanhess/juniper https://github.com/seanhess/juniper It's an implementation of Elm (imagine React if you're a JS dev), but all logic is executed on the server. State is passed back to the server whenever you choose to listen to an event. The view is then re-rendered and virtual dom diffed on the client. Non-interactive pages are just views. If you want them to be interactive, you add a Message an update function. I used it on a client project and it was pretty delightful. It probably isn't documented well enough yet to make total sense, but I think it's a step in the right direction.
- mdoms 5y agoAt the risk of a pile on, this is what jQuery was brilliant for. And frankly the native browser APIs have caught up enough that scenarios like what you want to achieve are simple to implement with just a script tag and a sprinkling of JS. I don't know what "Stimulus controllers" or "Turbo frames" are but they don't sound necessary.
- specialp 5y agoYes. Nobody should have to make a SPA to accomplish what JQuery did with sprinklings of JavaScript. JQuery was maligned because many people used it to make all XHR requests all over the place resulting in non-deterministic async behavior. JQuery was made to make adding small bits of JS easy and work in almost all browsers. Bringing in React and turning that non-deterministic events firing all over the place greatly improved that situation, but this has become if someone needs JS, bring in SPA framework. This is in spite of the browser world getting much better. So just as JQuery was used to make SPAs to bad effect, SPA frameworks have been used to do minimal JS actions in a bad way.
- dlisboa 5y agoThe problem is the mixing and matching of state management. In a traditional web app all of the state is in the back end, in a SPA all of the state is in the front end. When we share state in between the two it's often messy. To me the answer feels like it should be "traditional web app for most things, components-as-first-intended for some things". The simplest React example is just one component that abstracts presentation and logic. The only state is its own. It does not handle an entire web app as a SPA, no Redux, prop drilling, it's just the idea of a reusable component as an HTML tag. Same with VueJS and all. If we restrict ourselves to that we're in the good path. If there was already an HTML tag for your own specific problem, wouldn't you just use it in your traditional server-rendered app? A `<photo-upload url="/photos">` tag that does exactly what you want. Or a `<wizard pages=5 logic="com.domain">` tag. We should create just those components, either in React/VueJS/Whatever or in vanilla JS Web Components, and live with the rest as we used to. We're basically saying that some parts of our apps are too difficult to mix and match state management, and we should offload all of the state to one of the two sides. In some rare apps indeed all of the state should be on the front end, but the use cases for that are just not as big as they're made out to be.
- prmph 5y agoExactly, the best approach seems to be where the app is composed of traditional pages with server navigation between them, but each page is implemented as an SPA. This approach eliminates the need for a client-side router, keeps any centralized page state small, and improves the SEO and bookmarkability of the app. I have implemented this architecture in several projects, and it’s effective
- WillPostForFood 5y agoDo you lose performance because each page has to load the SPA?
- prmph 5y agoNot much, if you use dynamic loading for heavy functionality that may not be used.
- alskdjflaskjdhf 5y agoInertia [1] is an interesting project in this space that might solve some of your problems. I haven't used it, but I believe the general goal is to make it easy to "plug in" client-side frameworks (React, Vue, Svelte) into server-side views. [1] https://inertiajs.com/ https://inertiajs.com/
- jmconfuzeus 5y agoProgress bars and previews are simply a matter of attaching an events to the http request and file input respectively. When someone submits a form and navigates back, don't you just re-display the empty form? If it needs to be a form bounded with the uploaded file (maybe as part of a wizard), then why not ask the server for it instead of storing client side state? Maybe using Javascript without a SPA looks hard because you're trying to avoid storing state on the server as well as bypass native browser features.
- simonw 5y agoThis is what jQuery solved. It made it ridiculously easy (compared to not using jQuery at that time) to add a little sprinkle of progressively enhanced JavaScript to a page. It still works today (and you don't even need jQuery now, as browser standards have mostly caught up), but everyone seems to have forgotten how to do it!
- MourningWood 5y agoteach me :)
- pvorb 5y agoDid you have a look at https://htmx.org/ https://htmx.org/ ? I think it solves the "just a tiny bit of interactivity on an MPA" kind of thing.
- camjw 5y agoI feel like react-rails (https://github.com/reactjs/react-rails https://github.com/reactjs/react-rails) is basically perfect for this. You just make the photo upload its own react component and render it as normal from your rails view. You basically encapsulate the small bit of complex state into a component and it doesn't infect the rest of your app with SPA.
- pier25 5y agoI think the best solution for this is just doing fullstack dev with SSR + partial hydration. The issue is that, so far, we haven't figured out how to have a good fullstack DX. Remix is probably one of the best attempts so far, but it still leans heavily towards being a very sophisticated renderer for the front end. The proof is you probably would not use Remix to create a 100% backend project with no front end. Same with SvelteKit or Next. Until fullstack frameworks get more serious about the backend, we will be in this weird limbo. In my current project I use Fastify as my main backend framework, and then use Svelte for SSR + hydration. I loose a lot of the frontend sophistication that SvelteKit brings to the table, but OTOH I have an amazing backend framework and total control and flexibility.