, ,

Single Page Web Applications

Felix Messner

(Originally written for for 143206a Entwicklung von Rich Media Systemen in 07/2019)

Intro

There are two fundamentally different concepts in web application development: Single-Page and Multi-Page architectures. This article explores the different approaches and explains some of the development concerns of single page architectures, at the example of how to handle the browser history, search engine optimization and security. In a practical analysis, the performance of Gmail’s single- and multi-page versions is compared using the Google Lighthouse audit tool.

Single page web applications (SPWAs) are defined as web applications that do not make the browser reload the page during usage. Instead, they work by dynamically updating the already loaded HTML. Therefore, once an initial page is obtained from the server, only relatively small amounts of data need to be requested.

In single page websites, the content, which would be distributed over multiple pages in traditional multi page websites, is simply stacked on the same page. Navigation can, for example, be achieved by linking to different anchors on the same page.

Figure 1: Comparing Multipage and Singlepage websites (Source: [1])

While Figure 1 displays a single-page application as a page with all the content stacked on top of each other, the focus of this article is on complex web applications like Google Docs, which don’t necessarily include scrolling like on traditional websites.

The concept of interactive websites, that don’t require a full server roundtrip for every user interaction, has been around since the introduction of JavaScript (JS) in 1995 and Macromedia (today Adobe) Flash in 1996 [2]. However, truly asynchronous web apps have only been realized since the introduction of Asynchronous JavaScript and XML (AJAX) in 2005. [3]

With JS and AJAX, any part of the displayed page can be updated, eliminating the need of loading whole new pages. This allows for SPWAs to provide a more continuous user experience that is not interrupted by page reloads and therefore feels much more like a desktop application.

Some web apps, like Google Docs, Telegram, WhatsApp web, or Trello take this approach one step further and create a user interface that is specifically designed to work like a traditional desktop application. For example, Google Docs overrides the browser’s right-click action, providing a custom context menu – a feature that is usually not seen on many web apps or websites.

The advantage over true native desktop applications is that the client side of SPWAs is built to run in a web browser. Therefore, it doesn’t directly depend on the underlying operating system. Such web apps can therefore be considered cross-platform applications [2].

There is still potential for incompatibilities, though: Different browsers may implement certain features in their own unique way. Also, browser settings can be changed by its user, possibly in a way that prevents the app from working as intended. For example, many users disable JS by default for security reasons. However, SPWAs heavily rely on JS in order to work at all.

A middle-ground between developing for a specific OS, and depending on the user’s web browser settings to be compatible, is to wrap a web application in a desktop application. Many well-known tools, like Atom, Discord, VisualStudio Code, Slack, or WhatsApp, are built using web technologies like HTML, JS and CSS. They use Electron, a framework that bundles a Node.js app with its own Chromium renderer [4]. Others, like Discord or Steam, use the Chromium Embedded Framework, which is essentially wrapping their web applications in a custom browser, making them appear as a desktop program [5].
As opposed to pure web browser apps, this requires the distribution of different apps for each target operating system. However, the actual application is still developed with web technologies, so the porting effort is considerably lower than with fully native software.

Single Page vs. Multi Page Architecture

As mentioned earlier, single– and multi-page are fundamentally different architectures for web applications.

Traditional multi page web applications (MPWAs) and websites rely on a server backend to provide multiple predefined HTML pages, or to create them on demand like in php. Each time the user opens a new view, such a page is requested from the server, which then renders it into HTML and sends it, (and all its associated resources like JS, CSS or images) back to the browser, which then again needs time to render the new page for the user. Especially on mobile devices and with bad data reception, this can result in breaks of several seconds every time a new view is accessed.
The “economic value of rapid response” was already researched back in 1982 by Walter J. Doherty and Ahrvind J. Thadani from IBM [6]. According to a Google blogpost from Jake Brutlag in 2009, a delay of 200ms can already have impact on user behavior [7].

