Run a Shiny app in the browser with shinylive for R

Serverless Shiny applications are a hot topic these days. With the arrival of webR, which I wrote about in a previous blog post, it’s possible to run R directly in the browser. One of the supported packages is Shiny, so running a Shiny app directly on the user’s machine was only a few scripts away. But it was still quite a hassle, as I’ve shown before! And for Python, where Shiny is also available, it was much easier because of shinylive. Both Shiny for Python and shinylive for Python were announced during the posit::conf(2022). It was only a matter of time before shinylive came to R! 

During the posit::conf(2023) in September, that moment was finally there: shinylive for R was announced. In this quick tutorial you’ll learn how to run a Shiny app in the browser with shinylive for R.

Prerequisites

In the blog about running a Shiny app with webR, I used a little game called Hangman to demonstrate how to embed a Shiny app in WordPress. For this tutorial we’re also using the Hangman app, which you can find on GitHub.

Furthermore, you will need to install the development version of shinylive, and the development version of httpuv. You can install these packages with the pak package, which is an alternative to install.packages() and devtools::install_github().
				
					pak::pak("posit-dev/r-shinylive")
pak::pak("rstudio/httpuv")
				
			

If you don’t want to use pak, the latter will also work:

				
					devtools::install_github("posit-dev/r-shinylive")
devtools::install_github("rstudio/httpuv")
				
			

Exporting your Shiny app as a shinylive app

Once you have everything installed, it’s very simple to export your Shiny app as a shinylive app. First you will need to create a bunch of files:

				
					shinylive::export("app", "hangman")
				
			

The first argument is the folder that contains your Shiny app, and the second argument is the folder to which you want to export your Shinylive app. Note that your app file needs to be called app.R otherwise shinylive will tell you “Directory app does not contain an app.R file.”

I called the folder “hangman”, but you don’t have too. You can also call it “site” (more conventional), or “docs” (which is handy for GitHub Pages).

Another thing to be aware of is that shinylive will export all files and folders within the folder you give it, so make sure the folder is without clutter.

The /hangman folder

shinylive will create a folder called /hangman which contains the following files and folders:

You don’t have to know what all these files do… But for the nerdy ones out there, here’s an overview:

  • app.json: this is your R code, but formatted to JSON.
  • index.html: this is your HTML and constructs your static web page. The web page serves the Shiny app. It adds the necessary JavaScript dependency from shinylive, and also some CSS. The <script> tag dynamically loads and displays our Hangman app, and it fetches the data from the app.json file. The content of app.json gets processed and we use the runApp function to render the Shiny app in a div element with ID “root”.
				
					<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Shiny App</title>
    <script
      src="./shinylive/load-shinylive-sw.js"
      type="module"
    ></script>
    <script type="module">
      import { runApp } from "./shinylive/shinylive.js";
      const response = await fetch("./app.json");
      if (!response.ok) {
        throw new Error("HTTP error loading app.json: " + response.status);
      }
      const appFiles = await response.json();

      const appRoot = document.getElementById("root");
      runApp(appRoot, "viewer", {startFiles: appFiles}, "r");
    </script>
    <link rel="stylesheet" href="./shinylive/style-resets.css" />
    <link rel="stylesheet" href="./shinylive/shinylive.css" />
  </head>
  <body>
    <div style="height: 100vh; width: 100vw" id="root"></div>
  </body>
</html>

				
			
  • The /edit/index.html file is different from te index.html file. As the name suggests, the script in the /edit folder will allow you to serve up a web page where you can edit the app. It also imports jQuery and jQuery terminal. jQuery Terminal is a JavaScript library that allows developers to create terminal-like interfaces within web applications. It provides a way to simulate a command-line terminal or console environment directly within a web page. Perfect for an R console!
  • The /shinylive folder and shinylive-sw.js contains code where all the magic happens: actually serving up the Shiny app and make sure you can send and receive messages through the websocket. Of course powered by httpuv. Some of the code that was needed in my previous blog, and kindly provided by George Stagg, you can see back in /shinylive/shinylive.js. This folder also contains some R packages, like base, stats, and utils.
 
That’s all you need. With just one simple command you’ll have a bunch of files that all work together to run a Shiny app in the browser. 
 

Running the serverless app locally

If you want to take your serverless Shiny app for spin you can run:

				
					library(plumber)

pr() %>%
  pr_static("/", "hangman/") %>%
  pr_run()
				
			

A nice touch is the pre-loader. And yes, you’ll need a pre-loader! It will take a while for the app to load, just because webR needs to install all kinds of packages (Shiny and its dependencies). 

Hosting the files on WordPress

There’s one thing left to do if you want to make your app available to the world: host the files somewhere on the web. In this example, it will be WordPress, but you can choose any site. The only thing you need is access to the website directory. In the case of this website, the website directory is SiteGround. The general instructions are:

  1. Go to your website directory or file manager
  2. Upload the /hangman folder as generated by shinylive. In the case of WordPress, put it under /public_html. You can also rename it if you want to.  ⚠️ Warning: make sure you’re not overwriting anything, especially when you’re working with a folder called “site”. Your website can break! Make a backup first before playing around. ⚠️ 

 

Note that the /hangman folder contains a lot of files, and a lot of nested folders. Your file manager might not like that. In that case, you can upload a zipped folder and unpack it.

Once you’ve finalized these steps, you can get the URL of the index.html file, and you can go straight to it! For this website that is: https://apps.hypebright.nl/hangman/. I put the app on a subdomain.

Is the app not working after waiting for a minute or so? Try to clear cache and try again, this helps on Safari.

And another note: if you followed the prerequisites I mentioned earlier to work with webR, you have a COEP policy enabled. That doesn’t work with Shinylive, especially on Chrome. You need to disable your COEP policy. For now, you can’t have both (yet).

If everything is successful, the Hangman app will appear:

Yay! Shinylive definitely makes it SO much easier 🎉.

Limitations

Pretty cool to run a Shiny app in the browser with shinylive for R! It’s still experimental and heavily under development, so there are still some limitations:

  • It’s all very new, the shinylive package is under development and experimental, the API can, and most likely will, change. If any of the above code doesn’t work anymore, it’s probably because of that.
  • It’s slow, mainly because it needs to install packages on the fly.
  • Not all packages are available to be used with shinylive/webR. Building packages from source is unlikely to be facilitated in the near future. For now you’ll have to stick with pre-compiled WebAssembly binaries.

 

But did I say it is really cool already?!

Resources

I love seeing so many people jump on shinylive! That means there’s a lot out there already. Here’s a couple of my favorite resources:

Wrap up

This was a quick demonstration of the new shinylive for R package, and hopefully the ease of use has become clear!

⚠️ Both shinylive for R and webR are new and currently under development, the API is not stable yet and might change- meaning these examples might stop working at some stage. 

☕️ Was this useful to you and would you like to support me? You can buy me a coffee!

I provide R and Shiny consultancy. Do you need help with a project? Reach out and let’s have a chat!

Leave a Reply

Your email address will not be published. Required fields are marked *