<p><div><div><div><div data-show-faces="false" data-height="21" data-width="100" data-layout="button_count" data-send="true" data-href="https://www.r-bloggers.com/packaging-shiny-applications-a-deep-dive/"></div></div><div></div></div><div></div></div>
<div>
(This article was first published on <strong><a href="https://www.mango-solutions.com/blog/packaging-shiny-applications-a-deep-dive"> Mango Solutions</a></strong>, and kindly contributed to <a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers)</a> </div>
<p> <img sizes="100vw" src="https://i0.wp.com/www.mango-solutions.com/blog/images/9/d/c/7/2/9dc722f661183460eeab4684f2cb294d10fce2a1-packaging-shiny-applications-1.png?w=456&ssl=1" data-recalc-dims="1"></p>
<p><em>(Or, how to write a Shiny app.R file that only contains a single line of code)</em></p>
<h5>Mark Sellors, Head of Data Engineering</h5>
<p>This post is long overdue. The information contained herein has been built up over years of deploying and hosting Shiny apps, particularly in production environments, and mainly where those Shiny apps are very large and contain a lot of code.</p>
<p>Last year, during some of my conference talks, I told the story of Mango’s early adoption of Shiny and how it wasn’t always an easy path to production for us. In this post I’d like to fill in some of the technical background and provide some information about Shiny app publishing and packaging that is hopefully useful to a wider audience.</p>
<p>I’ve figured out some of this for myself, but the most pivotal piece of information came from Shiny creator, Joe Cheng. Joe told me some time ago, that all you really need in an app.R file is a function that returns a Shiny application object. When he told me this, I was heavily embedded in the publication side and I didn’t immediately understand the implications.</p>
<p>Over time though I came to understand the power and flexibility that this model provides and, to a large extent, that’s what this post is about.</p>
<h3>What is Shiny?</h3>
<p>Hopefully if you’re reading this you already know, but <a rel="nofollow" href="https://shiny.rstudio.com/" target="_blank">Shiny is a web application framework for Ri</a>. It allows R users to develop powerful web applications entirely in R without having to understand HTML, CSS and JavaScript. It also allows us to embed the statistical power of R directly into those web applications.</p>
<p>Shiny apps generally consist of either a ui.R and a server.R (containing user interface and server-side logic respectively) or a single app.R which contains both.<br>
Why package a Shiny app anyway?</p>
<p>If your app is small enough to fit comfortably in a single file, then packaging your application is unlikely to be worth it. As with any R script though, when it gets too large to be comfortably worked with as a single file, it can be useful to break it up into discrete components.</p>
<p>Publishing a packaged app will be more difficult, but to some extent that will depend on the infrastructure you have available to you.</p>
<h3>Pros of packaging</h3>
<p>Packaging is one of the many great features of the R language. Packages are fairly straightforward, quick to create and you can build them with a host of useful features like built-in documentation and unit tests.</p>
<p>They also integrate really nicely into Continuous Integration (CI) pipelines and are supported by tools like Travis. You can also get test coverage reports using things like codecov.io.</p>
<p>They’re also really easy to share. Even if you don’t publish your package to CRAN, you can still share it on GitHub and have people install it with devtools, or build the package and share that around, or publish the package on a CRAN-like system within your organisation’s firewall.</p>
<h3>Cons of packaging</h3>
<p>Before you get all excited and start to package your Shiny applications, you should be aware that — depending on your publishing environment — packaging a Shiny application may make it difficult or even impossible to publish to a system like Shiny Server or RStudio Connect, without first unpacking it again.</p>
<h3>A little bit of Mango history</h3>
<p>This is where Mango were in the early days of our Shiny use. We had a significant disconnect between our data scientists writing the Shiny apps and the IT team tasked with supporting the infrastructure they used. This was before we’d committed to having an engineering team that could sit in the middle and provide a bridge between the two.</p>
<p>When our data scientists would write apps that got a little large or that they wanted robust tests and documentation for, they would stick them in packages and send them over to me to publish to our original Shiny Server. The problem was: R packages didn’t really mean anything to me at the time. I knew how to install them, but that was about as far as it went. I knew from the Shiny docs that a Shiny app needs certain files (server.R and ui.R or an app.R) file, but that wasn’t what I got, so I’d send it back to the data science team and tell them that I needed those files or I wouldn’t be able to publish it.</p>
<p>More than once I got back a response along the lines of, “but you just need to load it up and then do runApp()”. But, that’s just not how Shiny Server works. Over time, we’ve evolved a set of best practices around when and how to package a Shiny application.</p>
<p>The first step was taking the leap into understanding Shiny and R packages better. It was here that I started to work in the space between data science and IT.</p>
<h3>How to package a Shiny application</h3>
<p>If you’ve seen the simple app you get when you choose to create a new Shiny application in RStudio, you’ll be familiar with the basic structure of a Shiny application. You need to have a UI object and a server function.</p>
<p>If you have a look inside the UI object you’ll see that it contains the html that will be used for building your user interface. It’s not everything that will get served to the user when they access the web application — some of that is added by the Shiny framework when it runs the application — but it covers off the elements you’ve defined yourself.</p>
<p>The server function defines the server-side logic that will be executed for your application. This includes code to handle your inputs and produce outputs in response.</p>
<p>The great thing about Shiny is that you can create something awesome quite quickly, but once you’ve mastered the basics, the only limit is your imagination.</p>
<p>For our purposes here, we’re going to stick with the ‘geyser’ application that RStudio gives you when you click to create a new Shiny Web Application. If you open up RStudio, and create a new Shiny app — choosing the single file app.R version — you’ll be able to see what we’re talking about. The small size of the geyser app makes it ideal for further study.</p>
<p>If you look through the code you’ll see that there are essentially three components: the UI object, the server function, and the <code>shinyApp()</code> function that actually runs the app.</p>
<p>Building an R package of just those three components is a case of breaking them out into the constituent parts and inserting them into a blank package structure. We have a <a rel="nofollow" href="https://github.com/mangothecat/shinyAppDemo" target="_blank">version of this up on GitHub</a> that you can check out if you want.</p>
<p>The directory layout of the demo project looks like this:</p>
<pre><code>|-- DESCRIPTION
|-- LICENSE
|-- NAMESPACE
|-- R
|   |-- launchApp.R
|   |-- shinyAppServer.R
|   `-- shinyAppUI.R
|-- README.md
|-- inst
|   `-- shinyApp
|       `-- app.R
|-- man
|   |-- launchApp.Rd
|   |-- shinyAppServer.Rd
|   `-- shinyAppUI.Rd
`-- shinyAppDemo.Rproj</code></pre>
<p>Once the app has been adapted to sit within the standard R package structure we’re almost done. The UI object and server function don’t really need to be exported, and we’ve just put a really thin wrapper function around <code>shinyApp()</code> — I’ve called it <code>launchApp()</code> — which we’ll actually use to launch the app. If you install the package from GitHub with devtools, you can see it in action.</p>
<pre><code>library(shinyAppDemo)
launchApp()</code></pre>
<p>This will start the Shiny application running locally.</p>
<p>The approach outlined here also works fine with <a rel="nofollow" href="https://shiny.rstudio.com/articles/modules.html" target="_blank">Shiny Modules</a>, either in the same package, or called from a separate package.</p>
<p>And that’s almost it! The only thing remaining is how we might deploy this app to Shiny server (including Shiny Server Pro) or RStudio Connect.</p>
<h3>Publishing your packaged Shiny app</h3>
<p>We already know that Shiny Server and RStudio Connect expect either a ui.R and a server.R or an app.R file. We’re running our application out of a package with none of this, so we won’t be able to publish it until we fix this problem.</p>
<p>The solution we’ve arrived at is to create a directory called ‘shinyApp’ inside the inst directory of the package. For those of you who are new to R packaging, the contents of the ‘inst’ directory are essentially ignored during the package build process, so it’s an ideal place to put little extras like this.</p>
<p>The name ‘shinyApp’ was chosen for consistency with Shiny Server which uses a ‘shinyApps’ directory if a user is allowed to serve applications from their home directory.</p>
<p>Inside this directory we create a single ‘app.R’ file with the following line in it:</p>
<pre><code>shinyAppDemo::launchApp()</code></pre>
<p>And that really is it. This one file will allow us to publish our packaged application under some circumstances, which we’ll discuss shortly.</p>
<p>Here’s where having a packaged Shiny app can get tricky, so we’re going to talk you through the options and do what we can to point out the pitfalls.</p>
<h3>Shiny Server and Shiny Server Pro</h3>
<p>Perhaps surprisingly — given that <a rel="nofollow" href="https://www.rstudio.com/products/shiny/shiny-server/" target="_blank">Shiny Server</a> is the oldest method of Shiny app publication — it’s also the easiest one to use with these sorts of packaged Shiny apps. There are basically two ways to publish on Shiny Server. From your home directory on the server — also known as self-publishing — or publishing from a central location, usually the directory ‘/srv/shiny-server’.</p>
<p>The central benefit of this approach is the ability to update the application just by installing a newer version of the package. Sadly though, it’s not always an easy approach to take.</p>
<h4>Apps served from home directory (AKA self-publishing)</h4>
<p>The first publication method is <a rel="nofollow" href="http://docs.rstudio.com/shiny-server/#host-per-user-application-directories" target="_blank">from a users’ home directory</a>. This is generally used in conjunction with RStudio Server. In the self-publishing model, Shiny Server (and Pro) expect apps to be found in a directory called ‘ShinyApps’, within the users home directory. This means that if we install a Shiny app in a package the final location of the app directory will be inside the installed package, not in the ShinyApps directory. In order to work around this, we create a link from where the app is expected to be, to where it actually is within the installed package structure.</p>
<p>So in the example of our package, we’d do something like this in a terminal session:</p>
<pre><code># make sure we’re in our home directory
cd
# change into the shinyApps directory
cd shinyApps
# create a link from our app directory inside the package
ln -s /home/sellorm/R/x86_64-pc-linux-gnu-library/3.4/shinyAppDemo/shinyApp ./testApp</code></pre>
<p>Note: The path you will find your libraries in will differ from the above. Check by running <code>.libPaths()[1]</code> and then <code>dir(.libPaths()[1])</code> to see if that’s where your packages are installed.</p>
<p>Once this is done, the app should be available at ‘http://