The principle of single page architecture is that only one initial page is loaded at the beginning. After that, only data is requested from the server, and dynamically integrated into the already displayed page with JS. Therefore, a single page app cannot work without JS, and usually relies on more or less heavy frameworks [8], which can slow down the initial loading of the application. In turn, once the application is loaded, it can function without the browser ever loading another full page. This allows for non-blocking page updates and view changes, and therefore a much better responsiveness.

For example, when a new page is loaded in a MPWA, the user can’t really do much except wait until the process is complete. If there is a high time-to-first-byte1, there won’t be any visual clues for the user about what is going on, or even if something is happening at all. In the worst case, the bowser will start to display a blank page until the content of the new view starts arriving.

1 meaning that there is a delay between the web server receiving the request and sending the response – for example if it has to wait for a database query or similar

With a SPWA, it is easy to display a loading animation, or even a loading progress bar (as seen in Figure 2), while waiting for the requested data from the server. This way, the user is provided with feedback about the loading progress.

Figure 2: Gmail’s loading screen

Development Concerns

MPWAs have a very tight connection between client- and server side. Frontend views usually are created by the server on demand. The logic for this is written in a server specific language like php or Java Server Pages.

MPWAs have a very tight connection between client- and server side. Frontend views usually are created by the server on demand. The logic for this is written in a server specific language like php or Java Server Pages.
They can be expanded more easily than a SPWA. It is basically just a matter of adding a new page, which has little effect on other pages.

A SPWA’s client side is mainly developed like a pure desktop application. The initial page load must contain everything necessary in order for the application to function. After that, all frontend logic is handled via JS on the client side. Communication with the server only happens to retrieve or send data. Therefore, the site can also be used without an internet connection, as long as no new data needs to be loaded.

The client- and server side are also much more independent from each other, and can therefore be developed more independently, than with MPWAs. The server side basically provides an API for the client to access. Thus, a frontend developer doesn’t need to worry much, if at all, about server logic. This also makes it possible to use the same server backend for multiple applications, for example a web application and a corresponding mobile app.
Some frameworks, like Angular [9] or React [10], even have their own developer tools that can be installed as a Chrome extension.

On the other hand, being developed like a desktop application negates some of the comfort functionality that is provided by browsers. For example, a browser can remember the scrolling position when a site is left and restore it when the user returns or reloads. In an MPWA, the user can easily be prompted to save unsaved work before leaving through the beforeunload event. In a SPWA, there is only one page, so the browser never navigates away from it, and thus doesn’t fire the event [11].
There are also a number of issues regarding accessibility, in particular the usability of screen readers, as pointed out by Craig Abbot in a blogpost from 2018 [12].
All these issues may be taken care of by the big frameworks, but this in turn increases amount and complexity of their code.

Browser History

Since a SPWA never loads new pages, the user always stays on the same page from the browser’s perspective, which means that the browser’s back and forward buttons cannot be used properly. When pressing the back button, the user would simply be brought back to the site that was open before the SPWA. In order to make use of these buttons, developers need to use the HTML5 history API to manipulate the browser’s history [13].

In particular, a new item can be pushed onto the history stack using the `history.pushState()` method. This can also include a change of the displayed URL. Also, a custom state object can be added to the new history item to store information. This object is accessible in the `popstate` event, which is fired whenever the browser moves to a new history state. It’s also possible to manipulate the current history item with `history.replaceState()` if adding a new one isn’t desired.

Search Engine Optimization

Since the basic idea of SPWAs is to only provide an empty HTML page, and serve all the content through AJAX on demand, how can such a page be read and understood by search engine crawlers, such as Google’s Googlebot? Originally, Googlebot was not able to deal with dynamically created content. In 2009, Google provided recommendations to make AJAX applications crawlable, not by using the actual JS code, but based on putting special tokens in URLs [14]. However, this got deprecated in 2015, when it was announced that Googlebot was now able to “render and understand […] web pages like modern browsers“ by directly accessing a site’s JS and CSS files [15]. An article by Anthony Gore, Community Partner of Vue.js, demonstrates that this generally works, but also states that in order to achieve a desirable ranking, developers shouldn’t rely on it blindly, as there may still be cases where Googlebot won’t function correctly [16].

