As I mentioned in the final post of my read-me-first Shiny tutorial, the need for a ui variable makes Shiny look like it requires a separate app for every distinct web page. But if you reduce the ui to a stub that has only what you want to be the same on every page of your web site, you can move the rest of each page into the server function.
To fully appreciate the delights this can lead to, you need to understand that when Shiny starts an app, it loads three things – the ui variable, the server function, and any other code outside those two, which become global variables or functions.
On the other hand, when you request a URL from a Shiny server, the app.R code is already running. The server sends the pre-loaded ui variable to the browser and runs the pre-loaded server function.
If you begin that server function by looking to see what URL was requested, you can load additional server code that’s just for that page. There’s no need to load the server code for every page! This saves memory and makes the initial app load much faster. It also provides you with a way to organize large projects by page.
I’ve put sample code for multi-page Shiny web sites on GitHub and in this post I’ll explain more fully what it does and how it works.
The sample code creates a web site with a three-link menu and two actual pages. The third link goes to a bad URL to demonstrate how error handling works. Take a look at the uiStub web site demo and the rest of this post will make more sense.
The app.R code starts with comments, then has a uiStub, then a debugging print statement to clarify how it works, then the server function. The server function builds the menu, checks to see what page was requested, and makes sure that it’s a valid page. There’s another debugging print, then, if the page isn’t a valid page, the server code sends an error message to the browser. If, on the other hand, it’s a good page, the server function loads extra server code for that page and executes it.
It’s important to understand that when the server function loads this extra code, that code becomes part of the server function itself! It’s loaded from inside the server function. Consequently the extra code in the file has no ui variable and it doesn’t define a server function; it just provides additional code for app.R’s server function.
The extra code for the first page, home.R, doesn’t even have any Shiny reactivity. The extra code for Old Faithful is just the server code from my read-me-first Shiny tutorial without the first and last lines that define the server function. This page shows that the demo supports Shiny reactivity.
If you have any questions about this technique you can leave them in the comments.
UPDATE: there’s an enhanced version of this code in a publicly-available version that now includes user authentication: registration, email address verification, logging in, recovering lost passwords, changing passwords and email addresses, and logging out. Details are in our post Multi-page URL-based Shiny web site skeleton with authentication.