1. 76
  1. 23

    I think sometimes the motivation for doing something as a SPA, whether it really has to be or not, goes like this:

    1. Having an API for our service is a business requirement.
    2. If we ever do a non-Web app (native mobile, desktop, voice assistant skill, etc.), it’ll have to use the API.
    3. To ensure the API doesn’t end up being second-class, our web front-end should use the API as well.
    4. I don’t want to go full micro-services already.
    5. Having a server-rendered web app access the API over http://localhost just seems dumb.
    6. So… SPA.

    Has anyone else gone through this thought process?

    1. 3

      Yeup. At $work we have a bunch of projects on which we’re contracted to deliver a mobile app and a web app using the same backend. This makes NodeJS (server) + React DOM (web) + React Native (app) really attractive. We take advantage of a lot of skill-sharing between React and React Native, and a little bit of skill-sharing between the NodeJS bits and the rest.

      1. 3

        I think I did #5 recently…

        1. 3

          Yeah, I’m not really sure what’s wrong with #5. I vehemently object to the use of javascript, so if I were given freedom to design a web interface to an API, that’s exactly what it would look like.

        2. 2

          Our website at work was built not as a SPA and now our customers require an API. If we just built it off to the side it would end up not keeping up with all the features that the website has. So many APIs today are second class. Now we have to put in a huge effort to convert the existing website in to a spa.

          1. 1

            Can you use the API on the server side, as an abstraction layer under your existing MVC app?

          2. 1

            We do software in a similar fashion where I work, but instead of doing SPA’s our server-side MVC endpoints call into Web APIs. Not sure if that’s better or worse than what you describe.

          3. 18

            The primary reason I’ve liked making SPAs for years now is that they let me combine my favorite features in a really unique way:

            • cross-platform easy access;
            • quick deployments of new features;
            • real-time collaboration; and
            • offline-first.

            This is something like a holy grail as far as I’m concerned… and it’s still far from easy to attain. Here’s what I like to do:

            • Set up resource loading for offline functionality while enabling deployments of new versions.
              • Make sure my index.html links only to file names containing hashes, and that the index.html itself doesn’t get cached by the default browser cache or CDN.
              • Make the index.js install a Service Worker that’s correctly coded to cache all the resources so that it loads instantly even offline; show a transient message when done, like “You’re now ready to use the app offline.”
              • Make the Service Worker also check for a new deployment on load, and present the user with an unobtrusive option to reload with the new version, or automatically load the new version when that’s reasonable.
            • Make editing work offline.
              • First of all avoid the urge to aim for web scale. Aim for community scale, group-of-friends scale, firm scale. This solves a lot of problems.
              • Consider using CouchDB, if it fits the application. Allow the user to choose their own server if they want, so that they can completely avoid relying on me for data storage. Take care to handle merge conflicts.
              • Otherwise do a simple version of event sourcing.
              • Consider writing the frontend code in such a way that the currently rendered state is a known replicated state plus an optimistic sequence of actions, and indicate to the user when she has, e.g., “four actions not yet saved.”
                • Whenever possible, especially when the user comes online, begin trying to replicate the tentative actions; if this fails due to some conflict, let the user know and give her the tools to solve it.
              • Consider (I haven’t gotten to this yet) using CRDTs, commutativity, etc.

            As you can see this can all amount to a sort of lifetime dream project, but actually I have somewhat straightforwardly implemented most of these things for a client in a way that made life easier for their actual customers, without spending enormous amounts of time or effort.

            Trello was a bit of a pioneer in making web apps that work well offline, and I think they showed that it’s a beautiful thing when you can work in a web app without waiting for the network latency on every action. I love apps like that, and I think the web has a really great potential in this direction.

            In short I think the often ridiculed notion of the web browser as an app delivery system is pretty awesome, when used properly, which it is usually not. I even think HTML/CSS as a responsive layout system for hybrid document/applications is a remarkable and unparalleled innovation.

            1. 17

              If you are trying to get a frontend job and don’t know React, Vue, Angular or Meteor or something then prepare to be treated like a second class citizen.

              I have been avoiding this tech vehemently and it has not done me many favours :P

              1. 6

                If you want to get a job doing frontend, why would you vehemently avoid learning the most popular JS frameworks?

                1. 2

                  Frontend development is not about Javascript, at least not exclusively.

                  I don’t think it is necessary at all to use these frameworks for the majority of projects, and if you were to talk about putting together a website or web app that does not a JS framework, what would you call that practise?

                  Design Integration? I think it is much broader than that, so that’s why I call it frontend development.

                  1. 5

                    I think frontend frameworks are both overused and you should know at least one as a web frontend developer. I don’t think you can be in a position to judge what approach makes most sense for a particular project if you are not at least reasonably proficient developing both with and without framework.

                    I also think you should try to be familiar with ideas on which at least most popular frameworks are built to inform your own praxis.

                    Religiously avoiding JS frameworks makes as much sense to me as religiously using them.

              2. 8

                I often follow the same process of ignoring technology until it seems like a long term and viable tool. Though, this has, at times, bitten me. For the most part I try to stay away from anything that looks too cool.

                1. 6

                  Past a certain age/maturity you eventually see the things that make something be successful on /r/programming or Hacker News aren’t always the things you’d want to put in production.

                  Later, you stop caring about new and shiny altogether.

                  1. 1

                    Everything old is new, again.

                2. 6

                  If you’re mostly serving static documents from a server that don’t have a lot of dynamic behaviors, then server-side rendering is perfectly fine. The SPA architecture becomes useful when you’re building an app instead of a website. Think of something like Outlook as an example. With SPA approach you have a thick client that manages all of the UI state, and the server becomes a simple service API that the client talks to.

                  There are a number of benefits to this approach for larger apps. First, you have clear separation between client and server code by design. This makes it easier to compartmentalize work, and allows for things like alternative client implementations. For example, maybe you started with a web apps, and now you want to make a mobile client.

                  Another benefit is that you’re amortizing UI rendering work across your clients instead of it being done by the server. This can also significantly reduce your data transfer needs as the client only requests the data that it needs when it needs it. The responsiveness of the UI can be improved as well since you can be very granular about what you repaint.

                  Finally, SPAs make it much easier to scale horizontally by keeping your server stateless. Since all the UI state lives on the client, there doesn’t need to be much state on the server.

                  Understanding the tools and their trade offs is important for making architectural decisions. So, think about the problem you’re solving and pick the approach that makes sense for your scenario.

                  1. 3

                    I’m going to respectfully disagree with some points.

                    I do agree that for certain types of full-blown web apps, there’s no alternative to an SPA (or similar). But I think the app/page distinction is overplayed sometimes, and developers frequently like to call what they’re doing an “app” in order to justify their design decisions. Social media “apps”, for example, tend to be more page-like in what they’re actually doing. CRUD apps and reports, too, tend to be more page-like.

                    For “amortizing UI rendering work across your clients”, this translates to me as, at times, “imposing unnecessary costs on your clients”. That is, putting rendering work onto low-powered client devices that may be ill-suited to handle it, especially in the form they’re being given it (rendering to a DOM from JSON).

                    “Reducing data transfer needs” turns out not to really pan out in practice. I’m not sure why, and maybe someone with more knowledge of modern browser internals can explain it to me, but browser cache lifetimes seem to be terrible today, and I rarely return to an SPA to find the core JS bundle can still be loaded from cache. In practice, you pay the first-time cost the author talks about on every new session.

                    Finally, on statelessness, you may be right when you are talking about certain levels of scaling or certain types of application design. But my experience with server-side web apps is that they can generally be written in a stateless style by focusing on resources that are meaningful to the user and that you expose with their own URLs.

                    1. 1

                      While apps like Twitter can be page-like, you still get value from having a hard boundary between client and server code. In case of an site like Twitter it’s especially important to keep your server statelss as you need to scale horizontally.

                      The thing is that in a lot of cases the clients have to do less rendering with SPA approach. If you have a low powered client, the last thing you want is to have to keep repainting HTML sent to you by the server because parsing HTML is notoriously expensive. With SPA, you manipulate the DOM via Js, and and the JSON payloads only contain the data you actually need. Furthermore, the initial page assets can be cached once by the client, and don’t need to be sent over again even when the user comes back to the page later.

                      I’m really not sure what you’re referring to specifically, but my team definitely gets the benefits of reduced transfer speeds with SPAs. There is absolutely no reason why the client should be paying first-time costs on every session if your application is configured properly.

                      You’re of course correct that you can setup server-side web apps to be stateless. However, my experience is that it’s much harder to do, and it takes a lot of discipline in practice.

                    2. 3

                      This is a great way to put it.

                      If you are building a large app and have server-side rendering… well now your server has to manage UI state. Sometimes this is useful (you can actually see some UI state on the server-side), but other times this means a lot of “ask client to pass me param X so that on the enxt page I can give them back param X”-style information passing that can lead to mistakes like “oops we accidentally sent all your emails instead of just the ones you were filtering by 3 clicks ago”

                      1. 2

                        …. and most of the commercial programming gigs aren’t in the world of making web sites for consumers, they’re in making web apps, for consumers and for internal use.

                      2. 5

                        This guy is really good. Cudos. It’s really difficult to find good web developer posts.

                        1. 3

                          I’m looking forward to trying out Unpoly. It turns navigation to XHR with some very cool features on top.

                          What caught my eye were the passive updates (link changes the main viewport, but menu gets updated every time) and the two-level modal dialogs (you render full confirmation page, but only the interesting part of it gets shown in a small dialog).

                          1. 1

                            Yeah, I built an app with intercooler.js, which is similar, and it’s really nice to be able to add dynamic client-side behavior on top of a server-side application with only very minimal changes and writing practically no JavaScript. My next project will probably use Unpoly, because I want to give them a good comparison.

                            1. 1

                              You may be interested in the upcoming Phoenix LiveView: https://dockyard.com/blog/2018/12/12/phoenix-liveview-interactive-real-time-apps-no-need-to-write-javascript

                              It’s kind of a ‘React on the server’: it uses a websocket to drive interactivity on the web page, with minimal data transfer, automatic error recovery, state management, and lots of other perks.

                              1. 1

                                I have had some bad experience with Racket’s stateful continuations (with server side memory allocation). It’s very cheap to mount DoS attacks against it.

                                This is probably going to be very similarly weak against them.

                                1. 1

                                  I don’t know how Racket’s stateful continuations interact with concurrency, but on the Erlang/Elixir platform, concurrent processes are very lightweight ‘green threads’ that use minimal memory. By the way, here’s an excerpt from my above link:

                                  A live view starts its life as a stateless render from the controller, which sends HTML to the client as a regular HTTP request. Even with JavaScript disabled, end-users and crawlers alike will receive HTML as expected. After the HTTP request, the live view connects to the server and is upgraded to a stateful process.

                                  So a client visiting a page doesn’t immediately take up memory on your server. Only once the client loads the response HTML and JavaScript, runs the JS and establishes a WebSocket connection back to the server, is there a stateful process spun up. I think this gives you plenty of opportunity to mitigate DoS attacks. For example, you could require users to sign in (through normal static views) before they can access the ‘live’ app.

                            2. 2

                              These two quotes sum it up, both the article, and my own - I think - similar approach to technology in general:

                              My strategy for dealing with the absurd pace of change in web development has been as follows: ignore 99% of it and see if it goes away.

                              Surely the billions of programming hours that have gone into all these new things aren’t in vain.

                              Except for me, the second one is said with a healthy dose of sarcasm.

                              1. 1

                                I mostly agree with this in that none of the side projects I’ve done that have an actual purpose other than learning a new technology seem to make sense to build as SPAs.

                                But I disagree a bit in that I think that if you’re building a SPA at all, it usually makes sense to use the most popular setup even if it isn’t perfect for your situation. It makes it easier to find help and supporting libs, easier if you need to bring on a contractor to help or sell it or something.

                                1. 1

                                  Everything that wants to be a SPA unless it would be better written as a desktop app could just as easily if not more so be done without the SPA. Yep, most projects don’t want to be SPAs either.

                                  1. 1

                                    This post is exactly how I feel. DRF for the backend, and minimal html/css for the frontend is so much easier for my mind and grey hairs.

                                    Until this month…

                                    So every few months in the past year I had attempted to learn Elm, and this time on the third try and it finally stuck for me. Give it a try, the syntax is strange if you are not accustomed to Haskell or Erlang but it has wonderful error messages, great plugin support, and once it compiles it Just Works™. Turns out React copied a lot from Elm which was something that intrigued me.

                                    1. 2

                                      More specifically, Redux was inspired by the Elm architecture. I’m not sure that React borrows much.

                                      Relevant to the main issue raised in the article, the latest version of Elm mitigates the concern about payload size thanks to dead code elimination and record field renaming.

                                      1. 1

                                        Ah you are right, Redux not React.

                                      2. 1

                                        What’s DRF?

                                        1. 1

                                          Django Rest Framework