To avoid these issues, Server Side Rendering (SSR) should be used. With this technique, the application is run on the server, and the resulting HTML is then inserted into the page that is sent to the client. This way, there is HTML content that is easy to understand for crawlers, and the JS framework will still work on the client side as it would simply overwrite the existing content.
It is also possible to pre-create this HTML statically before deployment (“prerendering”). This, however, isn’t well suited for pages with changing data.

Security

It is important to understand that code running on the client side can easily be manipulated by the user, and therefore cannot be trusted. This quote from a security.stackexchange answer puts it really well:

Any validation and authorization that happens on the client is UX, not application security. Your endpoints on the server are ultimately and totally responsible for ensuring the security of the data and the application.” [17]

While this is true for any kind of web application, the whole frontend logic of a SPWA runs solely on the client. So, even though the server only provides an API to the client, it has to be additionally secured. This is good practice anyway, but especially important to keep in mind for SPWAs. Also, a potential attacker has access to the whole frontend code.

Performance Comparison of Gmail’s Single- and Multi Page Application with Google Lighthouse

In a SPWA, all required code must be loaded before the application becomes responsive. Since this is usually done with large frameworks, such as Angular, React, Vue, or Ember [8], there is a larger amount of code that needs to be loaded for the application to work, than in a multi-page application.

A good example to measure this is Gmail, because it provides both the Closure-based [18] “Standard view”, as well as a “Basic HTML view”. The latter is a multi-page version intended for browsers that aren’t supported by the Standard view [19], but is also advertised for slow internet connections in the loading screen of the Standard view (see Figure 2). It is important to note that the Standard view loads some features likethe chat function, spell checking, keyboard shortcuts, adding or importing contacts, custom “from” addresses or rich formatting, which are not included in the Basic HTML view [19]. Because of this, the two versions can’t be directly measured against each other as they don’t have the exact same functionality, and by extension, don’t have the same amount of code to load and run. Still, comparing their loading times gives an impression of the difference between a basic MPWA and an application that is based on a JS framework.

Lighthouse Benchmark

The benchmark was performed in Google Chrome 74.0.3729.169 with the Performance audit of Google Lighthouse 4.2.0. The audit was set to test for a Desktop device, with no simulated throttling and with no cache usage.

For the test, a relatively weak system with an Intel Core i5 5200U and 8GB RAM (“weak system”) has been used. There were also many unrelated background tasks active, leading to a generally high CPU background load, to simulate non ideal real world conditions. The influence of the client’s performance is investigated in the section Client Performance by rerunning the benchmark on a stronger system.

The tables below show the mean results and standard deviation of ten consecutive measurements.

StandardMEANSTD. DEVIATION
First Contentful Paint0,480,07second (s)
Speed Index4,351,66s
Time to Interactive14,926,68s
First Meaningful Paint5,162,41s
First CPU Idle13,185,46s
Estimated Input Latency179,00120,29millisecond (ms)
Table 1: Lighthouse Performance Audit of Gmail “Standard View” on weak system
Basic HTML MEANSTD. DEVIATION
First Contentful Paint0,530,14s
Speed Index0,600,15s
Time to Interactive0,600,15s
First Meaningful Paint0,600,15s
First CPU Idle0,600,15s
Estimated Input Latency20,000,00ms
Table 2: Lighthouse Performance Audit of Gmail “Basic HTML View” on weak system

As Table 1 and Table 2 show, the Basic HTML view performs better overall, and gives much more consistent results, than the Standard view.

An exception is First Contentful Paint, which marks the time at which the first DOM element is rendered. This is an important point, as it gives visual feedback that the page is actually loading [20]. Here, the Standard view is slightly faster than Basic HTML. This difference is within the standard deviation, so it is most likely down to measurement error. In theory, it could also be explained by the fact that in the SPWA, only a very basic HTML page is loaded, while in the MPWA, the page is filled with content, therefore larger, which may take longer to load and display. However, in the case of Gmail, the initial page of the SPWA is still about ten times larger than in the MPWA due to script content.

