From 9c44ff4b14d83187caa49f8338c64a14e119d086 Mon Sep 17 00:00:00 2001 From: Marco Otte-Witte Date: Sun, 17 Mar 2019 18:40:43 -0700 Subject: [PATCH] initial --- blog/_posts/2019-03-16-spas-pwas-and-ssr.md | 86 ++++++++++++++++++ .../2019-03-16-spas-pwas-and-ssr/breethe.gif | Bin 0 -> 406237 bytes .../2019-03-16-spas-pwas-and-ssr/loading.gif | Bin 0 -> 109636 bytes .../2019-03-16-spas-pwas-and-ssr/maps.gif | Bin 0 -> 658671 bytes .../2019-03-16-spas-pwas-and-ssr/spacejam.gif | Bin 0 -> 46686 bytes 5 files changed, 86 insertions(+) create mode 100755 blog/_posts/2019-03-16-spas-pwas-and-ssr.md create mode 100755 images/posts/2019-03-16-spas-pwas-and-ssr/breethe.gif create mode 100644 images/posts/2019-03-16-spas-pwas-and-ssr/loading.gif create mode 100644 images/posts/2019-03-16-spas-pwas-and-ssr/maps.gif create mode 100644 images/posts/2019-03-16-spas-pwas-and-ssr/spacejam.gif diff --git a/blog/_posts/2019-03-16-spas-pwas-and-ssr.md b/blog/_posts/2019-03-16-spas-pwas-and-ssr.md new file mode 100755 index 0000000000..b988d13ec0 --- /dev/null +++ b/blog/_posts/2019-03-16-spas-pwas-and-ssr.md @@ -0,0 +1,86 @@ +--- +layout: article +section: Blog +title: "SPAs, PWAs and SSR" +author: "Marco Otte-Witte" +github-handle: marcoow +twitter-handle: marcoow +topic: javascript +--- + +Single Page Apps, Progressive Web Apps and classic Server side rendered websites are often seen as orthogonal approaches to building web apps where only one is best suited for a particular project and a decision has to be made which approach to leverage early on in a project. In this post we'll explore why that doesn't have to be the case but all 3 approaches can actually be combined in order to achieve the best result. + + + +## Desktop-grade apps + +Modern websites are in many cases not really websites anymore but in fact full blown apps with desktop-grade feature sets and user experiences. While the much-loved [Spacejam Website](https://www.spacejam.com/archive/spacejam/movie/jam.htm) with its little blinking satellites for menu items was a pretty standard website only about 2 decades ago + +![Video of the spacejam.com menu](/images/posts/2019-03-16-spas-pwas-and-ssr/spacejam.gif) + +we can now go to [Google Maps](https://www.google.com/maps), zoom and rotate the earth in 3D space, measure distances between arbitrary points and have a look at our neighbor's backyard: + +![Video of Google Maps](/images/posts/2019-03-16-spas-pwas-and-ssr/maps.gif) + +All of this functionality, interactivity and visual appeal comes at a cost though, mainly in the the form of JavaScript code. The median size of JavaScript used on pages across the Internet is now [ca. 400KB on the desktop and ca. 360KB on mobile devices](https://httparchive.org/reports/state-of-javascript), an increase of ca. 36% and ca. 50% over the course of the past 3 years. All of this JavaScript not only has to be loaded via often spotty connections but also parsed, compiled and executed - often on devices that are less powerful than one might expect (have a look at [Addy Osmani's in-depth post on the matter](https://medium.com/@addyosmani/the-cost-of-javascript-in-2018-7d8950fbb5d4)). + +What all this leads to is that for many of these highly-interactive, feature-rich and shiny apps that are being built today, the first impression that the user gets will often be this: + +![Video of a loading JS app](/images/posts/2019-03-16-spas-pwas-and-ssr/loading.gif) + +## SPAs + +While JavaScript-heavy apps can be slow to start initially though, the benefit of the Single Page App approach that is most often followed to build them is that once the the app has started up in the browser, it is running continuously and handles route changes in the browser so that no subsequent page loads are necessary. In that sense the SPA approach trades a slow initial load for fast or often immediated subsequent loads. + +The initial response though that the server sends will often be either empty or just a basic loading state as shown above. Only after the application's JavaScript has been loaded, parsed, compiled and executed, can the application start up. This results in relatively slow time to first meaningful paint and time to interactive metrics. + +### Time to first meaningful paint + +This is the time when the browser can first paint any **meaningful** content on the screen. While the time to first paint metric would just measure the first time **anything** is painted (which would be when the loading spinner is painted in the above example), for an SPA time to first meaningful paint would only occur once the app has started and the actual UI is painted on the screen. + +### Time to interactive + +This is the time when the app is first usable and able to react to user inputs. In the above example of the SPA, time to interactive and time to first meaningful paint happen at the same time which is when the app has fully started up, has painted the UI on screen and is waiting for user input. + +## The App Shell Model + +One popular approach for improving the startup experience of JavaScript-heavy applications, is called the [App Shell Model](https://developers.google.com/web/fundamentals/architecture/app-shell). The idea behind this concept is that instead of responding to the user's first request with an empty HTML document with maybe only a loading spinner and a number of script tags, the server would respond with the minimal set of code that is necessary for rendering and making interactive the app's minimal UI. In most cases, that would be a visual framework for the app's main blocks and some barebones functionality associated to that (e.g. a working slideout menu without the individual items actually being functional). + +Although this does not improve the app's time to first meaningful paint, at least it gives the user a first visual impression of what the app will look like (and users might even be able to develop an idea for what it will work like) once it has started up. Of course the app shall can be cached in the browser using a service worker so that for subsequent visits it can be served from that instantly. + +## Back to SSR + +The only effective solution for solving the problem of the meaningless initial response - be it an empty HTML document with script tags only, a loading indicator or an app shell - is to leverage server-side rendering and respond with the full UI or something that's close to it. + +Of course it wouldn't be advisable to go back to classic server-side rendered websites completely, dropping all of the benefits that single page apps come with (instance page transitions once the app has started, rich user interfaces that would be almost impossible to build with server side rendering, etc.) A better approach is to run the same single page app that is shipped to the browser on the server side as well as follows: + +* the server responds to `GET` requests to all of the routes the single page app defines and that would be transitioned to instantly once the app has started up in the browser +* once a request comes in, the server constructs an application state from the request path and potentially additional data like a session cookie and injects that into the SPA +* it then executes the SPA, including data loading and performs an initial render of the app's UI into a string, leveraging a library like SimpleDOM +* that string is then served as the response to the browser's request as opposed to an empty document with script tags only or an app shell +* the pre-rendered response of course still contains all `