11 ms·
> And most of them don't spend the time to implement HTML5 history properly, so they break the URLs - which means you can't bookmark or deep link into them and
by com2kid 5y ago
> And most of them don't spend the time to implement HTML5 history properly, so they break the URLs - which means you can't bookmark or deep link into them and they break the back/forward buttons.
The majority of routers for React, and other SPA frameworks, do this out of the box. This has been a solved problem for half a decade at least. A website has to go out of its way to mess this up.
That aside,
SPAs are great for a number of reasons:
1. You aren't mixing state across server and client. Single Source of Truth is a thing for a good reason. If you have a stateful backend, and your front end naturally has the state of whatever the user has input, you now have to work to keep those two in sync.
2. You need a beefier backend. A SPA backed by REST APIs is super easy to scale. nginx can serve up static resources (the JS bundle of the site) LOLWTF fast, and stateless REST apis are easy peasy to scale up to whatever load you want. Now you just have to worry about backend DB, which you have to worry about with non SPAs anyway.
3. Less languages to deal with. If you are making a modern site you likely have JS on the front end, so with SPA you have JS + HTML. With another backend framework you now have JS+HTML+(Ruby|Python|PHP|C#|...), and that back end code now needs to generate HTML+JS. That is just all around more work.
I agree some sites shouldn't be a SPA, a site that is mostly text content consumption, please no. A blog doesn't need to be a SPA. Many forums, such as HN, don't need to be a SPA.
But if a site is behaving like an actual application, just delivered through a web browser, then SPAs make a ton of sense.
- manigandham 5y ago1) JS history handling is fragile. A single error can break navigation completely. There's no built-in loading indicator so sites are left with no feedback or have bloated progress bars. And nothing automatically solves for deep links if the app doesn't use routes for different views or relies on other events instead of hyperlinks. 2) Servers are very fast and assembling HTML is trivial. Browsers are optimized for downloading, parsing and rendering HTML as it streams in. Using JS to write HTML after making multiple network calls is objectively slower than a single network request that assembles everything on the server close to the datastore with minimal latency. 3) Every other language is faster and more capable on the server than JS, and all major web frameworks have modern component-based UI templating. Interactions with roundtrips are just fine, and some light JS can handle most other scenarios. > "an actual application" That's the only reason to use a SPA, not what you mentioned.
- chrismorgan 5y agoClient-side routing for page-oriented stuff is certainly not a solved problem: the basics, sure, but not actually doing it properly. There are some parts of the experience that it’s not possible to do perfectly because the web doesn’t expose the necessary primitives, and exceptionally few things go beyond the basics of just clobbering and resetting scroll position on back/forward. To do it properly, you need to restore all transient UI state (form field contents/state, scroll positions, focus, selection, media playback position; zoom level, probably not implementable; and there may be more, though I don’t include things like <details open> as transient state since that’s put into the DOM) on back/forwards, and I don’t know if I’ve seen anything actually do that. Then there’s the matter of helping accessibility tech to realise a page change has occurred, and I’m not sure of the state of the art on that, but last time I looked (some years ago) I think it was bogged down in unreliable heuristic land rather than actually being solved.
- gortok 5y ago> . You aren't mixing state across server and client. Single Source of Truth is a thing for a good reason. If you have a stateful backend, and your front end naturally has the state of whatever the user has input, you now have to work to keep those two in sync. Why would I want to keep any state on the client? What in the history of the web (the whole idea being its someone elses computer) would make it a good idea to take away the one major selling point of the web? That no matter what, someone else has the state I need, and I never have to worry about losing that if something happens to my connection. It either went through or it didn't.
- the_gipsy 5y ago> The majority of routers for React, and other SPA frameworks, do this out of the box. This has been a solved problem for half a decade at least. A website has to go out of its way to mess this up. 99% of SPAs break history related features in some way.
- ozim 5y ago99% of people don't FRICKING care. Most of the users I have to deal with still have problems with double clicking. They don't understand basic browser features. They don't understand that they can set preferred language in their browser. History related features are not an argument in any way.
- manigandham 5y agoWhy would people not care that browsing URLs work well?
- ozim 5y agoBecause they don't care about computer stuff. They just have to do computer stuff because they are forced to.
- manigandham 5y agoThey do care that it works. That's the point being discussed.
- CRConrad 5y agoShit you gotta do not because you want to but because you have to, you care even more that it works without hassle. This is so obvious that not seeing it is weird, and claiming not to see it is weirdly defensive.
- the_gipsy 5y agoThey do care if the experience doesn't work right, even if they don't understand why.
- freedomben 5y agoI agree with all your points, but I think it's worth pointing out that those benefits you mentioned are largely for the developers. As a consumer I love a well-written SPA when the problem set calls for it, but most of the SPAs I have to use are garbage. I don't fault the tech for that, although I suspect that a lot of those SPAs were created by "me too" people that just wanted to build a SPA. When React was in the pre 1.0 days, I did that, and several people on my team as well (so I'm not casting any stones here, just trying to state facts). Last time I bootstrapped a React SPA I don't think cra includes a router ootb.
- midrus 5y ago> but most of the SPAs I have to use are garbage As an example, look at reddit. I'm still using old.reddit.com because I can't stand their fancy SPA UI. It is so bad to the point, as a user, I enjoy a lot more HN's interface than reddit's one.
- simonw 5y ago"A website has to go out of its way to mess this up." I know it's supposed to be easier, but I keep seeing teams mess this up.
- tracker1 5y agoI can say I've seen a lot of state management issues with SPAs... more with Angular than React, and almost none when using React+Redux well. I think a part of this is that a lot of developers simply don't desire, want to, get to or otherwise take the time to understand the framework they are using... It has been true forever... I can't tell you how many times I've seen stuff copy/pasted from StackOverflow, by devs that don't understand what they're doing, or they add jQuery to a React application, and have goofy interactions. The lack of understanding will always be a thing, you have to learn, most learn by doing, and when starting out, you don't know that what you are doing isn't good, but it kind-of works.
- gefhfffh 5y agoTried ngrx?
- tracker1 5y agoYeah... it's decent, but there are many, many other reasons why I'll never touch an Angular app again.
- com2kid 5y agoReact+redux well is a huge if. Last time I used redux, about 4 years ago, every tutorial on it demonstrated a completely different way of using it. I spent a week piping a couple dozen form inputs through redux. Throw typescript in there and life got more complex. Maybe it sucks less now. But I've seen plenty of websites where every key press causes crap tons of state to get copied around because "lol const only". I've seen sites where typing takes a second per character due to mis use of redux, and the problem with redux is that it is easier to misuse than to use properly.
- WhitneyLand 5y agoAll of your benefits seem to come from using only rest APIs to drive to site. That alone can be done with any site, but SPA usually implies more.
- scarmig 5y ago> You aren't mixing state across server and client. Single Source of Truth is a thing for a good reason. If you have a stateful backend, and your front end naturally has the state of whatever the user has input, you now have to work to keep those two in sync. This is a bit weird to me, in that I'd say that cuts in the opposite direction. State can exist in at least three locations for most applications: db, app server, and client. Keeping state consistent across all of them can be difficult in the best of times, but thin clients by their very nature carry less state, lessening the burden. Sometimes client state is necessary, for richer user interactions, but for all but the most cosmetic of purposes you're going to have to replicate that state on the backend anyway, to enforce business and security requirements.
- westoncb 5y ago> but for all but the most cosmetic of purposes you're going to have to replicate that state on the backend anyway, to enforce business and security requirements. This really just comes down to what you're writing, how app-like your web app is. It's too easy to have one's own experience focused in a certain area and estimate the remaining majority as relatively similar. (For most of what I personally work on, the DB portion is mostly a simple straightforward serialization of what the user has built through the application; whereas client-side state has so many aspects to it I couldn't give a brief characterization—the whole app is basically client-side.) From what I can tell most of the disagreement about SPAs results from devs who are building things that aren't app-like railing against their futility vs devs who are, who become perplexed by the vitriol when they have immediate experience with their architectural benefits.
- shkkmo 5y ago> From what I can tell most of the disagreement about SPAs results from devs who are building things that aren't app-like railing against their futility vs devs who are, who become perplexed by the vitriol when they have immediate experience with their architectural benefits. The SPA criticics from the article and this thread have repeatedly said that their issue is not with building things that need the benefits an SPA architecture brings. The criticism is that the majority of SPAs are harmed by that architecture because it is the industry default and being used when it isn't appropriate.
- tepitoperrito 5y ago> The majority of routers for React, and other SPA frameworks, do this out of the box. This has been a solved problem for half a decade at least. A website has to go out of its way to mess this up. They might not mess up history when using a standard routing library, but I've seen plenty of devs forget to add unique titles to different pages which is frustrating for a user with multiple tabs going. On SO the accepted answer for react-router looks like "create a custom Page component with title as a prop"[0]. At work I just ask folks to use react-helmet. [0] https://stackoverflow.com/questions/52447828/is-there-a-way-to-modify-the-page-title-with-react-router-v4 https://stackoverflow.com/questions/52447828/is-there-a-way-...
- bcrosby95 5y ago> 1. You aren't mixing state across server and client. Single Source of Truth is a thing for a good reason. If you have a stateful backend, and your front end naturally has the state of whatever the user has input, you now have to work to keep those two in sync. If this were true, you wouldn't need a REST API. I don't understand what you're trying to say here. When you make a REST call to get data, you instantly have two different sets of state: the client and the server. It's no different from SSR, it's just transmitted in a different data format (json vs html). > 2. You need a beefier backend. A SPA backed by REST APIs is super easy to scale. nginx can serve up static resources (the JS bundle of the site) LOLWTF fast, and stateless REST apis are easy peasy to scale up to whatever load you want. Now you just have to worry about backend DB, which you have to worry about with non SPAs anyway. You do the exact same thing with SSR. Stateless shared nothing app tier instances. Been doing it for 15 years now. > 3. Less languages to deal with. If you are making a modern site you likely have JS on the front end, so with SPA you have JS + HTML. With another backend framework you now have JS+HTML+(Ruby|Python|PHP|C#|...), and that back end code now needs to generate HTML+JS. That is just all around more work. You can use JS on both the frontend and backend. Or ClojureScript. Or TypeScript. I'm sure there's others. But yes, for many languages this is a potential negative of SSR.
- tracker1 5y agoRegarding a rest call (#1) being out of sync ... usually the "state" is in the database... if you're using SSR, it's still a separate context of state than what may be in the database a fraction of a second later.. and if you wish to keep that in sync, you're still going to need JS, or some other goofy hacks to do so.
- lmm 5y ago> If this were true, you wouldn't need a REST API. I don't understand what you're trying to say here. When you make a REST call to get data, you instantly have two different sets of state: the client and the server. It's no different from SSR, it's just transmitted in a different data format (json vs html). SSR means you don't have a clear representation of the client-side state (as distinct from the presentation) - by definition you render on the server and only serve the view layer to the client, whereas your data model only lives on the server. There will naturally be state in the client (e.g. form inputs), but you don't have a good representation of that in your model. > You do the exact same thing with SSR. Stateless shared nothing app tier instances. Been doing it for 15 years now. OK so where does the UI state live - not the long-term persistent entities, but things like unvalidated form input, which tab is enabled, which step of an in-progress wizard the user is on? Either you manage that on the client (at which point you're halfway to an SPA, and getting the worst of both worlds), or you manage it in the application layer on the server (in which case you have all the scaling issues), or you make every UI change go all the way into the data layer which has even bigger performance issues.
- s17n 5y agoThis is missing the real reason that people write SPAs, which is that React solved web components, which are hugely beneficial for almost 100% of web sites, and thus became the standard for building web sites, and with React it's easier to make an "SPA" than to make a "traditional" site and users don't know or care either way.
- sjs 5y agoUsers care they just don’t know why many modern websites are bad websites. Every website is now an app whether that actually makes it better UX or not.
- lmm 5y agoWicket has offered a beautiful component approach for over a decade now. Having seen it I can't stand page-oriented MVC frameworks (indeed it's good enough that it convinced me that OO actually has some merit in some cases).
- manishsharan 5y agoI used Wicket quite extensively about 10 years ago so my comments may not be true anymore. I began using Wicket as it was so much better than Struts and JSF. However, the development of new custom widgets in Wicket was so much more convoluted than implementing the same widget in Backbone.js. And it was hard to inject new functionality into and existing page. I eventually refactored all my UI code into jquery+ backbone.js ( this was before React ) and that code is in production and still working. And the new developers maintaining it don't see any reason to refactor that into React or Vue.
- lmm 5y ago> However, the development of new custom widgets in Wicket was so much more convoluted than implementing the same widget in Backbone.js. Hmm, I found developing custom widgets was a joy, though the key was to keep them very small and compositional - e.g. if you want a user details widget with an address entry, it's probably best to make that address widget its own smaller widget that the user details widget just uses - and aligned with your model hierarchy. Often you end up with a parallel hierarchy where e.g. you have a user model that contains an address and phone number, so you've got a user display widget whose model is that user object and in that there's an address display widget whose model is the address field of that user object (and similarly for your edit widgets). I tried to look up examples of what doing the same thing in Backbone.js looks like, but the search results don't seem to be about making custom widgets as I understand it. To be fair I'm struggling to find examples in Wicket as well. But I'd be interested to hear what it does better. > And it was hard to inject new functionality into and existing page. Hmm, what kind of functionality do you mean? I will say that again making pages very compositional was key - my team settled on a pattern where most of our pages were just a single top-level panel (so you could always reuse or embed a whole page if you wanted to) and then most panels were made of a handful of smaller panels, similar to the clean code style where you try to make each function only call three or four other functions. And then it was easy to change whatever we needed because the code structure corresponded directly to the logical business/model structure and the inheritance structure corresponded to the visual structure (e.g. we had an abstract class for what an "editing panel" looks like and all our editing panels inherited from that. So if you want to add a new field to the user model, you add it in the user model and the user display panel and user edit panel are right next to that. And if you want to change the visual design of all our editing panels, you change that in the parent component and it will apply to all of them).
- lolinder 5y agoYour arguments seem to be assuming a particularly bad implementation of a traditional backend. 1. A good server-generated-HTML backend will have no more state than a good server-generated-JSON backend. The client state is all stored in the client either way, whether in JS variables, HTML tags, or the URL. 2. A good server-generated-HTML backend doesn't do significantly more work just because its output is in HTML instead of JSON. A bit of extra text generated isn't going to increase your CPU load in any meaningful way. 3. There are only fewer languages to deal with if you aren't in charge of writing backend code. If you're in charge of the backend code, you still have to pick a backend language for your JSON API. I think you're assuming that the choice is "SPA" or "messy stateful monstrosity". It's perfectly possible to build a RESTful HTML-based API that is as clean and stateless as any JSON API. PHP's been starting each request with a clean slate for decades.
- gefhfffh 5y ago> a bit of extra text Doesn't really sound like an application, but a website. In a web app it can happen that you use it for an hour without the backend doing a single thing. > There are only fewer languages to deal with if you aren't in charge of writing backend code. You don't have to deal with them at the same time
- midrus 5y agoThere is no black or white here. 98% of every site is in between those things and you could consider them one way or the other. Is reddit a website or an application? is a backoffice dashboar a website or an application?. The problem with SPAs is not the technology or the architecture itself. The problem is everyone thinks, by your own definitions, they are building an "app" by default. I've already worked for several teams which struggle to get almost anything done and everything takes ages to ship because of the fanaticism of using React for everything. God, some didn't even know you could submit a form without building a json API endpoint.
- CRConrad 5y ago> Doesn't really sound like an application, but a website. Yeah, well, from the name of it, doesn't that sound like what the Web is for? I mean, we already have systems to run applications on; they're called operating systems. Not only SPAs but "web applications" as a whole are a mistake IMO.
- tored 5y ago2. Hard to believe that is true in the general case. Typical scenario for SPA is to use some sort of REST API, these API:s are usually designed for general usage, not specific usage, i.e. designed to be reused between components and views thus they basically return everything of a specific model regardless if data is needed or not. Therefore the controller queries the database with the equivalent of SELECT * on a table (or perhaps multiple tables with joins) and then exposes every field. And in many cases one request is not enough because the common generic design of REST APIs, thus a few request more are fired that results in multiple SELECT * against the database, and eventually the equivalent of SQL JOIN is performed in JavaScript. Already SPA solution has an increased cost by asking for data that is currently not needed, not only in the traffic between the database and the backend but also in the traffic between the backend and the frontend. And because we want to be good REST citizens we sprinkle the JSON payload with timestamps, resource urls and pagination information and what not and in majority of cases never to be used. Comparing that to SSR where you can fetch what you need from the database with custom SQL query (I hope you do, otherwise the SQL leprechaun will make a visit). Just imaging how much data there is on the web that is requested and then just discarded, not even looked at. It is possible to design custom REST endpoints for each component, but then of course what is the point of a SPA then? If you are already writing a custom REST endpoint just return HTML instead of JSON and then swap in the new and swap out the old for your component (one-liner), the end result is the same. SQL -> (Array of) object(s) -> JSON -> Javascript (Array of) object(s) -> HTML can therefore be shortened to SQL -> (Array of) object(s) -> HTML 3. That doesn't make any sense, number of languages are still the same regardless.
- nrb 5y agoGraphQL is such a quality of life upgrade coming from this environment, especially at the scale where your frontend teams are potentially larger and shipping more than the teams closer to the SQL can provide.
- tored 5y agoGraphQL is a consequence of the SPA design, a bad design leads to a worse fix. The drawback is that the frontend now has its own schema, often it starts as a naive direct mapping of the real schema. Thus any changes in the real schema also need to change the frontend schema and every use of it, or the mapping to the frontend schema needs to change. Eventually these two schemas will diverge because it is not feasible that every schema change results in frontend change. Especially if the idea is to have two different teams working from either side, then the backend team can’t wait for the frontend team therefore the schema mapping will change. And the thing is that the frontend shouldn’t be aware of how the backend schema is constructed, if the User model is separated into three different tables, because of some technical reason, that should not change how the frontend operates. The frontend understanding of what a User is shouldn’t be the same as the backends. Therefore ideally frontend schema and the backend schema will always differ. They don’t view the world the same way. However what you now have is a slow mapper between the frontend schema and backend schema. The point of relationship databases is that you can view your data from different perspective by doing different SQL queries. That is already built in. But now we have invented yet another layer on top of SQL, usually in combination with the already monstrosity called ORM.
- Someone 5y ago> SPAs are great for a number of reasons: > [...] > 2. You need a beefier backend. I don’t work on front-end and am trying to learn from this thread, so I may misunderstand, but that doesn’t look like an advantage to me. Doesn’t “beefier backend” imply “higher costs”?