Speed Index is a metric showing how fast a page is visually populated [21]. It makes sense that the Basic HTML view populates much faster than the Standard view, which needs to generate everything via script, whereas in the Basic HTML view, all content to be displayed is included in the initially loaded page.

Time to Interactive is arguably one of the most important measurements regarding perceived performance. It shows the time until the site becomes interactive. Google defines the term “interactive” with three criteria:

  • The page must have displayed “useful” content (which refers to the First Contentful Paint)
  • Event handlers must be registered for most elements
  • The page must respond to user interaction in 50 ms [22]

Here, the SPWA is much slower than the MPWA, which is expected since all content must be rendered into HTML versus the HTML already being present in the MPWA version. Since this rendering is done on the client side, computer performance may also impact the Time to Interactive.

First Meaningful Paint isn’t well defined, as what is meaningful can vary depending on the type of website/web app. In the Lighthouse documentation, it refers to the time of the paint after which “the biggest above-the-fold1 layout change has happened, and web fonts have loaded” [23]. Again, the results are expected, since rendering an existing HTML page should be faster than generating the HTML on the fly first.

1 The part of a page that is directly visible on screen without scrolling

First CPU Idle (in versions prior to Lighthouse 3, this was called First Interactive) represents the time until the page becomes “minimally interactive” [24], which is basically a step before fully interactive (Time to Interactive).

Estimated Input Latency estimates how fast the application will respond to user input based on the main thread’s idle time [25]. Google proposes to measure performance of a web application in four aspects: Response– , Animation– , Idle– and Loading-Times, or RAIL for short [25]. The first of these, Response, suggests that user input should be responded to within 100 ms, otherwise the user may begin to feel a delay between input and reaction.

In Lighthouse, the Estimated Input Latency test aims for a score of only 50ms. That is because web applications are recommended to process work in chunks of 50ms. Once a chunk of work has started, it won’t be interrupted. Therefore, input can be queued for up to 50ms before it’s processed.

Figure 3: How idle tasks affect input response budget (Source: [26])

As illustrated Figure 3, that potentially only leaves 50 ms to handle the input.

Client Performance

In order to show the influence of Client performance, the test has been repeated on a more powerful machine with an AMD FX-6100 processor and 16GB RAM (“strong system”).

StandardMEANSTD. DEVIATION
First Contentful Paint0,320,04s
Speed Index3,120,43s
Time to Interactive8,030,47s
First Meaningful Paint3,110,84s
First CPU Idle8,030,84s
Estimated Input Latency93,0011,55ms
Table 3: Lighthouse Performance Audit of Gmail “Standard View” on strong system
Basic HTML MEANSTD. DEVIATION
First Contentful Paint0,380,07s
Speed Index0,440,05s
Time to Interactive0,430,05s
First Meaningful Paint0,420,04s
First CPU Idle0,430,05s
Estimated Input Latency20,000,00ms
Table 4: Lighthouse Performance Audit of Gmail “Basic HTML View” on strong system

These results show a much better performance for the Standard view, and only a slight improvement in the Basic HTML view. To better illustrate this, the test results on the strong system have been set into relation to the results of the weak system in Table 5.
While there was a strong improvement relative to the weak system, in absolute numbers, the Standard view didn’t perform as well as expected on the strong system (See Table 3). The Input latency estimation was still far over the recommended 50ms. With about eight seconds, the Time to Interactive also was higher than expected.

Strong vs weak systemStandard ViewHTML View
First Contentful Paint150,00139,47%
Speed Index139,42136,36%
Time to Interactive185,80142,86%
First Meaningful Paint165,92139,53%
First CPU Idle164,13139,53%
Estimated Input Latency192,47100,00%
Table 5: Performance of the strong system compared to the weak system in percent

