4 The web, frameworks, and R
Broadly speaking there are two approaches to building web applications:
- Multi page applications
- Single page applications
The above are somewhat self-explanatory but it’s nonetheless good to quickly look into their particularities to ensure we distinguish between them and understand their implications.
Here I just skim over these high-level ideas, they should become clearer as the book progresses.
4.1 Multi page
The multi page approach consists of building applications that span multiple pages. This is also often referred to as the traditional approach as it predates the single page style.
In this paradigm the website will organise content on different pages and provide the user with ways to navigate between pages and find the content they look for.
This concretely often results in <nav> used in, for instance, “navbars”. These are essentially stylised links between the various pages of the website.
Each page is served at its own path. The index.html sits at the first / which is stripped by web browsers; when visiting github.com we actually visit https://github.com/ but the browser displays https://github.com. Other pages have their own path, for instance, we can then visit the about page at /about.
Every time we visit one of these paths in the browser, be it via the provided navigation or by typing the address in the browser, we execute a GET request to the respective server which then returns the appropriate HTML.
I do not know the exact stats but it’s safe to say that the majority of websites out-there follow such an approach.
Coming from R, blogdown follows this approach, although it builds static sites that do not require servers to dynamically render pages.
4.2 Single page
Single page applications differ quite a bit. It does very much what it says on the tin; it consists of a single page.
We’ll likely never get to zero page application, there is no avoiding making an initial GET request to the server to obtain an initial response.
Where such applications differ is that then, everything happens on that one page. The user is never sent to other paths in the application, there is no /about or any other pages.
That is not to say there is no possibility to display content that would otherwise be placed in an about page, but it has to work differently.
Take some examples of single page applications, or mostly single page applications:
- Google maps
Those, if they don’t consist of a single page, certainly see most of their action on the landing page.
However, this content is hardly static, on Google maps you see your position on the map updated in near real-time but it does not do so by repeatedly refreshing the page, that would be obnoxious.
These applications update the already loaded page with the use of the WebSocket, which allows two way communication between the client (web browser) and the server. The messages and data sent from the server to the client ultimately use JavaScript to update the page.
In the R world, you can build such applications with the shiny framework.
Note that this categorisation is relatively unimportant and the distinction between the two will often be blurry as large applications likely both have multiple pages and use WebSockets. For instance, Github adheres primarily to the multi page paradigm but also makes use of the WebSocket: when starring a repository the page does not re-render – this goes through the WebSocket.
4.3 Performances
There used to be great differences in performances between the two approaches but this is no-longer the case.
All applications have dependencies, be it Bootstrap, a visualisation library such as d3.js, or other. It used to be that single page applications had to load all such dependencies upfront but this has since changed.
For instance, shiny renders the required dependencies dynamically; the dependencies required to display a plotly graph are only rendered when such a plot is made visible and not when the app loads.
Technically the websocket is a tiny wee bit faster because HTTP requests require headers but we’re talking about dozens of milliseconds at best.
All in all, use the approach that suits you and the application you build best.
4.4 Frameworks
One thing to keep in mind is that web frameworks, the tools you will use to build your applications, tend to suit one approach over the other.
Ambiorix is unopinionated, you can build either form of applications with it, however, as the author of the package, I do not think you should use ambiorix for single page applications, simply because there is a framework out there that already specialises in it and will likely make your life easier: shiny. But it’s good to know you can still access the WebSocket if needed.
The same is true in other ecosystems. In Python, Django leans toward multi page applications while Flask gives you a minimal foundation to build either way – much like Ambiorix does in R.
4.5 Reactive programming
Most R users who have built web applications have used Shiny, which makes heavy use of reactive programming on the back-end. If that’s your background, it’s worth understanding where reactivity fits – and where it doesn’t.
Reactivity is a natural fit for single page applications. Elements on the page need to react to changes, dynamically sending messages to the client to update what the user sees. Shiny is built around this idea.
In multi page applications, reactivity has little place. Each request arrives, gets processed, and a response is sent back – there is nothing to react to. The interaction is stateless: a request comes in, a response goes out.
You could still use reactivity within individual pages of a multi page application, but it adds complexity. Mixing reactive and non-reactive code is difficult to reason about, and it gives up one of the key advantages of the multi page model: statelessness. Reactive elements imply state, and state has to be managed.
Ambiorix does not use reactivity. It gives you the request-response cycle directly, and you decide what to do with it.