3 min read

shiny app as R package

Background

I love and use shiny regularly and I also try to modularize my work more and more. Naturally I started to wonder whether I could have a whole shiny app as an R package and then possibly a project organizing multiple apps together. The answer is yes as I suspected.

Several others already wrote about the topic, including Dean Attali and William Landau. However, I gained a deeper understanding by trying things out myself.

You have two main options to run a shiny app:

  • either launch shiny in a directory with a server.R and ui.R file,
  • or launch a shiny object with ui and server parts defined appropriately.

Until now I always used the first method but to put an app in a package you need the second. This is probably why it took some time for me to understand how a package containing a shiny app can work.

Implementation

Taking this functional method there is actually no difficulty in putting a shiny app in a package. You define a function for both your ui and server parts and have a function for launching the app which is the only function you need to export from your package.

shinypackage_ui <- function() {
    fluidPage(...)
}

shinypackage_server <- function(input, output, session) {
    ...
}
#' @param ... passed to runApp, e.g. port, launch.browser
#' @export
runShinyPackageApp <- function(...) {
    app <- shinyApp(
        ui = shinypackage_ui(),
        server = shinypackage_server
    )
    runApp(app, ...)
}

If you have data loading during runtime or any dependencies outside your package it will work as usual.

(Not) using global.R

One significant difference between the two methods to run a shiny app is the use of the global.R file. (The onStart param is related but different.) I generally use global.R for the following things:

  • source libraries,
  • source functions,
  • define project-wide constants or load data used in ui,
  • define values which may change between launches of the app.

The first three points are in fact easier and cleaner in a package.

  • You can import packages package-wide or for specific functions,
  • all functions within package are automatically available to other functions,
  • you can use internal data of any kind in your package.

For the last one instead of declaring global variables (not a good practice anyways) you may pass paramaters to the runShinyPackageApp function which can pass them on to the server and ui, for example:

runShinyPackageApp <- function(launch_param = NULL, ...) {
    app <- shinyApp(
        ui = shinypackage_ui(launch_param),
        server = shinypackage_server
    )
    runApp(app, ...)
}

Conclusion

I recommend putting shiny apps in R packages but even if I don’t I will use the functional form more as it seems clearer to me now.

You can see the the whole code on github and try for yourselves with:

devtools::install_github(
    "czeildi/shinypackage", ref = "v0.4.0"
)