For the HTML view, the performance difference is very stable at around 140%. However it is worth noting that this difference is still only fractions of a second in absolute numbers (compare Table 4 and Table 2).

The Standard View on the other hand, has varying performance gains, from around 139% for Speed Index up to 192% in Estimated Input Latency. This shows that stronger client performance benefits some aspects more than others.

Conclusion

Both single and multi page architectures come with their own advantages and downsides.

While single page architectures heavily rely on JavaScript frameworks, they require only one full page load, which makes them very robust against weak network connections once they are actually loaded. For loading further data, progress feedback can be displayed to the user. However, client performance also has a big effect on responsiveness, as the Lighthouse test of Gmail on the two different systems showed.

There are a few things to consider when choosing to develop a single page application. Updating the browser history as the user navigates through the different states of the application has to be manually taken care of, search engine optimization requires more attention than on multi page apps, and it is especially important to keep server side security in mind.
The decoupled server backend on the other hand, makes this architecture an ideal choice if native apps for other platforms are also planned. In an ideal case, the same backend can be shared between multiple different frontend applications/platforms.

Overall, whether to use a single-page application or not, depends on the use case.

Single page applications make the most sense if there is a relatively small, not expanding, frontend, since they are not as easy to scale. On the other hand, they also allow for large and complex frontend logic (like Gmail or Google’s online office suite), making their potential basically equal to desktop applications. However, achieving both performance and complexity at the same time still seems to be difficult right now, as the Lighthouse test of Gmail showed. Single page apps can also provide limited offline functionality, since they don’t rely on fetching new pages from the server.

If it is likely that a user will frequently switch views, single page applications will probably save more time than multi page applications would spend loading new pages. On the other hand, it is easier to expand a multi page application, than it is to do so with a single page application. They are easier to scale and therefore make more sense in large, growing environments.

References

