My company (4,500+ people) ordered all products in their portfolio (~12 web apps) to migrate to SPA front ends about a year ago as a way to stand out from our competitors, and boy has it been painful.
Prior to that initiative, we had been using the hybrid approach mentioned in this piece, embedding SPAs only where necessary and sticking to SSR everywhere else, which worked really well.
Since the announcement, our productivity has diminished dramatically since so much of our time is now focused on re-working functionality that already exists into an SPA, and it's completely unnecessary. Not only that, but extending these UIs will take more time in the future than their SSR versions due to the added complexity of the front end frameworks, and we're definitely going to make mistakes along the way that we weren't making before.
It drives me crazy to think that some exec came up with SPA-ing everything as a sales pitch to clients, when 99.9% of our clients have no idea what an SPA is. And the amount of money being spent on turning already-working apps into SPAs is astronomical.
I've been working alone for so long I've not had to deal with anything like that for years, but I'll offer this...
Doesn't matter, so don't let it matter to you.
When I worked for others I'd offer my opinion and advice and when it was ignored I'd do it their way every step of the way because it really does not matter. You get paid the same either way.
I'll add that because it didn't matter to me I ended up getting to work on some pretty cool stuff. Everyone knew I wouldn't whine about changing directions or being taken off a project and jumping on whatever they wanted so I was almost always the 1st choice to work on something new.
When that happened I was often able to influence the direction of the work.
All you can do as a professional, with experience, is offer up an argument and attempt to make it convincing enough to compel people to do things your way. If they reject your option, defend only once, and no more. After that, simply step back and work with whatever technologies are decided upon.
You can also attempt to work the social networking game and play (internal) politics. If you do these successfully you're more likely to get your ideas heard and implemented. I find this tiresome.
Ultimately if I'm being polite, professional and basing my arguments on facts and evidence, and they're being rejected, I'm not expelling any more energy on this front. Move on. Work on and with what's decided and have fun doing it.
> work with whatever technologies are decided upon.
It may sound great when you learn something new, but when you worked with a technology and you know its deprecated crap - as a professional - you should also consider your own career..
Work on crap nobody uses for 5 years and you are so handicapped by that you "will" find a new job, but rather not a good one.
Not everyone can spend hours at home to keep up with the industry.
I was looking for work once and went to place that made wheelchair lifts for vans and buses. There was a miscommunication about what they were hiring for and when I got there they took me out to a drill press with a stack of thousands of parts on carts that needed a hole drilled in them.
> My company (4,500+ people) ordered all products in their portfolio (~12 web apps) to migrate to SPA front ends about a year ago as a way to stand out from our competitors, and boy has it been painful.
This doesn't seem like a problem of "MVC vs SPA".
The same problem would occur if you were ordered to rebuild 12 apps written in Rails ( or whatever full-stack MVC framework) in a different one, like Django, for example. You'd experience the same pain.
The story of rewriting Netscape comes to mind and a few others. Point being, not much value in rewriting something that works in different language.
> Not only that, but extending these UIs will take more time in the future than their SSR versions due to the added complexity of the front end frameworks
You simply trade back-end frameworks complexities for the front-end framework complexities. With the right architecture there is no huge difference IMO, just of course you also need to upgrade your teams so that they can handle a lot more tasks on the front-end than with SSRs (and you'll probably need less back-end devs)
There was indeed a moment few years ago when front-end frameworks/libs were changing at warp speed, but last year or so I think the situation crystalized a lot. You now have React and Vue as major players and Angular competing for the 3rd place against some fresh libs... and I don't see that changing anytime soon.
yeah, you have React, but which of the 30 fashionable state-management libraries are you using? Typescript or Flow? What version of JS syntax? What compiler what minifier? oh hey, half of these just stopped being maintained without warning
It's possible, especially if you look primarily at the enterprise market. From where I stand (startups, SMEs) it seems like a lot of people moved from Angular 1.x directly to Vue, skipping Angular 2+ versions. I haven't been offered any Angular projects in about 2 years, while React and Vue are really popular. But it's just my perspective, global situation might be different.
This has also been my experience. Enterprise systems really went all-in on Angular 1 for some reason (I personally suspect because it bridges reactive and MVC), and when it was time to move to a fully-reactive front-end framework, in my opinion Vue and Angular 1 are similar to each other in a way that React is not similar in relation to either of them or Angular 2+.
I still can't quite put my finger on why Angular 1 and Vue rhyme, though. It's common wisdom that "If you know Angular, you'll pick up Vue quickly", and it seems to be true, but nobody has ever explained to me why. Is it the state management? Reliance on viewmodels? How they're more complete systems out of the box and can be reasoned about holistically? Help a girl out, HN.
Not only that but you have to reinvent SSR with front end frameworks. Why do something simple when you can make it 10x as hard but ultimately end up with the same result.
I mean, I think these SSR front-end frameworks are a pile of crap, not worth the added complexity, and I hate using them; but it's pretty clearly not the same result. The problem they're solving is not "render on the server side", it's "render on the server side for the initial load then inject a fully functioning SPA for subsequent loads".
I'd rephrase: Front-end frameworks have been progressing through an iterative process, browsers are adopting standards that make them more consistent, and the tooling have been advancing at a rapid rate.
FE is a vibrant ecosystem and the tooling, in my opinion, is some of the best I have worked with as a SE.
Not at all, people moves between libraries of the same framework, they will likely refactor jQuery mess into a framework, but it's unlikely for a team to move from React to Vue or Angular (and vice versa).
you don't have to follow every trend. stick to one framework until it is no longer suitable. since 2012 i have learned to work with exactly two frameworks. i started with angular 1, and switched to aurelia when angular 1 was no longer viable. i'll stick with aurelia until it has run its course.
Remote workers are good for this scenario. My current employer is maintaining an outdated backbone.js app, thankfully I'm not on that team.
We have one guy in the office responsible for all of it, as warm bodies with backbone experience are impossible to find. However, should we decide to employ remote workers, we can easily find developers with backbone.js experience from Romania, Lithuania, India, and Pakistan who would work for a pittance and be grateful for the opportunity.
Also, on the majority of SPA frameworks you have the notion of components which makes making the UI a lot simpler than with traditional SSR abstractions (templating and partials are not sufficient).
Or your backend template engine is weak. In Elixir, EEx used in Phoenix, every template is a function. It's not supper good, but it's component (I hate term "component" and prefer "function")
But a component is a function that satisfies certain properties, why would you prefer to not to be precise in your communication? Do you call squares rectangles because you hate the term "squares"?
The complexities of back-end frameworks are far less than the complexities of front-end frameworks in my experience and observation (in particular because the latter tend to needlessly reinvent half of a web browser). Additionally, the back-end complexities still exist when using front-end frameworks (unless you don't actually have a back-end, of course).
"You simply trade back-end frameworks complexities for the front-end framework complexities"
Not necessarily, you can have simple and modular front-ends while also having less complex back-end frameworks. The question is between SPA and non-SPA web applications, not between SPA and JSP/PHP.
Is there any possibility that the added complexity is a symptom of the framework in use and not a general problem with ALL frameworks? I know I've experienced many projects and found server side rendering more complex then client side when using frameworks like Ember.js.
I'm a front-end engineer, but I'd agree that SPAs are always more complicated than a pure SSR solution: You're inherently doing more. You're probably already tracking state somewhere on the backend (e.g. in a database). An SPA means you now have to track state on the front-end too.
There are benefits and things you can do with an SPA that you can't do with pure SSR, but they _do_ come at a cost. TANSTAAFL.
It's a symptom of the SPA architecture. Since you give up a lot of basic functionality by not using multiple pages, that same functionality has to be reinvented.
That's pretty debatable. I've worked on some gnarly SSR architectures and making changes to the front end almost always involves refactoring some of the backend as well.
I don’t disagree here at all, but I would note that generally server side templating is often a mish mash of business logic, view logic, accessing query string and session parameters, and whatever server side Singleton/globals available in the template context, that becomes horrific spaghetti in no time at all.
Compared to client side rendering discrete web requests with minimal templates; you usually get much better separation of logic, view, and code than the typical serverside solution.
There is a happy medium where server side services are encapsulated to separate concerns in a similar manner, but it rarely happens, even with competent, experienced, well intentioned teams.
SPA doesn’t guarantee good separation of concerns though. I have seen many a horrible SPA in my day that had all the business logic in the client side JS and zero validation server side. Server basically a very thin wrapper around the database.
I’ve been doing this for 15 years, and if I’ve learned anything it’s that developers can figure out ways to abuse anything.
Separate frontend from backend development and make it even two teams. This makes it much more robust and loosely coupled because both sides protect the interface from each other.
This works. Now you only need double the engineers to create the same app as you would using a server side framework. Hardly a more powerful argument against SPAs than this.
I'm not sure I buy this. I recently worked on a project where we had one .net core developer, a dev ops guy, and me doing the client SPA. We were all able to focus on our core competencies and turn around the project incredibly quickly. I would argue that you can get away with the same team size split between front and back end and possibly end up with a more efficient allocation of resources.
Perhaps, but if both teams are half the size, specialised and deliver faster, it’s a win.
That may not always be the case, but if your SSR team and API team are the same size, your devs suck, bluntly. API based backends are much easier to build, test, manage and look after.
Two teams sharing an interface means one team will block the other most of the time if a new feature always requires changes in the interface and implementation on both sides. Doesn't matter if individual development speed increases, overall project speed will suffer greatly.
That's a hell of a generalisation, and it falls down pretty fast when you move beyond CRUD apps. You can easily end up with entire teams whose role is just to babysit Elasticsearch.
Regardless of the backend stack, if you maintain both the front end and the backend, it is categorically less effort to only maintain the backend (ie. just run an API).
Half as much effort? 3/4? I don’t know, maybe your UI is a man autogenerated swagger frontend and it’s (43/50) as much effort.
It depends... but it is always less effort not maintaining an external user facing UI.
I think the counterpoint to this would be Google Search. The core product is incredibly simple from a frontend perspective, but the backend is world-class engineering.
I think making information usable is hard. This means that the burden of the development falls on whatever is making the information useful. If you simply can query an API and get stuff back that's valuable because the data is already processed, UI is pretty easy (aka Google). If your backend is returning raw data that needs to be organized and displayed, and users need to be guided through complex processes that are just simple CRUD operations server side, you have a much harder UX/UI challenge. Most things fall somewhere in the middle.
Well, what does your API actually do? If you're e.g. Heroku, your front end does almost nothing in comparison to the rest of your product. Why would running the backend of a globally distributed infrastructure-as-a-service company be easier than maintaining the front end?
>Plus you've got the extra layer of an API to maintain too
On the other hand, if you're providing a service that will always have an API, and you want to make sure that all the functionality you provide is nicely accessible through the API, building the frontend on top of it can be a good approach. The developers at the company I work for have done this, and IMO it's worked out pretty well.
Possibly, though your perfect API design may differ significantly from your perfect site structure. It feels reasonable to consider both and see it as a positive if the use cases work.
Nonsense. People have been doing that for years before the single-page hype. The servers generating HTML contents use the API as their own backend and you have better layering.
This is also the main argument that keeps me on the side of SPA for our own project, at the moment. Our product is a specialized database with a fancy GUI on top, but we have customers that only use the database through its API; by using it ourselves for our frontends we make sure everything is doable that way.
The other argument is that frontend developers are looking for SPA work because they see SPA work everywhere. There's an element of everybody having to go with the flow...
I definitely view being forced to build a sane API as one of the perks of a SPA. Having worked on some PHP pages with SQL queries, HTML, CSS, & JS all in a single file you would be surprised how people fail to separate concerns when they aren't forced to.
How would you make it "even more complicated, and more likely to spaghettifi" to maintain an API than having to maintain a rich UI. Now that's a load of nonsense, or at least very misguided hyperbole.
It doesn't often happen because of Conway's law - that "organizations which design systems ... are constrained to produce designs which are copies of the communication structures of these organizations."
Its always possible to architect the web/app back end to do everything through APIs, keeping the APIs pure, and ensuring that others will be able to build UIs on top of them.
But in many organizations the same people that own the APIs also own the back end. That means it takes discipline and an acceptance of extra costs to keep this separation. Its easiest and cheapest to just slop all the back end together.
With an SPA, a different team builds the front end from the back end, and APIs are the only way for them to talk. That acts as a force for good APIs.
IMO it's one of the long-term failures of web architecture for CRUD that there isn't a unified solution for this; not only should they be the same team but they should be in the same repo, quite possibly in the same language, and the number of places a field has to be defined should be as small as possible. Let the machine sort out separation of concerns and what code goes where. Learn something from dBase and FoxPro.
I completely agree that a big part of this conversation falls on ensuring code quality is maintained over time, regardless of the architecture you choose.
Fortunately, I inherited a set of pretty well-maintained SSR rails apps, and they've been pretty straightforward to continue working on (with a couple of exceptions).
The single biggest disadvantage I see with front end apps is that comprehending state management via redux and co. is so complicated, and so, so easy to get wrong.
I can tell a coworker to refactor a smelly ERB view and extract out a new template, presenter, whatever. But redux still causes us problems that require refactors months later. It still feels way more cumbersome than being diligent about keeping controller/presenter/template logic clean. We're also far more competent rails developers than we are modern UI developers, and that definitely factors into our productivity.
Hi, I'm a Redux maintainer. Any specific concerns that I can help with?
You might want to check out our new Redux Starter Kit package. It includes utilities to simplify several common Redux use cases, including store setup, defining reducers, immutable update logic, and even creating entire "slices" of state at once:
After having some pretty extensive (heated) debates about the merits of redux here on HN, I've come to the opinion that the love/hate for redux is a consequence of the departure from MVC architectures that more experienced developers are accustomed to. There are decades of best practices built up around scaling object oriented MVC architectures, but react and redux come from a completely different school of programming where trying to apply traditional inheritance patterns is impossible and can mortally wound a project.
There was an article about entity component systems recently posted here, which are typically used in game programming, and I was shocked at how similar it is to the architectures I use in my react apps. This entry [0] from the ECS wiki is a good summary:
> Whereas in an inheritance-based design, an enemy may have a complex inheritance chain such as Damageable <- Actor <- GroundBasedActor <- Enemy <- ZombieEnemy, in a C/ES-based design you might have a Health component, a GroundBasedMovement component and a ZombieAi component added to an entity named ZombieEnemy. This eliminates ambiguity issues encountered in an inheritance-based design (should the root be Actor <- DamageableActor or Damageable <- Actor? Should items be implemented twice as PickupActors or DamageablePickupActors?). At the same time, components can be freely combined: a damageable inventory item? add the Collectable and Health components to an entity.
It occurred to me that in a lot of ways, games are just extremely complex user interfaces. So it makes sense that patterns that work well in game architectures should map rather cleanly to application UIs. I'd be interested in hearing if anyone else sees the correlation here, or if I'm just confused and misunderstanding ECS architectures. My email is in my user profile.
> I would note that generally server side templating is often a mish mash of business logic
If you don't have good, experienced senior developers or they don't have discipline, yes. But that's true for any technology. Good developers have the knowledge for simple things like how to separate business logic from templates...
TBH if the thing is getting rewritten every two years because of $new_paradigm, code quality matters less.
It would be nice if, given a task, we could teach people to choose the right approach in code the first time, but given we still have trouble recognizing good developers, the fast-paced churn of rewriting apps is a decent hedge until we figure out how to train the people we want.
We seem to only want developers with this skill, but then force them to rewrite stuff often enough so that no actual long-term gains can be realized from their expertise.
> TBH if the thing is getting rewritten every two years because of $new_paradigm, code quality matters less.
I disagree with this. De-prioritizing code quality because a rewrite is on the horizon is a great way to paint yourself into a very bad corner.
Imagine letting your codebase rot with the assumption you're going to rewrite it only to have your CEO walk in one day and completely shift priorities to build some new feature to land a new customer or appease a current one (a not-too-different scenario happened to me once.)
Priorities change all the time, and quality code grants the flexibility to adapt to changing priorities.
So I could see an issue with someone writing business logic in a view and then someone else rewriting that business logic somewhere else slightly differently.
But I've seen the same thing happen in the SPA. Where one person calculates some value in an API method, another doesn't know about it and calculates it again slightly differently in a different method leading to app inconsistencies. And SPA's make it worse not better because it sometimes forces you to write a piece of domain logic twice, once for the browser and once serverside.
I honestly don't know what's wrong with accessing query strings or session information. But I think maybe the reason you've seen template code using global state is because the template code was just written earlier back before that information had really soaked into the entire development community.
I could make the reverse argument: bad frontend programmers who dont use the facilities available to separate concerns create unmaintainable spaghetti when good backend programmers who separate concerns properly produce beautiful maintainable code.
The key being bad programmers dont isolate concerns and good ones do.
Indeed, that's true. While I'm not saying they're good for everything, one thing I like about SPAs is that the server can just serve up an API that is usable by both web and mobile clients. No duplication of templating/view logic between server and client as often happens when the server is serving up HTML.
One reason the SSR mess is so easy to walk into is that everyone knows it's a reasonable amount of refactoring to get out of later. The cleanup of an SSR app lacks the deployment headaches of SPAs (doubly so with the service worker layer).
Well, in our case moving from server side MVC to SPA approach has drastically increased productivity and stability of our applications.
MVC approach was a hairball of code where 2/3 was dealing with synchronization of state between client and server, and only 1/3 being related to actual application logic.
Clean separation of frontend SPA and backend API made both sides simpler and more robust.
I would also wholeheartedly recommend separating the development into two teams (frontend / backend) . It makes both pieces of the application even more robust due to both teams guarding the interface with the other part even better.
I turned around an SPA fast because I'm only a backend developer. I wrote API endpoints only and contracted a friend to write the frontend, delivering a swaggerspec and vague ideas of what I wanted. Completed the thing in like four design meetings and one touch-up meeting. Couldn't be happier.
> I would also wholeheartedly recommend separating the development into two teams (frontend / backend) . It makes both pieces of the application even more robust due to both teams guarding the interface with the other part even better.
In theory, we should strive for that. In practice, back-end team tend to strive on "technical purity" and would ask the front-end team to take any hacks/workarounds necessary to deliver "compelling" user-experience. One example would be the disagreement over "Data Model" of front-end vs back-end.
Hah. I just finished a huge refactor of an application where the back end developers "dramatically simplified" the business logic and architecture. What they meant is they removed all of the business logic from the back end so the client could do it instead. You might be able to tell I'm still a little bitter about that.
> In practice, back-end team tend to strive on "technical purity" and would ask the front-end team to take any hacks/workarounds necessary to deliver "compelling" user-experience.
The key is to design the DTOs (which API endpoints are based on) starting from the API consumer perspective. Business logic on backend is responsible to deal with mapping of DTOs to the domain models and in turn to data access layer models.
This results in most DTOs being "flat" and easy to consume by client.
I'm not convinced. We were using MVC for years and tried different approaches, but the API code is incomparably cleaner when it doesn't deal with client concerns.
Eh. The problems you talk about have little to do with SPAs in general, and have more to do with "rewriting things from A to B". If you had started out with SPAs first and wanted to un-SPA everything, you'd be making the same comments. The issues you mentioned aren't intrinsic to SPAs, they're intrinsic in redoing things.
You're right, but it's also intrinsic to the senselessly shifting paradigm/bandwagon-jumping around SPAs. It's not just that redoing things is a problem, but that the motivation behind the rehaul is poorly conceived.
I think that's how the cookie crumbles, unfortunately. Most companies want to be on the biggest bandwagon to ensure they have a steady supply of fresh, young employees. Few companies want to rely on niche software that only a few people know how to work with. As long as younger people keep jumping onto new trends, companies will continue to follow.
I'd love to hear some trench stories where these kinds of initiatives to increase the complexity of (what appear to be core) business tools were met with what I'll call a "simplicity advocate," who carried the day and the complexity was tempered, if not rejected.
Anytime you rewrite 12 existing, working web apps in something new it is going to be a huge pain. The only sane way to approach this is the strangler pattern, picking one page/view in one app to rewrite, then another, hooking them up with some kind of client-side router, and slowly letting the SPA consume the old SSR pages.
That way you can measure the cost/benefit of each page before deciding it should be added into the SPA.
Sorry, I don't have the complete context - SSR stack, app architecture, load times etc. So, I'm not in a position to comment on your SPA migration. But, I'd like to share thoughts from my current situation.
We have a flagship product written in web forms (started in 2006). It's a big solution. Performance has always been a challenge with it.
While I'm not proposing a complete rewrite into SPA, due to - migration requires a lot of effort, huge risk for missing functionality, errors etc.
The biggest problem with the product is - app posts back the entire page, which most of the times is huge, even if we changed just one field. The viewstate is enormous. My proposal is to switch to json objects for information exchange between server and client. We'll get the benefits similar to SPA without rewriting for it.
> My proposal is to switch to json objects for information exchange between server and client. We'll get the benefits similar to SPA without rewriting for it
If I understand your approach correctly, I often do something similar, but with modern ASP.NET Core MVC apps. Basically, I have a tiny bit of JavaScript that 'intercepts' all form POSTs and submits them using AJAX instead. Another tiny bit of JavaScript can then process the result and do something (update a table, display a message, redirect, whatever).
I feel like this gives me the best of both worlds - the backend is very testable, and really straightforward for new developers to come up to speed on, while at the same time we remove a lot of full-page renders.
I recall one of the more frustrating clients at my old firm. The client was hoping to build a competitor to a fancy all-AJAX industry-specific backoffice application (written by a team of dozens and with a coffee budget alone three times our dev budget) Since they were domain experts, but sort of scatterbrained (oh, we need undisclosed requirement xyz" 3 months into development), we were building it in phases to make sure we could cover their functional needs. It was a rule-based system for validating and analyzing user-provided data, where they'd be responsible for maintaining the rules via an admin backend. It was your typical PHP based request/response lifecycle.
They. Could. Not. Get. Over. The. Fact. The. Pages. Reloaded. After. Each. Request. No matter how many times we said "can we focus on making sure the underlying math is right and then polish the UI?"
So I finally snapped and implemented that exact same thing. That shut them up enough that they just started disappearing when they were asked for info. I suspect the project had enterred the phase where they were out of money and/or realized they were trying to swallow a bigger task than they could handle themselves.
Recently, I saw Turbolinks [0] which looks like the same concept with way more panache.
This is exactly what the article points out. Github/Gitlab and many other projects do the same thing.
Either small parts of the application are standalone SPAs (since they can be mounted to any single root element) or there are libraries like Turbolinks/Intercooler that just make the full-page request but in JS and then replace the DOM with the results so the browser doesn't actually experience a full page reload.
I’ve occasionally thought of doing SSR but making it possible to server render only a small part of the page in response to an API request and then just use JavaScript to swap in the html from the backend.
Same issue at the previous company. Engineering team decided to turn the web app into SPA, and spent months doing this. All that time which could have been spent on building customer value were wasted.
The hybrid approach sounds good, but I've found it frequently non-trivial to pull off in practice. In my experience, you have to be really thoughtful about what and how much you make dynamic.
For instance, if you start to rely heavily on dynamic capabilities to render key components, such as detail views/overlays, then you have to start reasoning about making them accessible via their own URL to enable direct access, browser reloads, sharing, etc. By the time you've done that, you've started duplicating browser functionality via routing, history, etc, and generally working to create an app that coexists peacefully within an app. In other words, you quickly move into SPA territory and all that that entails.
But, if that causes you to be more conservative about sprinkling in dynamic capabilities, then you're really much closer to an old school SSR app and not realizing a lot of the purorted benefits of a SPA, or much else beyond the old school AJAX approaches. Not to say that's useless, but we've long since been down that road, and it doesn't represent any new thinking.
So, it's just hard to find balance there. In most cases, you're really either a SPA or you're not.
Our team has found the balance by making a bunch of smaller, individual SPAs that make up our whole application. We follow some SPA designs, but have them more modular, and glued together by a bunch of delivery pages. We kind of get the best of both worlds, plus there's some pages and content that just render better on the server, and delivered faster through caching...
> "It drives me crazy to think that some exec came up with SPA-ing everything as a sales pitch to clients"
In other companies, I wonder if this is just as often due to: (a) developers getting tired of what works reasonably well and wanting to move to a different technology and/or (b) the voices in the tech evangelist community whose own jobs seems to hinge on pitching new and shiny, latest and greatest library/framework/whatever, instilling FOMO and insecurity in the developers who listen to them about not getting on board with the latest and greatest?
On the flip side, I recently worked on a "hybrid" project that has been around for a couple years. It was a nightmare knowing when SSR stopped and SPA began. There was no consistency, multiple ways to do the same thing, and poorly maintained. It was schizophrenic.
I think the real issue you are dealing with is what others mentioned: rebuilding something from scratch burns a ton of people-hours and money. Asking a bunch of rails developers to lean into FE development is a recipe for animosity and to me it shows in this post.
The bank I used has gone from traditional to SPA style, and I wish they hadn't. There is a massive load time before I can even log in with some stupid animation, and they've reduced the exporting features. As a customer I have gained nothing. But I guess it keeps food on the table for some devs.
your anecdotal story doesn't highlight deficiencies with SPA. You only talked about the pains associated with rebuilding apps with different technology to achieve feature parity.
Yeah we have read experiences like yours again and again on every HN thread about SPA, but why we never learn? We developers kind of helping this fashion to happen.
Nine times out of ten, we developers aren't in a position to make or change business decisions of that magnitude.
Remember, every time you tell your boss to do something they don't want to do, you're telling them to spend money they don't want to spend, and if it's something you were hired to do, you're also placing your own value as an employee in question.
True but I was talking about the producer side, those cool kids in big corps. They have money backed and drive small companies to adopt the next cool things.
Not contradicting you, but how did you evaluated that the SPA is not bringing any value to the customers? It may make work harder for you, it may cost more, but maybe that cost is rightfully justified from a business perspective.
As a consumer of SPAs all across the internet, all I seem to get is a bunch of janky, slow, bloated, buggy experiences. Server-rendered views just seem more performant and reliable when done well.
Agree with the article. I find server views to be substantially easier to work with.
But more importantly, I also find server view rendering to be a faster, better UI experience. It's really frustrating having to wait several seconds for a SPA to load, or to have unexpected behavior when clicking the browser back button, or failing completely because some random hunk of JS garbage errored out, and it's one of the big contributors to why I don't really like using Facebook or Twitter anymore. They murder my browser with megabytes worth of slow SPA crap to give me less than a few kilobytes of meaningful data (and/or people screaming at each other). Gmail now takes 10-20 seconds for me to load at this point, on my high end laptop. I just want to switch to HTML mode by default.
I definitely get edge cases like Slack, but honestly don't think SPA has been a positive development, overall. I think the web was better as a document/HTML oriented design.
With gmail: Move your mouse pointer down to the lower right corner of the tab. Do a forced refresh (Ctrl+f5) and you'll see some text pop up while it's loading, one of which is a link to a basic HTML version of the site. Click on it and you're back to what appears to be almost the original gmail interface. Up the top of the page you'll see an option to make it default.
It's super fast. Almost absurdly so, compared to the "full" gmail experience. Added bonus: It gets out of the damn way so you can just do what you came there to do: write and read email.
Great example, because the basic HTML version doesn't support keyboard shortcuts, which makes it a huge step back for me.
It's certainly possible to have a server rendered app that uses JS sparingly for interactive behavior, but it blows away a lot of the benefits once you're doing significant DOM-manipulation.
Aren't those inconsistent across platforms? Also you must use the "super" key/combo, and there's only one. Not to mention the internationalization concerns.
Instead of trying to quickly click the link, it's easier to just turn JS off and refresh GMail. You'll be prompted to either turn JS on or switch to Basic HTML. (You can make it the default after that, as described.)
I did this a while back, and the only real issue I've had with it is that there doesn't seem to be an equivalent to the "Check mail now" action for imported email accounts. (The 'refresh' link annoyingly does not trigger this action.)
There's a single file that's 584KB of javascript from hangouts.google.com in the "full experience" Gmail. Blocking that seems to help, a lot. I imagine there's probably some configuration to turn off hangouts that provides the same benefit.
I got a popup saying the offline app is going away with a link to "setup" the new gmail app for offline use. Unfortunately the new gmail app for offline use does not support Firefox.
>Offline unavailable.
>The browser you are using is missing some features required to enable offline. To enable offline, you must use Chrome with version 61 or higher.
Thanks for the tip! I realized this existed but didn't clue in to the fact that it could be set default. I've done so now, and already feel the absurd javascript weight lifting...
I definitely get edge cases like Slack, but honestly don't think SPA has been a positive development, overall. I think the web was better as a document/HTML oriented design.
It was nice and would still be nice if browser caching meant a site still worked well over a bad connection. But you can be browsing around a "static" site and hit the back button and be stuck staring at an empty or partly rendered page waiting for your flaky connection to load the page.
SPAs handle that situation better even for sites that are theoretically not suited for SPAs. The simple principle of doing your best to display the data you've already fetched is extremely refreshing compared to supposedly "document-oriented" sites, which typically take the opposite approach -- we showed you this page fifteen seconds ago, but we can't show it to you again until we exchange a few megabytes of data with headquarters. And now we can't show you the other page, either. Just be patient. If it's really that important you should have taken a screenshot, mmmkay?
(Slow-loading web sites are the main reason my not-so-tech-savvy family members, who are very stubborn and selective about learning anything, are all adept at taking screenshots on their phones. When it comes to information they might need later, they take screenshots, because you can't just leave a page open and trust it to be there when you need it. You might accidentally trigger some navigation and then who knows how long it will take to get back to the information they need, if it's even possible.)
Browser caching should theoretically let a document-oriented web site work smoothly over a flaky connection, as long as you stick to the pages you've already viewed, right? But how often does it help even a little bit? Maybe SPAs will eventually be just as broken, but right now it seems damned cool that they make a good-faith effort to show me stuff.
You could also run server-rendering with a service worker. There's nothing about a service worker that means it only works with SPAs. It basically just gives you control over caching behaviour...
You can also control caching behavior by just setting the headers correctly in the first place. I think the takeaway here is that sometimes SPA frameworks make the behavior “just work” in more cases when the developer doesn’t put any thought into correct cache handling.
> I definitely get edge cases like Slack, but honestly don't think SPA has been a positive development, overall. I think the web was better as a document/HTML oriented design.
But even Slack is subject to the same clunky and slow user experience you're describing because its entire user interface is an SPA.
In my opinion, a site for the SPA hall of shame is the Starbucks.com progressive web app [1]. My grievances about it are legion, but to name a few:
* It's agonizing slow, both on the client and server. The server is an egregiously-slow GraphQL endpoint.
* It hasn't been tested on anything but Chrome, as far as I can tell. It flat out refuses to work in Firefox or Edge, even fresh installations I've put into VMs. These browsers may not be mainstream targets, but odds are you would have no trouble supporting them if you weren't using these unnecessarily complicated client-side frameworks for placing a coffee order.
* It routinely messes up state management. I've had it forget my selected store location; fail to add items to the shopping cart; fail to submit orders; fail to apply star points (coupons); get into a weird state where it thinks I have a coupon when the server disagrees; etc. It's constantly introducing new and imaginative ways to fail.
* If you use it for months, white-page failure modes are surprisingly common.
Every time I use it, I wish that Starbucks had made just a plain responsive web app with simple server-side rendering. It would be fast and probably work better as a way to place orders.
The Starbucks app in Edge is _miles_ faster than Amazon.com or eBay.com for me on my slow satellite connection. I think this is one often underlooked feature of SPAs. SSR stuff is a blank white screen about 50% of the time for people on slow connections, SPAs have a slower initial load and then from then on are either faster or _feel_ faster because they don't go completely blank for 5+ seconds every time you click something. Even a slowly-loading SPA feels better than any SSR site for that reason, IMO.
We had a very static product, and one of our devs decided to make more use of client-side rendering despite essentially being a set of unchanging forms. This quickly got out of hand, so we adopted a hybrid approach.
I built out another product, which was much more dynamic and made sense as a SPA. However, having been bitten by the forced SPA, I decided to do as much static rendering as feasible, and I think that has made things a lot easier to develop and less buggy.
Honestly, I agree that a SPA is usually a bad idea and prefer to have as much of the app be able static as possible since that simplifies things considerably. For example, slack could open a separate tab for settings (and perhaps chat history) and only have the chat parts as a SPA. It would make it slightly less fancy, but also probably much lighter on resources, faster to load, and easier to develop.
I don’t think this is about edge cases but SPA have been abused. Imagine using google docs as a server rendered experience. Or any of the apps in iCloud.com. There are use cases where it makes sense and use cases where it doesn’t.
Most of your complaints are about poor implementation but if a large percentage of people poorly implement SPA then it still looks bad. I used to say you could make a very native experience with a hybrid web app for mobile. While this is absolutely true, most people don’t pull it off so I get the critism.
Exactly. In many places slow networks are the problem, and quick spa's give a great user experience comparatively. The biggest lag in Google Docs is when it has to refresh from the server, and then it's like using windows on a 386.
I don't think PWA offline storage is anywhere reliable or predictable enough to be advertised as an actual benefit. It's essentially a fancy cache at this point:
Thank you for pointing the real issue with SPAs: they deliver awful user experience. It's quite telling how this fact is missing from the article and from most of the discussion here. We're a bunch of self-referential techies who've lost connection with reality.
I couldn't disagree more. For anyone on a slower connection (I use a satellite connection that's 1 Mbps on a good day) a SPA is almost always a greatly superior user experience. A server-side rendered application is a blank white screen for roughly 50% of the time I'm using it. Even if a SPA takes longer to initially load, it's much nicer to keep the application actually onscreen while it's loading new content. Even if the SPA takes longer to load content it will often feel as if it's faster because you're looking at the application while it loads rather than staring at a blank screen for 5-10 seconds with every click. When people talk about SSR applications being a better user experience I always assume they're operating on first-world 10+ Mbps broadband connections or cellphones in developed cities, because the difference is night and day for those of us on slower.
I also disagree with the idea that SPAs are pushed by developers who have lost touch. Clients frequently push for them and ask questions like "Twitter/Instagram/YouTube don't show these blank white pages after every click, why does my site? Can't you make it like YouTube?" Clients want to have them more than developers want to make them.
That's not huge at all, you can barely fit a few pictures into that. The page we are on require 100 KB, the page it link require 300 KB, and both aren't big and have no image to show.
I try to keep my pages down under 50k, 30k or less 80% of the time. Perhaps it's me but I think anything over 999k is insane unless it's spa or a page full of graphing function. My expectation that others are doing the same might be incorrect.
Yep. Millions of SPAs out in the wild and none of them are good. This whole thread is such a joke. It's a bunch of posturing and no data whatsoever from actual SPAs in the wild.
> Thank you for pointing the real issue with SPAs: they deliver awful user experience.
I don't think I could disagree more with a statement, but the way I browse the internet might be different from the way you browse the internet. SPAs, when done correctly, create rich and interactive GUIs that absolutely bring browsing websites into a entirely new territory for UX. There's a reason why webapps have taken over, including desktop apps.
It's funny how Google has been banging on about "just a few milliseconds of extra loadtime and your bounce-rate increases!" while in Gmail it's like they think the product is so good, people should be willing to wait 10 seconds to view their _mail_.
The reason I'm even reading this comment section is because I wanted something to do while waiting for Gmail to load.
But the reason Gmail is so slow isn't because they've made it a SPA. It's because they made it a shitty SPA. They use nonstandard web technologies that work like ass. It was also a SPA before the new redesign and it worked pretty well.
If Gmail is taking 10 seconds to load it might be worth your time to consider a faster computer for your own sake. It can be like 3-4 seconds on a faster computer.
Nah, just tested and mail.google.com took 23.3 seconds to load in Chrome and 30.2 seconds in Firefox. I have a 4-core 8-thread i7 and am on a 20Mbps internet line. It's the website, it isn't my computer.
Is that from scratch? I'm using an i3 on a 1 Mbps satellite connection, and opening up Gmail now (having opened it earlier today), it was 0.27s until DOMContentLoaded and I could interact with it. It continued asynchronously loading stuff in the background but from my POV it loaded in 1/3 of a second, which in Chrome is faster than the app opens on my iPhone 7. I have disabled the Hangouts/Chat feature in settings which apparently makes a big difference.
Okay I can't believe that either! You're really talking about full Gmail loading in 1/3 of a second? That sounds impossible if we're loading the same Gmail...
Yeah, it's pretty crazy that there would be such a huge difference. Turning off Hangouts and using uBlock Origin might make a big difference because that's all I've really done to modify it.
Can you try in Guest Mode (or Incognito but only if you've disabled extensions in it)? I'm guessing you either have (1) battery power or other cause of downclocking, (2) slow extensions, (3) disabled/small cache, (4) an old CPU (old gen i7 maybe?), or (5) a large distance between you and the server. I have a similar machine to yours that's 3+ GHz and it's consistently loading in less than 4 seconds when I'm on AC.
(To be clear, I'm not excusing how slow their code is, just trying to help you save some time in the long run.)
>>Agree with the article. I find server views to be substantially easier to work with.
When working with static pages that have minimal interactivity, sure. Just render the HTML and send it to the client.
Once you get past that though, if you try to stick with SSR you'll end up with incredibly difficult-to-decipher mish-mash of if/then statements, most likely with lots of jQuery or equivalent thrown in. I've debugged such templates and they are universally messy, not just because they are usually written by backend engineers who have a minimal understanding of/appreciation for JavaScript, but also because keeping track of state with such templates is really inefficient and frustrating.
As a user, I miss pre-SPA days. For all the negatives that SPAs were supposed to solve, there was one thing about those apps, and it's that they were predictable. These days, you never know whether you can even open a link in a new tab, or bookmark it, for that matter.
When browser receives HTML, either complete pages or updated fragments of them, it only needs to parse HTML, style/layout, and render. These steps are relatively fast, especially rendering (usually GPU does that).
When browser received JSON or XML instead, it needs to do all that as well (parsing is slightly simpler), but also it needs to make visual elements out of the data. Takes a lot of processing and therefore electricity: JavaScript is not particularly fast, the code size is often not insignificant i.e. takes time to download and parse the code, and the runtime is essentially single threaded (for any given page).
You probably don't need a single-page app, right up to the point where it's a business requirement and you have to translate a GB worth of convoluted JSPs into one because the client likes smoothness in their flows, continuous saving, and all those nicely choreographed state transitions you just cannot get without having a framework hijack the History and File APIs from the browser's paws.
Yes, a nice state machine-like flow with each thing happening only once at a given time is great, right until you get asked to make it so that clicking on a thing shouldn't reset all user input, and progress of a task should be communicated live, maybe while we also we want this app to just not show a blank screen like, ever, just comes and happens to you and that's what you kind of have to do now.
This is what HN is always missing on the anti-SPA rants. It’s almost always a requirement from the client. How many hours have been wasted on here by programmers writing overwrought comments about how we’re losing touch with the user because of all of our complicated frontend frameworks? No. It’s almost always because the client’s designer wanted a real-time updating hamburger menu or whatever.
If you know which of those you need, you can make an optimal technology decision. No one can expect to turn a wood-framed structure into a steel-framed structure. Nor build a steel-framed structure for the price of a wood-framed one.
In this day and age, chances are better than not for anything reasonable involved, that this smooth interaction is a business requirement, but YMMV.
How about “that’s totally possible. It will cost you 10x what you’re paying now, it will be much more brittle and harder to fix. I personally would love to work on it, just keep in mind that any changes will require 10x the time and budget”
And ...
“Here are a couple of technologies which would allow us to speed up the experience at a very low cost. I recommend we try these first.”
> It will cost you 10x what you’re paying now, it will be much more brittle and harder to fix.
I say this as someone who's done a lot of freelance work: No, you can't bullshit your clients like this. You may be able to tell them that if it's not an actual lie, but in your case, if you actually would endure such costs and fragility, it speaks volumes about your agency's skill levels.
If you're in the business of selling websites, maybe it's time to actually learn how to write a good SPA rather than bury your head in the sand, because yeah, clients do actually want those.
10x the cost!? Well, I have a quote from your competitor that's a fraction of that amount. If you keep quoting unreasonable prices, perhaps I should rethink our business relationship and move elsewhere.
Sure, you can say that. You will lose your clients to the agency down the road who happily use React and say "no problem." Especially once it turns out that it _doesn't_ require 10x the time and budget and your prospective client tells everyone you bullshitted them.
Turbolinks? Huh? You have to write your code keeping turbolinks in mind because certain onload events will only fire once but you use turbolinks specifically because you want those things to work but want the speed advantage of not doing a full page refresh.
All that complaining serves no purpose. SPA is just another tool in a belt. Where I think it shines is making rich apps that need complex flow and communication. This is where productivity is important and the process is complex and up until recently I would be advocating native desktop app. Now with advent frameworks that help me organize this very efficiently (I use re-frame/reagent with ClojureScript) I can create complex SPAs without the project collapsing under its own weight at some point.
I don't want to say you should use SPA frameworks for anything, don't make your company website with SPA. What I want to say that if you have a complex process you can consider creating "enterprise" UI instead of trying to dumb it down to a series of billion simple forms.
If you feel your business is overusing SPAs (is it so strange they want new shiny toy?) then as the technical person you need to educate them on pros/cons of the technology.
It's not complaining. It's a profession's view on the state of (default) behaviour by most developers in the wild. It's a valid set of points as to what the default mode of operation seems to be, as a general rule, and why it might not always be the correct default mode of operation.
I personally feel like what's really missing here is something like a generic spec (not a generator, but a descriptive standard) for the structure and organization of CRUD-style JS/JS-derivative SPAs, something like what re-ducks (https://github.com/alexnm/re-ducks) did for the Redux world.
Unpopular opinion: I love SPAs for simple stuff. Yes, they're a ton of work. But the feel of them is unparalleled.
I have my personal home page written as a Vue SPA. It was a silly amount of work to get together, and not everything works perfectly. BUT: it moves like a rocket. I pre-render the simple front page, so initial load is nearly instantaneous (especially with cloudflare &c), and, by the time a visitor finishes absorbing the information on the front page (which is just a palmos style collection of icons to other content), everything else is loaded. Which means that the effective load time of the whole website is perceptually indistinguishable from zero on a moderate-speed connection (like my crappy home DSL).
And that's... cool. It's legitimately cool. Let me have my fun!
I want to be open-minded for you to have your fun. But at the same time, I want to let you know the problems with your approach from my perspective if you want me to interact with your site.
No offense, but I don't know you, so I'm not going to run untrusted code you serve my computer without some good reason. That means your website is completely broken for me. It is also likely broken from an accessibility standpoint for those with special needs or using tools to access your webpage. (edit: People's personal browser defaults such as size, font, scrolling, language translation, or any other plugins they use for their workflow may easily break.) It also means that search engines and robots will have a hard problem indexing the links on your page or understanding the layout of your site.
So while I could agree you've created this cool user experience for the most common case, it breaks the fundamental precepts underlying the web and I think this does have some negative consequences, especially if this became the default approach. That all said, you do your thing - I just hope this provides useful food for thought!
Relying on JavaScript doesn't "break the fundamental precepts underlying the web", that horse has sailed long past that bridge.
Today, not running JS breaks the web. You can lament this, I too think it's not ideal, but you can't change it. So don't accuse devs of breaking the web for using an SPA just because you're part of the 0.002% of users that doesn't run js by default.
Furthermore SPAs do not break accessibility, that is nonsense. Devs may break accessibility if they choose to reimplement components without thinking about it but that has zero to do with SPAs.
Hi and thanks for your responses. I think you may not be considering my post in the context of the above person's webpage. I would be interested to hear if you see my perspective a bit more after viewing the page and its source code if you haven't already.
(1) I do think I can make a small difference toward making the web better by pointing out the drawbacks of unnecessary JS. I also think it's fair to describe this page as breaking the way hyperlinks usually work on the web.
(2) I don't mean to say all SPAs always break accessibility -- again this is all in the context of the page above. I do think, for the reasons I gave, it's fair to say that a plain HTML page with a list of links is much more amenable to generic accessibility tools than a block of JS that emulates behavior of links.
I misunderstood your post regarding accessibility then :) it's unfortunate but some react and Vue patterns tend to lead to a lot of div soup. It doesn't have much to do with the tooling but rather a lack of education for the devs on the subject and it's a testament to how easy it is to create custom components in both.
> I also think it's fair to describe this page as breaking the way hyperlinks usually work on the web.
Well maybe. A good SPA imo will render the first pageload with SSR, which means that your links will actually work the same. You share a link or open it in a new tab or whatever and it will load a page full of HTML that might not even need JavaScript.
SPAs do hijack the link system but they do so to retain natural back button functionality. Back when they didn't, people complained about that, rightfully so.
Howe there's nothing emulating anything. SPA links are anchors, as they are anywhere else on the web, and all the apis are native to the browser. It doesn't have anything to do with accessibility, no.
The more you write SPAs, the easier it is to set up the next one... This whole "but SPAs are bad!" tirade a lot of people have been going on since a couple years ago stinks of people being nervous about their job security.
It's a perfectly valid point to make: splitting everything up into SPAs, micro services, etc, instead of solving the business problem with a monolith is indeed the wrong way to go, and Martin makes some sensible arguments around this topic.
It's the same in video games: you create a prototype using cubes and texture-less blobs to test the "business logic" (mechanics) first before you produce a AAA model and 700 animations.
The site is very simple (6 icons links on the homepage and just plain text on the subpages) this could have been done as a static site quicker with even faster rendering. As a bonus you may get external traffic to your cv page if it was separate.
I do like the big icons on the homepage and I'll just say great job.
You used an spa because it was easier for you and that makes sense. One npm call and oje starter kit can get you a finished emtpy app. Doing it in plain html should be even easier but we lack the all-in-one modern tool it seems.
Well said. I think combining SSR and SPA by making intelligent tradeoffs is the way to go at this point. It's all about making the right choices to deliver the experience you're trying to offer.
Fun is fine, however, it can distract from the task in hand. Accessibility is queen.
No criticisms here, just observations on what gets missed generally by people who go too far along the build tools path and overlook things like document structure along the way.
The actual document could benefit from HTML5 niceties such as more accessible elements than 'div' and the table elements. Table has its place but the world is moving on to CSS Grid for proper layout of content rather than tables. I prefer to see 'article', 'section' 'aside', 'nav' and even things like 'cite'. For added usefulness to Google a few structured markup snippets for all of your publications will help nicely. The schema.org 'article' is a good place to start on that, you can also render your HTML from this structured data if in JSON+LD if you insist on clever wizardry or just put the Rdfa (or whatever) tags in the HTML.
The UX is not truly accessible, the home button is not a good touch target size plus the navigation is against the 'don't make me think' principle.
So it might 'move like a rocket' but if the site visitor can't work out how to get the navigation then what is the point? A vast magnitude of time is lost.
A favicon could help with accessibility too. If someone has lots open then a tab identifier helps. Go through the necessary to make a PWA instead of a SPA to get that right - nowadays you need lots of different things for 'add to homescreen' and whatnot. Whilst you are at it include some useful metadata in the header for people sharing your page on social media. Set the meta description with 'nosnippet' so Google shows people exactly what you want them to see. Nobody sees your site before Google so it is important.
Sometimes a focus on gadgets is counterintuitive, so the inline SVGs base64 encoded might be very clever, but to someone that understands SVGs this makes no sense at all. They are better as document content, not in an img tag and not base64 encoded. They will compress better that way too.
If you did the SVGs normally then you can use currentColor to effect a mouseover, you can use their title tags to show some text on the mouseover.
is a bit bulky when what you really need for that is to do (pseudo svg here) 'group fill=currentColor stroke=none id=circle-and-line' [ 'circle r=[radius]' 'rect x=[origin] y=[origin] width=[width] height=[height]' ] 'use y=[minus-a-bit] href=circle-and-line' 'use y=[plus-a-bit] href=circle-and-line'
In that way you can get a super concise and super editable icon for your CV that you can edit and tweak in document. It will also have the currentColor niceties. Sometimes I think that just because you can put sausages in a blender doesn't mean you should. Those SVGs really are wrongful being inlined and base64 encoded when HTML provides perfect and better mechanisms built in for doing whatever it is you are trying to achieve with them. Also, SVGs are best hand drawn for a pet project site, internet SVGs are just the disgorgings of an Adobe product, normally shapes for icons can be drawn with rectangles, circles, polygons and lines specified with integers, the Adobe products use NASA numbers instead (none decimal places).
I would say that you would have a lot more fun if you got the basics of document structure, accessibility and awesome SVG goodness done right, with measurables in Google search results and eyeballs.
We all live in glass houses and I am definitely throwing stones here with this critique, but the web gets better with a little bit of discussion on these things.
I certainly think most of this stuff is right. I've been meaning to go through and make the whole thing more semantic, just haven't gotten around to it yet. So I really appreciate your thoughts, most of that stuff is going on the todo list. (Maybe not the SVG stuff; the way I do the SVGs is a lot more convenient for design flexibility.)
(But, to the original point, all of those great suggestions are totally compatible with doing things SPA-style. And actually, Vue components are so composable that these kinds of changes should be pretty easy when I get around to them.)
You have some neat SVG icons already, I urge you to refactor them so they are not 'design assets' but fully fledged and fully yours. The exercise of doing them will give you a new string to your bow for solving visual problems. SVGs are like LEGO but a lot more fun, so long as you play with them properly rather than just use ready mades. So same as LEGO then...
Once you have done a small set, e.g. your dozen ones, you will be able to have more of this design flexibility, plus you will discover that creative drawing is not actually what usually goes on with Adobe style applications but goes up to a whole new level when you do SVG - because it is code.
If embedding SVGs has cool factor, you can make them fully presentational by putting them in CSS custom variables and then using those custom variables in pseudo elements. This is how I do external links, download links etc.
The only downside is that you can't radically change the colours on mouseover etc.
Also Google Lea Verou if you want to take pride in your SVGs.
To add to your refactoring list, have one stylesheet with everything that changes depending on screen size set as a CSS variable. So at the top have a big list of 'things that change' and the defaults for any screen size. So if you have margin size for instance, set it there for mobile, then, have a media query below the base list of css variables and then update the variable in the media query block. Try to have zero CSS rules in the media queries, have it exclusively setting CSS variables.
If you do it this way then you can tell from the CSS where something changes because it has a CSS variable. Done the old way with chunks of CSS in media queries you can't see at a glance if there is more than one place a given rule is defined, done the new way it can be maintained a lot easier.
A final thing - you have a lot of table information and CSS grid is absolutely excellent for showing tables. You don't have to explicitly write out all cells, unlike with tables, you can make things with a given class or other attribute go in the correct column keeping your source data semantically neat even if some records do not contain all the fields. Rather than classes you could mark up your 'papers' and references with things like 'cite' tags, 'address' tags or whatever is bestest HTML5 and have these flow into the correct columns without using classes or tables, just a succinct css grid declaration and that is it. The grid layout is much better for speed so you will like it.
I'm more interested in the future of "you probably don't need a native app".
It feels like browsers are closing the gap pretty well with things like IndexedDB, offline features, WASM, etc. Still a ways off, but seems like it's getting there.
I do worry, though, that it's not really in Apple's or Google's best interest to move that along.
It's in Googles interest as everything they deliver is through the browser. Not so much for Apple or Microsoft though. Personally I will be quite sad if I end up loosing so much control over my computing environment.
Native apps allow Google to collect much more information than they can via the browser. They also allow for a wider range of advertising opportunities.
Google's services are incredibly convenient and well made, and you may be assuming people will give up those conveniences. That's a big assumption and I think it wont pan out that way.
They don't need to show you ads in their apps. They just use them to collect your data, like where you are every moment of every day and use that data to better target ads.
Android and Google Search are completely different Google departments. They will fight for the audience as long as they won't directly compete with each other. Board can see this as a widening audience, cementing presence and reaching new markets. It's in the best interest of Google Search and Chrome to push browser apps ahead.
That’s much higher than I’d have expected. I wonder how much of it comes from games and their in app purchases, a segment that is unlikely to take much of a hit from moving other apps to the web.
As browsers close the gap they simply become the OS but slower, more abstracted, and with less security. And they stop being good browsers. It's the old emacs situation come round again.
The only positives are to corporations and institutions with profit motives to decrease dev time and increase ability to spy on users and extract rent from them.
> they simply become the OS but slower, more abstracted, and with less security.
I agree with slower, at least for computational tasks, but not security. Do you feel safer installing an organisation's native app than using their web app?
> The only positives are to corporations and institutions with profit motives...
What advantage does the web give to corporations that native apps don't? You mention spying, but the native mobile app ecosystem is filled with tracking and analytics code (and it's easier to hide it). The only corporation-level difference I can see is that native apps are heavily tied to a specific company's platform, while web apps aren't. This is a huge positive to the web - I've felt free to change platforms many times.
A second huge and underestimated positive of the web is backwards compatibility (ie. lower maintenance headaches). A complicated internal web app I wrote eight years ago is still running despite not being modified. The websites and lousy javascript I wrote as a kid in 1999 still run exactly the same as in 1999. Spacejam.com is unmodified from 1996. Yet I have many native apps from two years ago that no longer run correctly due to OS updates (especially on mobile).
> As browsers close the gap they simply become the OS but slower, more abstracted, and with less security
Browsers are forced to implement standards like CORS, single-origin policy, and multiple levels of SSL certificate validation and thus are more secure than most of native apps. How do you know whether that mobile app is not signing in over HTTP? In a web browser it's obvious instantly.
> motives to decrease dev time and increase ability to spy on users and extract rent from them.
Literally the worse what can happen over web browser is tracking based on various forms of fingerprinting. Native apps? MAC addresses, SSIDs, serial numbers - EVERYTHING is available for the native app to send ANYWEHERE, even over HTTP.
This is the only reason we have an SPA to begin with-- small team writes a single frontend and deploy to web, iOS and Android via Cordova, Windows via Electron, and (previous) Chrome OS via the now deprecated Chrome App APIs. If we didn't need to support the full experience on all these devices, SPA would be way overkill.
How's that working out when there's more than one browser you have to account for? What's the difference between polyfill or some framework, and something like Qt or SDL?
Or I suppose we could just all use chromium, but we could also just all use Windows.
> What's the difference between polyfill or some framework, and something like Qt or SDL?
As a user, I usually can't even tell when they're using a polyfill on the web (except when they stop, like GitHub did with type=date). (As a developer, I often can't tell the difference, either. Some of them are that good!) So long as you generate HTML/CSS/JS, it doesn't matter to me how you do it. That's as 'native' to the web as you can get.
I can spot Qt a mile away. A lot of the visuals look wrong and a lot of the controls don't behave right. It's frustrating to use, and I always slow way down and double-check my work because, e.g., popup menus show the 'accept' animation even when you cancel them.
Consider that maybe there are uses for software where the web isn't necessary and isn't even the first choice.
You're a hammer, so everything is a nail. The reality is that the web is a horrible choice for a whole lot of things. It's a document platform with parts of an application platform shoe-horned in and bolted on, and the result looks like a garbage fire to people who come from the land of native software.
I'm not sure I understand why browsers getting closer to native apps ruins anything for anyone else. You're still able to hammer your nails however you want.
I'm sure it's nice for you, but users like me aren't happy that every mouse move and page load is cataloged and studied and shared with partners. At least with a native app I can add a firewall rule to restrict it's ability to use the internet.
It's equally possible you're doing the same thing by forcing users to download a native app. It's kind of hard to talk about in the abstract. Some things work better in an app, for other things it adds nothing notable.
Not sure exactly what you mean by React NativeJS but perhaps React Native for Web (https://github.com/necolas/react-native-web) is along the lines of what you are thinking?
Works remarkably well. It’s already used for Twitter’s mobile site
Native has downsides too, like having almost zero control over the client and being unable to link other people like you can on the web. Just a bunch of silos by design.
Native is only a trade-off that has great performance at other expenses.
Not always. There are times when you don’t want to download an app for every little thing, though the opportunity to be able to do so is nice. There’s a reason we have browsers and not just everything coming through in its own individual app.
I didn't view WASM on its own as the big differentiator. But, it is one of many things that's closing the gap between native apps and web apps. As you mention, it's useful in some situations.
Having developed with nodejs since v0.4, went through jquery => backbone => angular (1) => ember => vue => react, written stuff in several incarnations of javascript (including coffee and typescript), used build tooling from grunt to webpack and customized browserify, even built stuff with meteor... i can‘t bear it any longer.
Actually now we are full circle again. Files that mix css/template/logic with FOTM syntax, add some database calls during SSR and you have basically PHP. Just more complicated tooling. Deploy your frontend on S3 and its similar to FTP to Apache Servers, except you can‘t update just individual files. Run your backend on AWS lambda and you have stateless backends like ... PHP, but with cloud vendor lock-in. State Management like „Flux“ that poorly resembles state machines on top of JS shortcomings.
I am personally switching completely to elixir/phoenix to do anything web-related and can solve things cleanly within minutes. Also when Phoenix LiveView finally arrives, it could be groundbreaking and replace many usecases of modern SPAs.
I used to feel that way, then I met a one javascript developer in particular who really made me see it differently. I won't get into those here, I just want to tone down the "probably don't need" into a "don't necessarily need".
As a predominant back end developer, I do feel that the complaints from the article are due to inexperience or misunderstanding:
1. stateless requests: You don't have to cache any state by default, just like server side. You start caching to improve performance and caching is always one of the big 2 problems of computer science. Don't cache if you don't have to: stateless has benefits.
2. Reinvent browser features: use your framework! This is a solved problem. I am not sure what the Angular or React solutions are but with vue just use the vue router.
3. More mature tools: backend suffers from this as well, I know a lot of mid level software engineers that are always chasing the latest fads. Microservices, containers, serverless, etc. The biggest issue I had when I tried to do serious frontend development is just not being aware of the tooling and how it works.
Don't get me wrong though. Sometimes an SPA is the wrong choice but it would be hard for me to say if that is usually, rarely or a toss up.
I think many places that go from server-side rendered to client-side rendered SPAs do not hire a bunch of front end experts when they do so. Then people experience a bunch of problems because of the fact I point out in 3: lack of awareness of the ecosystem. On the other hand, there sure are a lot of diva developers who don't like working with old technology (for example, PHP), and this probably causes a lot of the front end framework churn. Just like picking up a new language, it takes time to produce idiomatic code. Of course, for a new framework it takes time for the idioms to develop...
Google isn't the only search engine. But even if that is the only one you care about, Google said themselves in last years IO conference that it takes them several more days to index a client rendered interface, since they have to send it to a rendering queue, and the line is really long.
> I am not sure what the Angular or React solutions are but with vue just use the vue router.
For React there's a couple, but most of them boil down to the same basic idea that you've got switch statements that decide which components to render based on router state (rather than there being anything "special" about routing entry points), and then something like a <Link> component that just acts like an <a> tag but triggers the client routing change instead.
I used react-router before but absolutely hated how it mixes presentational logic with URL matching. For new projects I just use a small routing helper that’s written using React context and that performs URL matching the old fashioned way (a list of pattern with parameters that are routed to specific components). Works really well on all modern browsers and is less than 200 lines of code. It even allows for reverse routing (use a view name and parameters to generate a URL) which to my knowledge isn’t implemented in react-router.
> I used react-router before but absolutely hated how it mixes presentational logic with URL matching.
You may like redux-first-router, which has the URL literals as part of a routemap attached to the Redux store, and then has all routing in the app actually just be the dispatching of Redux actions. Your navigational components then end up with stuff like:
<Link to={{ type: THAT_PAGE_WITH_THE_STUFF }}>Link text here</Link>
...where the Link is actually just a convenience helper component wrapping <a> that dispatches the action and provides a browser-friendly href reverse-engineered from the routemap if possible.
Also, in the favor of SPA's you can consider the horrible state of repeating post requests when users press the back button on server rendered multi-stage forms (like purchasing a flight ticket). Of course, you can just avoid implementing multi-stage forms via POSTs like this and I wish airlines would stop.
If you implement your SPA with a service worker and use cacheable GET's properly, your SPA can work offline and survive temporary network glitches (like on a train) in a way that server rendered apps never can.
.NET is not that simple either, you are just used to it. Beginners will think it is confusing with .NET, .NET Core, .NET standard for example.
There are many options in the front end sure but when you just pick something and learn it then it is not very difficult to get started.
Just start with for example just React or Vue and don't add any state management. Create the apps with their CLI and follow the tutorials on their homepages.
`node_modules` directory topping 60+ mb means nothing when the final product is an optimized bundle or a `node` process loaded in memory. A large majority of developers don't care about this because they're just looking to get actual work done... not sure why you're trying to "fix this".
I'm also not sure what you're talking about when it comes to unclean code and complicated tooling. The tooling is dead simple... much simpler than the NuGet/IIS/OWIN nightmare that is C# development.
I think you're very close minded and you'll likely be stuck in .NET land forever. And that's okay if that's what you like or if it's what gets you a paycheck. But to completely dismiss this ecosystem as if it's not productive... it's just a sign of naiveté. Good luck.
It's really down to language and ecosystem. JS as a language and NPM as a ecosystem are not as productive as C# and the .NET standard library, framework and Nuget.
With WebAssembly, C# Razor Components will soon be able to run either server or client side and still maintain the same highly productive development that's missing from JS.
It's not as productive. Anyone can create a REST API in any language in a few minutes, that's the easy part.
Building a complex app is different though and much easier and faster in a proper environment that has strong typing, OOP, interfaces, reflection, dependency injection, a solid standard library, and more. Being able to use that same environment to create frontend views and code will greatly improve productivity compared to the current Javascript frameworks and limitations.
Strong typing is admittedly great and there are solutions to introduce that in JavaScript. However, this is hardly a dealbreaker in complex apps written in JavaScript.
OOP, interfaces: debatable and unnecessary fluff. There are plenty of productive languages without OOP. Example: Elixir. And there are plenty of productive languages without interfaces. Example: Go.
Reflection is unnecessary in JavaScript. You can access any property within an object dynamically and the language is interpreted, so there's no need to perform fancy reflection operations at runtime.
Dependency injection is an engineering pattern. You can apply this to almost any language. And ironically, plenty of JavaScript backend and frontend frameworks have attempted to use it successfully: Angular, Ember. Hell I even wrote my own DI layer once upon a time. https://github.com/divmgl/nwire
I'm sorry, I really disagree with you. I believe C# has the ability to be productive, but there is just no way you're going to convince me that it's superior to JavaScript and its ecosystem. There's a lot of disdain on Hacker News for JavaScript and it's honestly beyond me.
I pretty exclusively use .NET backends with VueJS frontends. You get all the power of the MS devtools for the backend, near total separation of backend and frontend logic, and then you get all the SPA benefits in the frontend. I absolutely love using SPA tools for frontend development (you just have to spend a year or so with them and really get comfortable, so maybe it's stockholm syndrome), but I can't imagine switching to a dynamic language for backend development.
I may switch things up once WASM is further along. I would love to be using C# on both sides. I would still want very clear backend/frontend separation though.
> Coming from the .NET toolchain and expecting a lightweight, easy to start with approach I was yet again totally shocked.
> I stopped working when my node modules directory topped 60mb and I still hadn't made a data layer.
This is cute.
I have a 40gb virtual machine with Windows + VS Enterprise and SQL Server, that I have to use to work on a single .NET project that can't be migrated to .NET Core yet.
60MB is a significantly lower amount compared to 40GB, but I don't think it is fair to compare the disk space of an operating system, IDE, and database server to a directory of javascript libraries.
If a developer cannot meaningfully work within .NET without an IDE, it absolutely counts. Just like someone on the frontend cannot work without babel or typescript.
Those libraries add specialized tooling for the project in question. Instead of downloading a runtime that has a huge std, in JS everything is downloaded on a per-project basis.
I cannot speak to .NET, but want to work with python? Bring in one library and it'll top 40MB (e.g. numpy).
I don't get why so many people complain about `node_modules` filesize, it's not even an issue to think about.
They complain because they're under the impression that everything in node_modules will end up shipped to the browser.
It's also more visible. Python libraries are hidden in the environment far from your shell or file manager. So you don't know that your virtualenv weighs 300mb. But node_modules is right there, you can't help but look.
In other words it's a complete lack of experience, regardless of how adamant the OP is about their skills.
For a while .NET Core also had a folder within the project for third-party NuGet modules, and for a simple web app they would go into the 200mb, and that's without the compiler itself. Now those files live in a hidden folder (or were absorbed by the stdlib), and nobody complains about it anymore.
Initiatives like Yarn's plug-and-play [1] would have the side effect of being great marketing for Node.js development.
It sounds like OP was trying to make a beginner-level sample app in Node.js - is your .NET app of the same nature? Judging by the mention of SQL Server, it's not.
You could use Blazor to export to webassembly, but it includes the entire .NET runtime, so the payload is huge.
It's a bit silly to say you quit when you topped 60mb in your node modules directly, something you never have to look at and doesn't represent what gets built in to the final app. There's tons of dependencies when dealing with the .NET toolchain.
There are hundreds of directions you could go in, and I consider that a good thing. There are choices, but there are recommended paths for beginners as well.
It sounds to me like you're hating on a toolchain that you don't have any experience in.
I understand the toolchain juuust fine. I have been making HTTP and browser applications for two decades.
The technology landscape is absolutely ridiculous if you want to do things for the web.
Each browser has its own standard, chrome is the new IE6, the industry is hacking together assembly languages to port from other technologies, preprocessors, minification, state and what have you not.
The web today had been tweaked beyond recognition and while the industry is doing so, most of us forgot the beautiful platform that resides underneath.
I love HTTP, HTML, CSS and JavaScript, I really do, but I really believe there is a huge tendency of amateurish approach towards making the web a better and more standardized place.
Back in the day, we had much less choice, and that made working with the web a lot more joyful.
I've heard this repeated a few times, and it's utter nonsense. Unless you're deliberately going off into the weeds, a full featured SPA works the same on Chrome, Safari, Firefox, and Edge. I don't even bother testing on multiple platforms anymore; they just work.
I did web development in the IE6 era (and before). This is nothing like that.
I do believe the live standards from whatwg is a good example of some vendors making it possible to implement features before other vendors do.
It creates a gap, it creates a constant drive forward which again seems, IMO, to sometimes be about vendor competition instead of the greater good of the web.
I don't doubt your experience, but when people say "toolchain" in the context of front end development, it's usually a reference to the dev environment and build toolchain, not the HTML/CSS/JS technologies themselves. I've been focusing primarily on front end development since 1999, and while I also hate the current complexity in setting up a complex JS client, it allows us to scale far beyond what was possible back in the jQuery days, and it has made my life much easier. It becomes a problem when people suggest that you set up babel, webpack and hot module reloading for a site with a couple of forms.
While I'm excited about WASM and .NET on the frontend, I don't think Blazor is quite the solution I want. (Getting there though!)
If Evan You, Anders Hejlsberg, and two computers were all locked together in a room for a month or so, whatever emerged from that room is what I'm looking for.
Razor syntax has always felt clunky to me, and I tried very hard to like it when I first started with branching into web development from .NET.
I'm hoping that someone will use WASM very effectively to create some XYZ framework that's revolutionary. Then, Microsoft can do what they did with Java and make a version of it improved by hindsight. I don't think that Razor syntax would be the basis for whatever that is.
FYI: Blazor is using the Mono runtime and is still in experimental stage. It's 2MB raw, can be compressed over HTTP as any other file, and can get much smaller after linking and optimizing the build.
Early tests have made the whole package as small as 200kb which rivals many JS builds but with far more capabilities.
Last time I followed the official .NET tutorial I was also shocked when I had to download +1.5gb of dependencies. It was more than 4 years ago though and the landscape might be a lot better now but I don't think they managed to keep the whole thing under the 60mb mark. The tooling is just simple and clean when you've been working with it for a long time.
Riot is a good solution for simple SPAs if you don't like huge toolchains. It gives you web components and DOM binding and all that, all in a 15 KB package that does all the compilation in a few milliseconds on the client.
No configuration of babel or webpack or whatever to worry about, just host your app as static files that point at your API.
I'm with you. I'm not employed as a developer, and am certainly not a web dev, but a few years ago I (perhaps foolishly) used some spare time at work to create a tool to help the people who do the non-sitting-in-an-office work in our company get more accurate and relevant documentation for their day-to-day workflow that they could access via a cheap tablet connected to our WiFi.
It grew, as projects do, out of its original simple use case and now it needs to be usable in scenarios where network access won't be available for most of the work day, which means I need to rebuild it --in whatever time I can manage to devote to it, dev not being my primary or even secondary responsibility-- to deal with that and better handle the functionality we tacked on later.
After a review of my options, which unfortunately doesn't seem to include writing a native application (for reasons I still may be able to work around), I'm thinking that my simplest option is to just write a single page of JS that writes HTML to the DOM directly and works with data entirely locally, synchronizing it with a server API (.NET) when available. Basically, just a client application written in JS. No special frameworks, no complicated toolchains. Even that is a pain in the ass because the web world hasn't quite worked out how to store local data in a non-stupid way.
> I'm thinking that my simplest option is to just write a single page of JS that writes HTML to the DOM directly and works with data entirely locally, synchronizing it with a server API (.NET) when available.
I don't know what your requirements are, but you've just described an SPA framework. Do you think it will be easier to implement your own instead of using something like vue or react? Also, localStorage is supported by all browsers and all you need to do is de/serialize your data to JSON when your data changes.
- Redux with a middleware that saves the whole state to localstorage automatically
- Some simple background timer stuff that uses ononline and onoffline events to know when to poll for updates, then dumps the JSON contents from the polling into the Redux store
- Some React components that act as one-way output of the stuff in the Redux store, optionally with a basic routing lib if some menus/navigation are necessary
Then stick some Progresssive Web App stuff in there so the whole bundle can work offline entirely from browser cache.
> Redux with a middleware that saves the whole state to localstorage automatically
I don't want to save the whole state automatically. The state isn't complicated. Even the data isn't complicated.
> Some React components that act as one-way output of the stuff in the Redux store, optionally with a basic routing lib if some menus/navigation are necessary
Or I just write some javascript that creates a view of based on the data it has cached locally and updates that view when the user interacts with it.
This is what we're talking about. I have a relatively simple problem, I don't need to pull in additional dependencies in the form of a framework that's just going to make things more complicated and require me to learn its paradigms.
> I don't want to save the whole state automatically. The state isn't complicated. Even the data isn't complicated.
If you don't want to save the state, why mention localstorage in the first place? The point of using the Redux thing would be to automate that process, so that you don't have to manually save/retrieve anything to localstorage yourself.
I'm currently building an app that works nicely as a web app, but it needs to store gigabytes of data and work with only intermittent network access. I'm considering trying to bundle the server-side code into a simple Windows binary that just fires up an HTTP server and binds to 127.0.0.1. Would that work for you?
That's essentially Electron. I'd considered that, but if I'm writing a native application component anyway I may as well make the whole thing native instead of using wonky web tech. I'd like to do that, make it completely native, but right now there are factors beyond my control that I'd have to work around first.
I come from the .Net toolchain as well, no longer develop full-time, but write tools for my business as needed. I use Angular (6 or whatever). They talk to a .Net (core) server as little as possible. What I find is the iterative dev turnaround time, that cycle between find a bug - fix it - test it, is so much faster with angular than if server-side rendered. It's a joy. That same cycle on server side in .Net - change some .cs file and check that fix quickly - , slowly rather - a real pain. That alone drives the choice for me.
I have modest skills as a developer. I was trying to convert an old static web site into something more interactive. Without really thinking it through, I started building a SPA. I got stuck on the SEO part. I found it innately complex, but the real trouble came from trying to bring together the disparate sections of the old static site while preserving and abetting SEO.
One day I just ditched the SPA and rebuilt the whole architecture with NodeJs and Express. I was done in a few days. It could have gone even faster, but the original static site was really a mess with years of accumulated bad decisions embedded in it.
I know this is just one data point and not really proof of anything. Nevertheless, the linked article made a lot of sense to me. Most of the bulleted points resonated with me, but none more than the SEO issue. There are solutions to the SEO issue, but I personally did not find them easy to implement. If I were part of a big professional team, and we really needed a SPA, I would have called this one differently, but I was working on my own, and I didn't really have the sense at first to see that I didn't need a SPA to achieve my goals. I was perhaps a bit too susceptible to the hype without enough experience to really understand the issues involved.
Thanks. This does look interesting. It's hard to keep up with all the frameworks, but this does look like something worth investing some time in. I'll check it out.
As a FE engineer, SEO is the one area of SPAs that does feel like the wheel is being reinvented to accommodate its existence. It's unfortunate, there are solutions, but it's a little annoying to deal with.
I can't agree with this article at all. Having an JSON API and a small web app bundle that you can deliver with a highly-available CDN removes a ton of scaling problems related to SSR and gives a clean separation of concerns both from a managerial and architectural standpoint.
It also makes testing dead simple: you just make contracts on what the response bodies will look like and just feed mock data structures into your stateless web app. This allows the API team to make changes to the API layer with confidence that as long as they don't change the contracts with the web app, everything will still work.
For new development, I reach for SPA tools (like VueJS with Webpack) fairly quickly. The reasons for this are:
1. Reusable web components.
2. Clear separation of backend and frontend logic.
3. Using the latest version of javascript.
I really like HTML/CSS/JS as tools for building GUIs, but I feel HTML/CSS specifically suffer from the inability to make components.
I think there are definitely instances where there is no need for these tools. I would genuinely like to know how to manage the items listed above when this is the case. ie Recommended tools for when I go "SPA seems like overkill for this... what are my other options for this functionality?"
Once you know how to use the tools (Webpack with Hot Module Reloading, React/Vue/Whatever, Storybook, TypeScript), it is hard to work without them.
They offer a ton of advantages, especially speed of development if you have a clear separation of frontend & backend logic. If you can mock your backend & develop the front end all by itself without any other code needed, you can go at crazy fast speed. You are also able to focus on UX/UI without needing to think at all about the backend. I feel there is a ton of value in this, whether or not your app is a SPA or not.
I think tools like Gatsby will make building actual SPAs easier down the road. They offer huge speed advantages the longer someone is on the site. Though one could gain a lot of these with just preloading content & HTTP/2 as well. As the article said "It all comes down to tradeoffs". I would also argue what resources you have available & the value of speed on your site.
If you want to stick to JS, then Node + Express is a fine stack. You can always use React to add functionality to specific parts of the site if you find you need to later.
You may want to look at Next.js, which is an SSR/SPA framework using React components that also has a "render entirely to static files" build mode option.
Totally agree with the article, the spa hype has produced a lot of crappy slow web sites and crippled productivity of many teams for years. I think ppl in the industry are way too young and have the bad attitude to nod add tools in their belt but keep only the last one that has hype. Spa are like applet or Silverlight, just different tech, same goes for ws* vs rest api and so on...
True, if you do not stay long enough to feel the consequences of your decision you do not learn from those years. We do not usually hire ppl that change job that often, but we are not in a silicon valley kind of enterprise
Because studies have shown that's the only reliable way to get appropriate salary raises. If companies properly managed salaries for existing employees that wouldn't happen so much.
1) CRUD / data entry systems: stay with request-response.
2) Complex webapps with snappy functionality that need to feel "native" - whatever that means: think about an SPA. Then realise that mostly what you need is (1).
3) Corporate homepages / brochure sites / product sites / blogs: use a static site generator like Hugo, Jekyll etc.
It's amazing what you can do with a staticgen site now
The concept of a SPA is a total hack of web patterns. I predict in a few years we'll refer back to SPA's the way we do now to AJAX or DHTML.
We're getting closer to the best of both worlds, where we SSR pages and then "hydrate" them with JS components. The tooling around this isn't great yet, but it's definitely all there.
1. It's like saying you don't need Rails, just use Sinatra and if your app really needs it then use Rails. I'll pick rails even for a super simple project because I'm very comfortable, quick with it.
2. "You don't need the complexity of SPA or javascript fatigue" and then you install webpacker gem that wraps around webpack and not only you have a headache of webpack but also of a gem that wraps around it. And then you need some front end libraries and you start including them in in the way that feels like a workaround.
I mean no disrespect to these wonderful tools, I appreciate the hard work being put into these gems, and I will admit I didn't give it TOO MUCH effort to learn. I tried it. didn't feel right. moved on.
I've just decided for myself that for now I'm gonna keep my backend ( ruby, db, server ) in one mental bucket, and all the fronted ( css, js, html ) in another.
For me to go traditional Rails way it has to be a super simple app, at which point there will probably be other tools to solve the problem.
I couldn't disagree with this article more. Developing SPAs is easier than server-render applications. The problem is React, Redux, and other such libs make this more complicated than necessary. React is all about surgically making the smallest possible change in the DOM to refresh the page. But is that really needed? Most of the time it is not. Why not re-render the whole page? This is what happens in the case of server-render applications any way, right? Turns out 99% of the time it is performant for the SPA to rerender the whole page. Instead of Angular and React, if you use simple libraries such as UIBuilder ( https://github.com/wisercoder/uibuilder ) and MVC router ( https://github.com/Rajeev-K/mvc-router/ ) you can build simpler applications that work well and are super easy to develop and maintain. Each of those libs is less than 500 lines, so super easy to learn and use.
This article says traditional web servers are stateless, but in the case of SPAs servers are stateful. The opposite is true. Traditional web servers have session state, but in the case of SPAs the servers can be stateless because all servers are responsible for is persistence and query/search.
This article says maintaining browser history is a mess in SPAs. Not true. The same MVC architecture that works so well on the server can be done just as easily on the client, see this lib: https://github.com/Rajeev-K/mvc-router/
This article says server-rendering has fewer more mature tools. That may be true. There are so many new tools for SPAs. But you can ignore them and build SPAs trivially using the libs mentioned above.
This article says server-rendering is better for SEO. Not true anymore. Google and Bing crawlers now execute javascript to crawl your content. This is more work for Google and Bing but not more work for you.
If you know how to do it SPAs are the easiest and best approach because all the server needs to do is implement persistence and query/search using a REST API. If you later need a native mobile client this approach is already more compatible with mobile than if the server renders HTML in addition to persistence and query/search.
> Developing SPAs is easier than server-render applications.
Not sure about "easier". I'm a backend person so take this with a grain of salt but, to me, nothing on the web is easier than doing everything server side. All of your code can be in one language (plus a template) and the same build.
Consider what it takes to make a change in each model. In an SPA with one of the frameworks mentioned, it requires several changes, across directories and languages in both the front and back-end, and usually two different build chains.
I think that "I'm a backend person" says it all -- most of the people in this thread are probably not JS natives or front-end natives. All of the complaints about JS fatigue, or not knowing how to use client-side routing are because you've done things differently on the backend. Is it such a surprise that front-end frameworks and tools make more sense to people who actually enjoy and have experience working on the frontend?
If you provide an API schema, with a SPA the whole frontend can be developed separately of ever touching backend code. Okay, so you changed the name of model.thing to model.anotherThing - quick change in the reducer that is consuming that end point and call it a day.
You have to deal with multiple languages in any case: Java/C#/etc for the server logic, HTML for rendering and CSS for styling. You also have to deal with whatever syntax you are using to embed expressions in the template. If you use SPA there is one additional language (unless you use Nodejs for server logic) that's true. And you also have two different build chains. But the advantage is that the server logic becomes much simpler because you don't need session state or rendering logic. Your server can focus on being a stateless REST service which is more scalable (since you don't have session state clients can connect to a different server on each request). Your server is also more future-proof because it won't need to be rewritten to support native mobile clients.
> Your server can focus on being a stateless REST service which is more scalable
You can do exactly the same with server side rendering. In all the applications I've built over the past decade, the only state I've had is an encrypted session cookie to say which user you are logged in as - but that's send by the browser on each request, so it doesn't matter which server handles it.
The urls I've built are basically the same as you would for a REST API, to view a widget you do a GET /widgets/1, to view the form to edit you do GET /widgets/1/edit, to save the update you to PATCH /widgets/1, which redirects you to the list of widgets at GET /widgets. I admit that trying to fit multi-step workflows into this scheme doesn't always fit so nicely, but with good API design (that's what you are building, an API for the browser to call directly without JavaScript) you can make it perfectly stateless.
You don't need React, Redux, and other such libs, true.
But you're missing the point of them. It's to prevent the problems that cropped up after years of jQuery development.
Too many side-effects and poor state management lead to very hard to find bugs.
When you follow the redux (or whatever state lib) flow you prevent a lot of these issues.
React, Redux and other such libs solve the problem while overcomplicating the programming model. My point is that 99% of applications don't need the complexity introduced by surgically making the smallest possible change in the DOM to refresh the page. There are simpler libs out there that eliminate 99% of the complexity of React, Redux etc while providing 99% of the benefits.
Not true. With Redux you write reams of actions and reducers and other such unnecessary crap in the name of state management, when in fact most client apps don't have state, all they do is fetch data from the server, display it, send updates back to the server.
React used to be a simple lib, now it is getting more and more complicated. Look at the libs I mentioned they are way simpler.
>you don't even have to use JSX
But JSX is the good part of React. You get compile-time checking of your expressions if you use TypeScript and you get syntax coloring, intellisense etc for both HTML and JavaScript.
If you don't need state, don't include it. That's the beauty of React. But as far as a state management lib goes, Redux is one of the simplest, go look at the source.
I agree JSX is very nice. It's one of the best features of React, and another reason React is a great templating lib. My point was you don't need it. React does a lot of other nice things like browser compatibility, event management. If you want a smaller implementation, use preact or some other template lib.
When dealing with React and Redux you are just dealing with functions. You could do everything in pure functions.
React requires too much incantations, rituals and ceremony. You have props and state, context, error boundaries, refs, keys, you have to figure out where state should live, etc. You make a component that contains state. Then you want to use it in a component hierarchy -- now the component is supposed to have props not state. You make a component that has props, now you want to use it at the top level -- now the component is supposed to have state, or have an otherwise unnecessary wrapper.
You don't have to deal with any of that crap.
The best part of React is DOM diffing and incremental screen update. Obviously this is only useful if your application needs to update screens it previously rendered. In fact I'd argue that React is only useful if you need to incrementally update complex screens, because simple screens can be re-rendered completely and no one will know the difference. Very few applications need to incrementally update complex screens. If your application doesn't have this need you can use simpler technologies that don't have the same "Care and feed" requirements of React, such as UIBuilder: https://github.com/wisercoder/uibuilder
You're dramatically overexaggerating the complications of global state handling in Redux. For a simple app, you could just use the useState hook, and pass the state-setting callback down into children components:
To reply to your last comment, each project is different, and if you just want a few things on a page, sure use a small lib like what you suggested. But at a certain point you start reinventing the wheel and no other developer will be able to jump into it. You need a framework for large projects with a team and potential future members.
But the very fact that we're having this debate is proving my point. React's programming model is unnecessarily complicated. JavaScript + DOM is all you need. The simple libs (each less than 500 lines) I pointed to get you close to this without sacrificing productivity or code maintainability while keeping the programming model simple.
First off, this is not “the point of React”. Second, direct use of setState is not somehow the only path to focused DOM updates with React. In order to understand this better, I suggest you read up on the topic of Reconciliation in React - https://reactjs.org/docs/reconciliation.html
There are better ways to build components. The problem with React components is that they are only compatible with React. What if there was a way to build components in a better way, and what if those components were compatible with all current and future frameworks? There is a way to do that. Look up W3 Web Components specification. There's sample code here: https://github.com/wisercoder/uibuilder
So another library. From the examples i am not impressed. Web-component are not panacea. For me reactjs is still the best frontend framework out there.
I've been making SPAs for a couple of years now and I totally agree.
Not only the complexity of development is increased, but there is no real benefit for the vast majority of use cases.
I think there is merit in using an API though and clearly separating data from presentation.
What I've been doing lately is using Jekyll with Vue components for some in house projects. It works great.
Another option I've been trying out is doing SSR in JavaScript on Zeit Now monorepos. Haven't used it in a real project, but so far it's awesome. You can keep using all your front end knowledge, but render each route on the server. No more managing state (Redux, Vuex, etc) or router.
While I've long been more comfortable with server rendered pages, I feel like we're oversaturated with this sentiment. I don't think it matters all that much.
The message is build with what accomplishes your goals and works with your team's skills.
The notion that SPAs are only good for certain types of applications or organizations doesn't make much sense to me.
Building server-generated web sites works faster for me because I'm still more comfortable with it. SPAs make concessions but so do server generated apps.
> The message is build with what accomplishes your goals and works with your team's skills.
Unfortunately most teams cannot be trusted to pick the right tool for each job without overcomplicating the planned implementation. Ego and the yearning to do “cool stuff” conspire to derail projects that could have been built without fuss using simpler tools.
>Unfortunately most teams cannot be trusted to pick the right tool for each job without overcomplicating the planned implementation. Ego and the yearning to do “cool stuff” conspire to derail projects that could have been built without fuss using simpler tools.
Force them to only use simple tools and the good ones will move elsewhere because they know that being stuck on just the simple things is going to limit their careers.
edit: And losing them will probably cost you more project velocity than you'd ever gain with different tools.
Good riddance! A project is undertaken to achieve some specified result, not to advance a career or learn some new tool. Don’t get me wrong: those lofty things are welcome when they occur as a byproduct of developing commercial software, but these cannot be the driving factor behind decisions that affect the bottom line.
Part of working with humans and managing humans is understanding they're human and not machines. And keeping those humans happy does very much impact the bottom line. If spending 20% more effort on a project retains engineers that speed up projects by 30% then it's a net gain for the business. Bad companies and managers don't understand that and then wonder why all their engineers are bottom of the barrel (or rather why their projects end up such disasters while those of their competitors don't).
The answer to whether a single-page app is appropriate for a given project needs to consider product requirements, team structure and available resources.
Libraries like React are awesome for breaking down complex (or even not so complex) UIs into story sized chunks that can be tackled by different engineers or even different teams. This is one of the biggest reasons to consider using them, IMO.
Even in the case of relatively unremarkable CRUD application, if the backend is split across multiple services and teams it may be entirely reasonable to choose to build a SPA frontend with a dedicated team.
On the other hand, if you're building a Rails app with a small team, and most engineers are working full-stack out of necessity, a SPA may not be appropriate.
As companies grow, I've found roles tend to become more specialized. Your decision to build a Rails web app early on could be considered legacy cruft (by some) down the road because it can be difficult to break down and deliver a feature across the full stack if you're not accustomed to building web apps that way.
There are tradeoffs to all of these approaches (including the hybrid approach). Ultimately, you need to do what's what right for your product and team(s), and make your technology choices intentional.
The answer to whether a single-page app is appropriate for a given project needs to consider product requirements, team structure and available resources.
If the team structure is the problem, you should disband the team
and rearrange the structure so that it produces the result what you want. Trying to fit your product to the existing organization is not a good idea.
Conway's law: "organizations which design systems ... are constrained to produce designs which are copies of the communication structures of these organizations."
In theory, but you'd need Steve Jobs or Elon Musk level of clout to get that to happen. You'd need to be at the top of the organisation and pulling the puppet strings. Might be OK in a startup, but unlikely in a medium to large sized firm.
There will be people who need to make you fail or they are out of a job - they'll care more about keeping their job and paying their mortgage than you do about SPA architecture (unless you are at the top and have the vision as to why what you are doing matters.).
The main problem with SSR is that the moment you want to do something a little bit outside of the-happy-path of your framework o choice, you're knee deep into sh.
Let me give you the simplest possible example. A form with multi-dependant inputs: you select an option from a dropdown, and depending of the choice you made, you see another dropdown with some options, or maybe an entire new set of inputs. Maybe there is a button that will open a popup with another form, dynamically generated based on what you choose. Or maybe there is data you must dynamically fetch from the server, based on some combination of actions that the user did.
You can play the ".show()" and ".hide()" game with plain JS, but if you have more than 5 inputs, I promise you, you'll be really sorry for choosing that method.
You can also "inject" somehow any SPA just into that particular view in your project, but then you'll be already dealing with the cons of both SPA and SSR. It doesn't pay off.
I have been doing all types of FE and BE development, and what has given me the best results is making the BE a REST API and doing the rendering on the frontend.
This is where the hybrid approach they mention in the article really shines. Embed front end frameworks where you need it, and stick to SSR where you don't. It doesn't have to be a binary choice.
Yes, that's what I said in my comment. But if you choose that path, you automatically have to deal with the problems from both worlds. "How do I configure webpack?", "Why is babel not working?", "How do I do _this_ or _that_ in React or Vue or whatever?". Going the hybrid approach is choosing to deal with the problems from both worlds.
But configuring webpack is usually just an initial set-up cost. I've never had to go back and rejigger webpack once it's set up. You might have to touch it again if you make major changes to how you serve assets or something, but these one-time costs are part of development.
> Going the hybrid approach is choosing to deal with the problems from both worlds.
This is true of any technology. Every framework, language, library, etc. comes with a cost in setup, design, maintenance, etc. For us, the cost of dealing with problems from both worlds is much, much lower than trying to shoehorn a SSR app with SPA-like functionality. By limiting the size and scope of the SPA, you avoid a lot of the really hairy state management problems that can arise when an SPA is trying to keep track of too much state.
I have the same opinion. Building SPA is f* hard and time-consuming. But it depends. If you know how to build SPA fast, then, by all means, go that route. (As a solo dev or small team)
I use Rails, but Rails views are a disaster. You can use a lot of different patterns/gems, but still, logic is highly coupled with the view layer. Personally, I like Phoenix approach with templates + views. But still writing script tags makes me cringe a little bit.
But I wouldn't discourage people from using SPAs, though. If you are gonna have a lot of buttons, modals, different tables, charts, forms and stuff like that, I would go SPA. Or first serverside -> SPA. Especially, when you are working in the team, it's so much easier to tell one person to craft this json api and another to craft this design with a consumer for the json api.
That become long... in short: if you have a small team or solo go server side 99%. If you have a big team or app that's gonna be very heavy UI -> go full spa or go server(mvp) -> spa
Take this with a grain of salt, as I only recently came across it and haven't used it, but the Trailblazer framework looks like it has a good way of getting logic out of the views.
I've been using parts of it on most Rails apps I've worked on for the last few years.
The form object pattern (Reform) really helps when you need to update the same model in different places with different validations.
For example maybe an Order only needs a price when it's created, but needs a invoice number (and some other validations) when marked as paid, but an admin should be able to override those validations at any stage. If you are doing something like that with standard Rails the model is going to end up as an untestable mess, where as the form objects can be tested on their own.
My only complaint is that the creators of Trailblazer really don't seem to like Rails, so trying to get them to both work together can sometimes be a bit tricky. And the documentation is lacking if you want to do some more complicated things.
Thank you for your thoughts on it, I'm intrigued enough to really want to look more into it. Even if I don't get to use it, I think it will give me some ideas that I can apply to other projects.
Not quite. Lot's of applications have SEO for their main content. Social networks (reddit, twitter), marketplaces, shopping sites (some shops, like nike's, are quite complicated js-wise), forums (stackoverflow for instance)
It's often a better user experience to let them click directly into the content they are looking for instead of making them run through a landing page.
I have experience building both SPA apps and server-side templated apps. They each have their strengths and weaknesses.
Just as a SPA won't solve all your problems without any trade-offs, getting rid of a SPA framework also won't solve all your problems -- you'll probably need to re-invent some wheels and then discover that your new solutions are hard too.
I think it's good to have a healthy dose of skepticism about new technologies. But it's also important to understand their value and not to hate them just because they're hard. I like that the author tries to find this ballance. Though, honestly, from my own experience, I would rename this title to "You might not need a single-page app."
More than once, I've tried to build something without a SPA framework only to realize that if there is any interactivity at all, it's often just simpler to use a SPA framework in the first place.
> it's often just simpler to use a SPA framework in the first place.
Simpler or more convenient? I've yet to see a production-grade React setup (for example) that is simpler than having either vanilla JavaScript or even jQuery to achieve the same interaction. The amount of tooling required to do simple interactions does not justify the technology for most applications IMO.
How complex were the applications that used those production-grade React setups?
As the number of possible states increases, your vanilla JS solution explodes in complexity when you have to manually define every state transition. The declarative nature of SPA frameworks means all you need to worry about is presentation of your data. If all you need to do is some form validation, then writing an SPA is a terrible idea. If you need to build a UI that functions more like a desktop app with long-lived sessions and complex workflows, trying to manage all of your DOM updates will be a monstrously difficult task. You'll basically end up implementing a slow, buggy version of react.
I used to love SPA's but, in my experience, the most poorly organized SPA code is severely more complex than poorly organized server side rendered app code.
With SPA's, you're usually dealing with some build system, a variety of dependencies, and a swathe of design patterns. At worst, you have everything located in a single file which has all of the above across tens of thousands of lines.
With server side rendered code, you are (at worst) following someone's code that didn't follow the correct separation of concerns. At worst, the spaghetti code will be within a couple thousands of lines of code.
I had a project recently where I ran into both of the above scenarios and I would prefer to debug poorly written server-side code than poorly written SPA code. It's night and day in terms of complexity.
Server-Side rendering tightly couples your front-end to your application server. Scaling the site means scaling up that application server. A bug in one "page" of the app can cause the whole application server to go down.
If you leverage client-side rendering then it's easier to decouple your front-end from the back meaning you can take advantages of things like segregated micro/serverless services and progressive web apps. You can also re-use those services for multiple applications, making it easier to keep the business logic OUT of your pages and in an API layer where they belong.
I agree that SPAs are not the solution for everything, but I think that server-side rendering is on it's way out.
> A bug in one "page" of the app can cause the whole application server to go down.
That doesn't seem like a valid issue. If a bug in a single page could take the application down then the same could be said for the API powering the front-end.
> If you leverage client-side rendering then it's easier to decouple your front-end from the back meaning you can take advantages of things like segregated micro/serverless services and progressive web apps
Your PWA point is valid but I don't think the microservices point is. Microservices add a ton of complexity and can easily become overwhelming. If you get to the point where your application can benefit heavily from microservices then congrats, you've made it.
> I think that server-side rendering is on it's way out.
If anything I think its on its way back in. So many companies bought into the benefits of client side apps and are now seeing the trade-offs that aren't very favorable.
> That doesn't seem like a valid issue. If a bug in a single page could take the application down then the same could be said for the API powering the front-end.
What? The previous poster said coupling frontend / server tightly will result in crash of both if there is a server bug. Your response is that a bug in an unattached API could happen? Of course a bug in your API could crash your API. But at least then it's just your API that's crashed, not the (thousand) servers you're using to serve the front end and every device using them.
If my app runs off multiple API, then the bug in my (for example) commenting API shouldn't prevent users from using the shopping cart API to check out.
> A bug in one "page" of the app can cause the whole application server to go down.
Maybe if you're using node or some other single threaded server like that but this isn't true for multithreaded or multiprocess servers. It might be an argument against node but it's not an argument against server side rendering. Also, it's irrelevant how pages are rendered or what you're architecture is if a bug brings down the whole server--either way your app doesn't work.
You don’t have to use a single server for your business logic and rendering. Separating those two on the backend will ensure you have a clean api that things like mobile apps can hit, while still having a service that renders html for the server-rendered view of your app.
The massive problem with this approach is that more and more the requirements we see are exactly where SPA's shine: real-time elements, rich UI and eventually PWA implementation when/if. I agree that the traditional SSR has served everyone well - but I don't think we need to be stubborn about what has worked vs. what can work.
There are a lot of hidden/implicit requirements when people think of SPAs. In order to do them right the interaction design needs to be worked out in detail with the developers so that everyone on the team knows all possible states of the application and how to best manage that.
“do I need a component library?” is the question I ask when deciding to use react or not.
It’s a totally different question to ask do I need a spa or a server rendered app, both can be dead simple or heinously complex or reasoned away to prove a point...
I 100% of the time want (1) to architect my UI as a collection of atomic, reusable components, (2) get page specific server rendered html per route, and (3) do JS in a sane way (manipulate DOM, manage client state, and support a series of interactions that do not reload the page.)
I think all of your requirements could be met in a myriad of ways. E.g. Django templates/Handlebars can be organized as reusable components, many backend frameworks will render HTML per route, and there are several JavaScript client libraries including Vue and, dare I say, jQuery that will give you a sane way to do client interactivity without page refresh with varying degrees of declarative code style.
I think this means you are sacrificing the component library requirement. There is not a sane way to intermix js,html,css as a single component with dependencies on other components with your approach. What you end up with is 3 very distinct/separate/unique/difficult to maintain solutions across css, js (probably 4 if you include js/html), html.
Vue.js and Aurelia offer examples of how UI components can be organized and composed, while allowing clean separation of structure, function, and presentation (divided along the lines of HTML, JavaScript, and CSS by design.)
The main point is not to limit ourselves to a monotheistic worldview that convinces us, without substantive evidence, that "all other ways are wrong."
The main point is that I listed 3 requirements/wants. Your example of Vue.js or Aurelia sacrifices the requirement for server-rendering.
> Server Side Rendering is a new feature of the Aurelia framework, intended for use by early adopters.
https://aurelia.io/docs/ssr/introduction#how-it-works
For (2), take a look at Next.js. It's a React SSR framework, but there's a static build option that turns every page into prerendered HTML files with embedded JS at build time.
I happened to watch a conference talk on YouTube by the director of infrastructure at Netflix. He closed it out by saying, yes we open source everything, and yes this solution works for us. But just because we do it doesn't mean you should. Do what works for you.
But in reality...I only need it because people on the other side of the interview table expects every engineer to have 3-5 years experience of x,y, z.
One of the biggest reasons I reach straight for React is that I then have only one UI language. Instead of templating on the server in python or c# and then doing any UI updates in javascript on the client, I only have to write templating code in React and it runs on client and server.
You switched from a C# or Python backend to node.js so that you can render React on the server, correct? Or are you doing something fancy to serve react.js rendered contents from a non-js backend?
I agree that the hybrid approach of both server-side templates and SPA-controlled content looks difficult.
Personally, I don't use node.js as a backend. I normally use Django REST Framework (DRF). I may do server-side rendering of the client using express, still calling back into DRF for the data. The important piece for me is that I don't like the idea of generating a page in one language and then mutating the UI on the client side with another language. I just use one language for the whole UI.
One problem we're having with the hybrid approach (Laravel + Mithril) is not being able to reuse common UI components between php & js rendered parts. Laravel has blade templates, and mithril is coded similarly to react.
The other problem is deciding which to use when starting a new feature or section. A page may start out fairly static but end up needing a rewrite when the specs change and start requiring more dynamic UI elements.
Well, the thing is that you don't know if you're "over engineering" up front. That's the whole challenge.
And rewriting down the road because of the wrong gamble can be very costly. Make the wrong bet enough times and you'll see that it's not over-engineering but just engineering for changing requirements.
A classic example is thinking it will be simpler to avoid React and use a few .show()/.hide() toggles. Simple at first. Then as you take on complexity, you start to feel like the lumberjack who thought he could save time by skipping the axe sharpening.
Definitely, which is why I leave room for those unknowns with a some preemptive over-engineering. Worst case, those (well-known, general, popular) abstractions don't get used and the project works. Best case, they really save my butt and the project works. Worth it either way, imo!
It seems like a good 80-90% of the hate of SPAs doesn’t seem to be aimed at SPAs as much a poor programming and poor user experience because of that. In a lot of the cases that people here use. It’s not the SPAs fault as much as the programmers that messed it up. And honestly why do we think that putting it all back to SSR is magically going to fix poor programming?
On the one hand, site like https://dev.to/ that are built in Rails and rival the speed and performance of any _static site_ support the argument that you can just use the tools you know.
On the other hand, to get your Rails site to function that well takes a lot of work - it is by no means the starting point.
Systems like Next.js and Gatsby.js and others are attractive in that A) they offer the ability to use both server-rendered and client-rendered React, and B) exceptional performance is the starting point. It's up to you to slow it down, not speed it up.
It‘s a traditional server side rendered application. But they use a custom implementation like turbolinks and instantclick to change the sites content without a full reload.
So, a question coming from a guy who's been doing Java backend processing for a long time and thinking of making a side project. Was going to go the Angular route, but I'd like to have good SEO. I'd also like to get a POC/MVP up and running to build momentum...don't want to waste time on the front end when it's basic form submissions to kick off data processing.
To show how long it's been since I've done front end...My last 'full stack' development had plenty of tables to style the application grin.
A couple of weeks ago I tried the official Angular tutorial on SSR and found it super difficult. If you're willing to give React a try I would choose Next.js. It's pretty much a Node.js web framework that uses React for its views and has SSR out of the box. It has client side routing, so smooth page transitions, it was also fairly use to style the app with good ol css or sass. Ping me if you have any questions.
Oh I forgot to mention: if you're doing this just so you could learn modern JS then rolling your own solution is all fine. Other than that I would avoid this at all costs.
In that case then do not use a UI framework such as Angular or React and instead just roll your own UI with HTML and JS, and style your CSS to make your MVP look fresh and new.
Anecdotal: cyph.com started off as an SPA, mainly so we could share some components and styling with our actual application — and ever since we migrated to a static WordPress site with a handful of Angular Elements it's been both a lot easier to maintain and way faster for end users.
(Sure, we could've gotten similar performance with server-side rendering, but at least with the current state of SSR tooling that would've been way more distraction from building our product than we could justify.)
I agree with this so much. These days, the first thing developers will do when making a new app is setup babel + webpack + react + redux, then make an API, all for mostly CRUD applications.
Most applications don't require these frontend frameworks, and it just adds needless complexity in most cases. I've suffered due to this, and so I've recently made the move back to server rendered apps.
And Rails with Turbolinks + UJS might not perfect, but it gets you like 80% of the way there for 10% of the effort.
This article feels to me like complaining about making the simple difficult.
Since I work alone I suppose I'm not up to speed on what defines a single page app but the apps I've been building with PouchDB, jQuery, and Bootstrap run in a single page.
"Stateless requests
Traditional web servers are built to be stateless. "
True, but "apps" should be designed to be self-contained (i.e. all the user navigation is done within the app UI, not the browser UI).
"The browser knows how to deal with a traditional architecture
If you go with the SPA route, you’ll always need extra code to emulate trivial browser features."
That's a pretty trivial problem and browsers don't really solve that, nor should they.
"Fewer, more mature tools
Avoid the Javascript fatigue by not relying so much on Javascript!"
The apps I'm building are almost entirely Javascript. I see that as a good thing. What little I do on the server side I do with Perl, which is something I've been doing since the `90s, so I can feel "traditional" doing that if it helps me sleep at night.
"SEO for free
Single-page apps have to add extra infrastructure and code to make sure they can be indexed by crawlers."
This is not so difficult to address and in some cases it's not even a consideration. In the case of a "blog" app you can simply assign a url to a post and deliver a page built on the fly specifically for it. Google can parse that.
> i.e. all the user navigation is done within the app UI, not the browser UI
Not sure if that's what you mean here, but when this breaks the “back”, “next”, “refresh”, “bookmark” or “share URL” features of my web browser (among others), I hate whoever has been responsible of the design as much as I've hated Flash in the past.
I get it, and I think the distinction is relevant, indeed. Unfortunately, way too many developers think it's a good idea to build a web app instead of a web site, when it's not. Same issue as with Flash before, in fact.
Yeah, I start with an SPA and adapt to the use-case. It either needs to be a SPA, or SPA -> SSR is easy (via Gatsby/Next.js). The other direction though, seeing projects grow from SSR -> interactivity/SPA is usually a horrifying display of highly-coupled code spaghettification.
> Yeah, I start with an SPA and adapt to the use-case. It either needs to be a SPA
Aha, by mistake you corrected your grammar! HNers cargo cult everything, including grammatical mistakes like "an SPA" ( see literally everywhere in this thread). Just say it out loud, "I start with an SPA", does that roll off the tongue? No, neither does, "I'm going to buy an sailboat". However, "It either needs to be a SPA, ..." is totally natural.
While this comment may not seem on topic/useful, it's a useful meta comment -- please don't take offense.
I’m an advocate for SPA’s when they make sense. They have a clear niche. When you need to build an “application”. Like photoshop. Not a simple website that serves information.
Most websites are best served by serverside rendering. Or some form of hybrid where you only send the templates as JS that will be in need.
With SPA’s what usually ends up happening is that the whole app is sent in the first load. All the views, their css and shebang. <1% is actually used by the browser. This is where most hate comes from. Most people give a shit about “time to first meaningful paint”. It’s what makes up for that “wow that was fast experience”
You can optimize both SPAs and server rendered pages for ttfcp. The former requires a lot more discipline.
Browsers also do a lot to render as quickly as possible without the whole page being downloaded. With html it’s simple and they have a lot of streaming tricks.
JavaScript is not that simple. It blocks the eventloop and the payload is downloaded in full, executed and then a paint can happen.
There are trade offs. SPAs can offer high interactive experience when server side rendering cannot.
SPAs are great. Just don’t throw everything away. We need the baby.
> As an application developer, you don’t need to write a single line of JavaScript to create these kinds of experiences. You can write and test all your code in a single language: Elixir.
Agree that SPAs are usually unnecessary. The big problems with JS SPA's is due to the limitations of javascript and the browser runtime. The one major innovation has been component-based view models while server-side frameworks have been stuck with older template-based approaches.
Component-based views are starting to get to server-side frameworks so that should reach parity within 2 years and WebAssembly will change the rest. Now apps can be built using many different languages with OOP/functional styles, strong typing, dependency injection, etc, and run at native speeds in the browser. With the next gen of WASM running threads, GC, and DOM abilities, JS frameworks will likely start a slow death as the existing web frameworks start to have both server and client side delivery models.
At https://qbix.com/platform we wanted to stick closely to the Web standards so we built a hybrid - although new pages would be loaded with AJAX, out of the box we made the “easy development path” cause every to page load from the server. This was because back when we started, search engines and other crawlers didn’t execute Javascript very well.
We always kinda felt bad that we didn’t “fully” embrase the “new and best” SPA trend, but also felt good we were giving people choice and were more compatible with Web Standards. And now as time goes by I see more and more of our choices vindicated. Is this anti-SPA backlash just another fad? Or were we right to give people two ways to render the same page - one on dynamic navigation and one on refresh?
I have a list of widgets and a button to create a new widget. I don’t want a full page reload when I create a new widget.
What are some elegant strategies for handling this with SSR?
I’ve used turbo links and found it rather clunky. Haven’t seen a solution that lets me elegantly reuse server side components in JavaScript without going SPA.
Why does creating a new client side widget require a server call at all? Couldn't you have the widget in a JavaScript template and just clone it on the dom client side?
Cloning from a template would be the what, but I was wondering if there are tools designed for this. It's the kind of thing that could spike complexity and I would want an established pattern of delivering html solely for the purpose of javascript manipulation. It's not a hard problem, but a messy one.
I kinda dislike this article. Not because it isn't true, but because of the effect it might have on some readers.
Yes, building a SPA is not always the best solution, but sometimes I get the feeling that a lot of developers hide behind 'I know how to build good SSR pages and all SPA I have used suck so I will not learn that sh*t'. If you know how to build a PWA with SEO support, offline+sync capabilities and push-notifications, you will know when to choose what (because of the pain you experienced learning it).
If your boss chooses your tech (from the latest buzzwords) and he doesn't understand the implications, I am truly sorry for you, but don't blame the tech on it (ask your boss for a seminar on 'How to Communicate with Managers' maybe then he will understand that you are trying to tell him something...).
What about separations in teams where designers don't mess with backend programmers code? Updates and parallel works on the frontend and backend projects without issues? What about servers that respond with minimal data and consumers that deal only with displaying the received data? Pushing code, re-compiling and restarting webservers all because a button had to be made green or its shadow changed? What about CI/CD, automated tests, automated migrations, builders and compilers consuming dollars and energy for that button change?
I'm happy with building SPAs where it makes sense (myaccount/admin). The problem is Javascript and its ecosystem but you could very well go with Ember which is stable as...and be relevant for years.
We pretender enough so if you turn off JavaScript you get old school and if you turn on you get SPA. All the basic widgets are server/client agnostic, and we have a combinator to special-case the server vs client code when needed. The types enforce client-specific functionality isn't used otherwise.
We also have a "DOM puppet" backend which allows everything to be compiled to native code puppeteering browser APIs from a fair. Prerendering, that, and direct JS output all all supported through related typed abstractions. Soon we will compile the puppeteer to WASM too, so we won't even need the direct JS output anymore.
So much of this is because of the mobile "app" craze where -- due to the limitations of mobile app architecture, you had to build a stateful "app" instead of several independent screens with some limited shared state (usually just a token).
Native mobile UIs are great, but something as simple as cookies / local storage could allow for stateless (or at least less stateful) mobile apps with native UIs.
Now, the abomination of hybrid (cordova), or pre-processed (react native/xamarin) mobile apps is whole other thing, but often why web apps are translated to SPAs.
If we need a mobile app as well, why not use a common code base for web and mobile...
I think a more practical approach is to focus on a generic enough UI toolkit meaning detached from any specific tech stack that will give a feeling of continuity to customers as they move from static pages and SPAs and different flavors of ideas that IT tried along the way. One SPA to rule them all is ridiculous as it doesn't work that way with scale as you have independent teams working on various projects that will be hindered by a single approach in that everyone will have to understand x approach and also have stupid meetings about it.
There are some features which will clearly call for a SPA over SSR, if you need
* to continuously play media (video/audio) while the user interacts with the web app (think modern youtube, soundcloud, spotify web, video news sites)
* provide offline usage/features
* highly interactive app with extensive use of drag'n'drop, animations, touch events etc.
* data sync between browsers/tabs (think moving a ticket in a trello board should update the stacks in other open trello tabs or even for other users that currently view the board)
A well written rails app with good caching and some async stuff sprinkled in where necessary generally feels just as responsive as an SPA for a fraction of the dev cost.
Counterpoint: how many times have you browsed an infinite list of progressively revealed items only to accidentally refresh it and start scrolling again from the top. And of course the items are randomized by our latest AI-based clickdriver algorithm so you won’t be able to find the item you were looking at no matter how long you scroll ;)
I can't see why the Show More content couldn't be rendered server-side, fetched with AJAX and plugged into the DOM with two lines of JS. SSR, no redirect nor refresh, progressive reveal af.
Not only you probably don't need a single page app but you also probably don't need a client side lib to build and render your views... Server side view caching and 304 can go a long way and saves round trips, even at scale and is much more friendly to high latency/low end cpu user agents.
Most of the projects I've been on there is a web app & native apps. So the appeal of a single page app is you will write the exact API/auth for all the clients. Would it be tempting to not use the same auth flow/api etc if you don't use a single page app? Not sure.
Wait - what other type of application is there? I transitioned to SPAs 18 years ago and would never look back. That is for "applications". For web sites I would never use SPA. I stick with server-side rendered HTML.
For me, the biggest problem with SPA is, needing node.js when you want SSR. There should be better ways than adding another backend layer if your stack is different and you don't want callback based multi-threading.
> Gulp, CoffeeScript, BackboneJS, and SASS, all of which have been superseded by newer tools. Avoid the Javascript fatigue by not relying so much on Javascript!
That was his point. The rails stuff he learned five years ago is all still considered good practice, but the JavaScript stuff he learned (listed above) is now considered antique.
I think the general point holds up, but why is sass in that list? I know some newer alternatives are used with React nowadays, but sass is still very much a best practice in general as far as I'm aware.
(If he means SASS vs SCSS syntax, I recall using SCSS ~8 years ago, so it's an odd choice to include either way.)
Once you've used grunt, using gulp is not a big logical jump. Then to webpack. Whatever, they're just build scripts! Roll your own shell scripts if you want! A day to learn them, or a lifetime of being a hater.
Valid points.
- another aspect to consider seriously when designing SPAs is authentication. I have built ReactJs applications and everytime we need a different module that had only the login functionality.
Somehow this always appeared disconnected whereas In traditional apps you have a middleware that watches before rendering, be it client side or server side rendered.
Coming from similar background as author (various legacy web apps with all the challenges of learning now useless js frameworks) - I’m now have a different opinion:
SPA approach should be the default unless you have specific requirements to add html SSR (and even then google is pretty good at indexing public spa content too).
I'll try adding to the conversation by at least justifying why I like SPAs: clearly decoupled front-end/back-end logic, likewise parallel updates/deployment from different teams, back-end mocking, minimal data updates for DOM changes, easy integration with microservices, powerful front-end tools to deal with client feature creep (e.g. interactive widgets), reusable UI components, easy migration to multiplatform desktop apps (e.g. Electron), possible single language for everything (JS, rather than a mishmash of JS/HTML/CSS/Python/PHP/etc), easy integration with hybrid or SSR stacks ( Next.js, Gatsby, etc).
But all this is just rationalization for one simple fact: I'm vastly more productive building SPAs. I know the tools, and I can quickly deliver anything from simple sites to richly interactive experiences very quickly. I can go from SPA -> SSR (via, say, Gatsby) easily. But going the other direction from SSR to something interactive has been far more painful for me. That's why I default to SPAs and adjust from there.
The OP glossed over managing styles and i18n between embedded JS apps and the host app. I'm not sure if there is a way to create strictly isolated CSS in pure server rendered applications without managing naming your own selectors manually. If you build tiny JS apps into your server rendered apps, you'll have to keep the styling for the JS app either in the main app, or bundle it into the embededded JS. If you bundle it into the embedded JS, you'll end up with two styling pipelines, which could make it more difficult to share variables and constants between the two, if you put the CSS rules for the embedded app in the host app, then you have to change the host app CSS for changes in the child app, which means the two might need to be in the same repo. This gets especially more difficult with advances in UI and interaction design which lean more heavily on state based animation. In those cases, we HAVE to have CSS related to animatable elements that are based on application state within the embedded JS application, then you'll really have an issue with having two pipelines. There are similar issues for i18n, asset bundling, accessibility auditing, and testing.
Given all the complexity of managing multiple pipelines for simple and complex pages, it seems to make sense to avoid that complexity by adopting a single pipeline that ensures browser compatibility, testing, i18n, accessibility and performance optimizations are consistently applied and centrally maintained.
Which might imply , if _any_ of your app requires complex presentation/interaction, it might be better to just build the entire app using the same framework.
Unfortunately, even if your app doesn't currently have complex functionality or interactions, doesn't mean you can guarantee it won't ever. Investors are known for pushing products to innovate, pivot, and adapt. Which implies that avoiding SPAs is a privilege for app developers and teams who have absolute control over their product and won't ever be forced to build more complex products.
The Op also doesn't address how having frontend dedicated ecosystems might affect hiring, or influence performance. I remember the days of having 20 instance variables set within a rails action and each of them being deeply coupled into the Erb template. Having a clear client server separation at least forces one to use an API, which can make caching easier by separating the caching of presentational and data elements. Also, the semantics of each server side templating language are quite different. E.g , slim vs liquid vs haml vs ejs. Using server side templates requires frontend developers to be much more versed in both templating languages and understanding the tiny bits of embedded server side code. I don't imagine too many front end folks jumping to learn scala, clojure or Haskell. However, if the client and server are separate than that means a scala shop can focus on the API and hire a frontend dev with no experience in the server side stack.
Normally you'll always need to add something interactive, therefore js. To do that with server side rendering you'll couple the client side to the server side.
For example the server has to send a tag with a class name that the client also is aware of that.
Therefore you have 1 component, where half is on server side and half of on client side, which in my opinion is not maintainable.
...? "Most of the world is fine with whale oil lamps, who needs electricity"
Try a really good interactive article from the New York Times. You'll have a much more impactful experience than if you read a blurb about the same thing on your RSS reader.
That's why I think these conversations are so meaningless. My job would be a nightmare if I didn't use SPAs. It's all about the right tool for the job.
You can get surprisingly far without Javascript, imo. Interactivity means a lot of different things, do you won't always need to have coordinating front and back ends
I think old.reddit.com's interface is more user-friendly than HN's. Why should I leave the page to write a comment? Avoiding JS just for the sake of avoiding is just blind fanaticism under the pretense of being faster and more lightweight.
(The new reddit redesign is a resource hogging abomination riddled with needless SPA bullshit, but the old reddit design was pretty clean and minimal and yet an SPA.)
I think the definition is a bit murky there. I can do a _lot_ of things on a Reddit page without a refresh: add comments, delete comments, edit, sticky, report as spam, save, hide the post, view the contents of the post (if it's an image), crosspost to other subs, etc. I understand that a true SPA would never require a refresh for anything, but this comes pretty close.
Not by default. The big frameworks are first and foremost client side frameworks, which means in an extreme case the server is just sending down <html><script src=.../></html> (basically), and the client framework handles all of the rendering/data fetching.
BUT — with a bit of work, you can set things up to do server side rendering. It requires you use Node at some point in your server stack, and you essentially call the library (on the server) and run their RenderToString function (each has a slightly different implementation).
There are frameworks for this (next.js, nuxt.js) or you can roll your own - it’s not terribly complicated.
You simply do not make SPA on crawlable URLs, so that's not a problem. You use SPA when the page is behind authentication and is customized for the user.
In theory google can crawl SPAs, but in practice it doesn't work all that well. Server side rendering is one solution, a pre-rendering proxy is another.
Google does, but not reliably, especially for newer (ES6) JavaScript features. Bing and DuckDuckGo do not render complex JavaScript apps. Neither does Yandex, I believe.
This feels like clickbait, but just as an aside there's nothing that says you can't do server side rendering and react. Next.js is what I'm using on my current project and it's server side out of the box. So you have text rendered in source like you would with a traditional server side app with the benefits of SPA. So at least one of his nitpicks sounds like he didn't do his homework.
I mean, not really? When you want a new page you create a react component in the "/pages" directory. "/pages/hello/index.js" routes to "mysite.com/hello", and "/pages/hello/there/world/index.js" routes to "mysite.com/hello/there/world". The pages are served from a node.js site. The newest version (8) comes with lambda rendering but you don't have to use it if you don't want.
Yes you actually do. At the very least you should build your web app with technology that makes it fairly trivial to move over to an SPA.
MVC is a mistake. Read that again. MVC is a mistake. It's not a good paradigm to write web applications in.
SPA's are not complicated. They do not take longer to build. They defacto are often way more responsive than any server side monolith that gets built. Because developers who buy into an archaic and broken "MVC" systems typically do so because its "easier" for them, but it's easier because they're not willing to think about whats being written in the first place, and that's a recipe for a bad app no matter how you write it.
Inevitably you will end up hacking your "simple" MVC app to meet perfectly reasonable, ubiquitous client requirements regarding user experience. Because the paradigm isn't fit for base level requirements.
A few years ago my entire job was completely based around consulting for these types web applications. Inevitably you get these developers that think they're wise by going "we're just going to do it with MVC" -- and after a few months of use it becomes completely obvious that the dev team can't meet any kind of modern requirements for the web application. The existing web app is slow (but it's "fast" to the developers), buggy, and the worst part for the business is it takes forever to write features for. Eventually these companies get so frustrated they look to the outside.
To recap, when you build a "traditional" MVC app this typically means a few different things:
1) It's written in a toolchain that's fairly niche to "back end" developers; severely limiting the pool of talent that company can hire to maintain the web application moving forward. In a fair number of cases the company will have a front end team and a back end team. And sometimes all that back end team does is update views so the JS developer can do their thing. So expensive for something so small.
2) You will end up writing a mass of JS anyways, but the JS will mostly revolve around dealing with the fact that the server side templating language controls the original output of the web application. At worst, this means that a lot of devs like to sprinkle bits of HTML inside the JS. So now your templating is strewn across multiple languages and locations. The JS is typically bad because these are "real" developers who don't like JS.
3) Because of 2, there will also be a mess of server side code purely written to massage data into the server side templating language and an analogous set of code just for the JS side of things.
4) Because of 2 and 3, the app because buggy and oddly slow (though again, the devs that wrote it will only look at the original output timing and not the actual life time performance of the application).
5) Because of all of the above, the company has now spent an enormous amount of resources for a fairly shitty app that no one likes to use nor maintain.
My primary focus for these companies was to build a baseline SPA. And then over the next couple of months guide them through creating new features.
And this wasn't a one off thing. I had an entire job based around fixing the sins of the company's internal developers who are costing the company money while not delivering, costing the company money making the application way more complicated than it needed to be, and costing the company money by forcing the company to hire a specific subset of developers familiar with their MVC toolchain.
Stop circle jerking about MVC apps. They were ugly in the first place and continuing to claim that's how we should build web apps is an erroneous position purely fueled by stubbornness on the part of developers.
Here's my benchmark for an SPA: You can either build your entire site using static generation, or you need to structure your web app as an SPA (or prepare to do so in the original implementation). That is the threshold in the current landscape. If you can't get away with doing a statically generated site then you're not going to have fun writing your site with backend MVC framework. At the very least the company's finances definitely won't.
I really wish I could upvote this twice. Tacking on features to a traditional MVC app causes orders of magnitude more technical debt and buggy, tightly-coupled, unmaintainable or extensible spaghetti code. React et al. didn't pass through a membrane from another reality for the sole purpose of annoying devs with more stuff to learn -- they're elegant, powerful solutions to the rapid growing pains and requirements of our modern web. The SPA pattern of completely separating front-end & back-end concerns is seemingly taking over the world for very good reason.
Yep. Developers take their choice and then externalize all the costs to the company; even though the company has put an immense amount of trust and financial power in them.
It's actually absurdly disgusting once you run the numbers. I've directly compared projects before and after over a 1-2 year period and the devs claiming that these "MVC" apps are better for users, the company, or anyone else besides themselves are actually arrogantly delusional. They write these apps, and either leave or then sit there in the company and blame everyone else but themselves.
But hey, at least the problem exists. It allowed me to make a ridiculous amount of money and invest it wisely. shrug
My company (4,500+ people) ordered all products in their portfolio (~12 web apps) to migrate to SPA front ends about a year ago as a way to stand out from our competitors, and boy has it been painful.
Prior to that initiative, we had been using the hybrid approach mentioned in this piece, embedding SPAs only where necessary and sticking to SSR everywhere else, which worked really well.
Since the announcement, our productivity has diminished dramatically since so much of our time is now focused on re-working functionality that already exists into an SPA, and it's completely unnecessary. Not only that, but extending these UIs will take more time in the future than their SSR versions due to the added complexity of the front end frameworks, and we're definitely going to make mistakes along the way that we weren't making before.
It drives me crazy to think that some exec came up with SPA-ing everything as a sales pitch to clients, when 99.9% of our clients have no idea what an SPA is. And the amount of money being spent on turning already-working apps into SPAs is astronomical.