[1]L. Giavara, “Sito web multipagina, sito web one page, landing page. Quale scegliere?,” 28 09 2018. [Online]. Available: https://www.lucagiavara.it/blog/item/sito-web-multipagina-sito-web-one-page-landing-page-quale-scegliere.html. [Accessed 12 06 2019].
[2]devsaran, “From History of Web Application Development,” 08 07 2016. [Online]. Available: https://www.devsaran.com/blog/history-web-application-development. [Accessed 04 05 2019].
[3]Jesse James Garrett, Adaptive Path , “Ajax: A New Approach to Web Applications,” 18 02 2005. [Online]. Available: https://adaptivepath.org/ideas/ajax-new-approach-web-applications/. [Accessed 04 05 2019].
[4]Electron, [Online]. Available: https://electronjs.org/apps. [Accessed 05 05 2019].
[5]“Chromium Embedded Framework From Wikipedia, the free encyclopedia,” 26 04 2019. [Online]. Available: https://en.wikipedia.org/wiki/Chromium_Embedded_Framework. [Accessed 05 05 2019].
[6]W. J. Doherty and A. J. Thadani, “The Economic Value of Rapid Response Time,” 11 1982. [Online]. Available: https://jlelliotton.blogspot.com/p/the-economic-value-of-rapid-response.html. [Accessed 29 06 2019].
[7]J. Brutlag, “Google AI blog – Speed Matters,” Google, 23 06 2009. [Online]. Available: https://ai.googleblog.com/2009/06/speed-matters.html. [Accessed 10 05 2019].
[8]A. Z., “What’s the Difference Between Single-Page and Multi-Page Apps,” RubyGarage, 21 06 2018. [Online]. Available: https://rubygarage.org/blog/single-page-app-vs-multi-page-app#article_title_0. [Accessed 10 05 2019].
[9]“AngularJS Batarang – Chrome Web Store,” [Online]. Available: https://chrome.google.com/webstore/detail/angularjs-batarang/ighdmehidhipcmcojjgiloacoafjmpfk. [Accessed 14 06 2019].
[10]“React Developer Tools – Chrome Web Store,” [Online]. Available: https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi. [Accessed 14 06 2019].
[11]A. Silver, “The disadvantages of single page applications by Adam Silver, designer based in London, UK,” 11 08 2014. [Online]. Available: https://adamsilver.io/articles/the-disadvantages-of-single-page-applications/. [Accessed 26 06 2019].
[12]C. Abbot, “craigabbott.co.uk – One-page-applications are not accessible,” 14 03 2018. [Online]. Available: http://www.craigabbott.co.uk/one-page-applications-are-not-accessible. [Accessed 28 06 2019].
[13]“MDN web docs – Manipulating the browser history,” Moziia, 19 03 2019. [Online]. Available: https://developer.mozilla.org/en-US/docs/Web/API/History_API. [Accessed 05 05 2019].
[14]Google, “Official Google Webmaster Central Blog: A proposal for making AJAX crawlable,” Google, 07 10 2009. [Online]. Available: https://webmasters.googleblog.com/2009/10/proposal-for-making-ajax-crawlable.html. [Accessed 13 06 2019].
[15]Google, “Official Google Webmaster Central Blog: Deprecating our AJAX crawling scheme,” Google, 14 10 2015. [Online]. Available: https://webmasters.googleblog.com/2015/10/deprecating-our-ajax-crawling-scheme.html. [Accessed 13 06 2019].
[16]A. Gore , “Is My Single-Page Application SEO Friendly? – Vue.js Developers,” 09 04 2018. [Online]. Available: https://vuejsdevelopers.com/2018/04/09/single-page-app-seo/. [Accessed 13 06 2019].
[17]Xander, “appsec – Do SPA applications have different security considerations than HTML5 sites? – Information Security Stack Exchange,” 26 08 2013. [Online]. Available: https://security.stackexchange.com/a/41244. [Accessed 14 06 2019].
[18]Google, “Closure Library,” Google, 24 05 2019. [Online]. Available: https://developers.google.com/closure/library/?csw=1. [Accessed 25 05 2019].
[19]Google, “See Gmail in standard or basic HTML version,” Google, [Online]. Available: https://support.google.com/mail/answer/15049?ctx=gmail. [Accessed 25 05 2019].
[20]Google, “First Contentful Paint | Tools for Web Developers | Google Developers,” Google, 29 05 2019. [Online]. Available: https://developers.google.com/web/tools/lighthouse/audits/first-contentful-paint. [Accessed 02 06 2019].
[21]Google, “Speed Index | Tools for Web Developers | Google Developers,” Google, 29 05 2019. [Online]. Available: https://developers.google.com/web/tools/lighthouse/audits/speed-index. [Accessed 02 06 2019].
[22]Google, “Time to Interactive | Tools for Web Developers | Google Developers,” Google, 29 05 2019. [Online]. Available: https://developers.google.com/web/tools/lighthouse/audits/time-to-interactive. [Accessed 02 06 2019].
[23]Google, “First Meaningful Paint | Tools for Web Developers | Google Developers,” Google, 29 05 2019. [Online]. Available: https://developers.google.com/web/tools/lighthouse/audits/first-meaningful-paint. [Accessed 02 06 2019].
[24]Google, “First CPU Idle | Tools for Web Developers | Google Developers,” Google, 29 05 2019. [Online]. Available: https://developers.google.com/web/tools/lighthouse/audits/first-cpu-idle. [Accessed 02 06 2019].
[25]. M. Kearney, A. Osmani , K. Basques and J. Miller , “Measure Performance with the RAIL Model | Web Fundamentals | Google Developers,” Google, 29 05 2019. [Online]. Available: https://developers.google.com/web/fundamentals/performance/rail. [Accessed 11 06 2019].
[26]Google, “Measure Performance with the RAIL Model | Web Fundamentals | Google Developers,” 29 05 2019. [Online]. Available: https://developers.google.com/web/fundamentals/performance/images/rail-response-details.png. [Accessed 11 06 2019].

by

Felix Messner

Tags:

Comments

Leave a Reply