developing shiny app as a package and deploying it to shiny server
Asked Answered
T

3

40

I am developing a shiny app and since I wanted to use automated testing and documentation of the function, I started to develop the interface within a package (as recommended here).

I develop this shiny app within RStudio and I have a server.R file which I can click on the Run App button within RStudio and everything works. I commit my package to a github repository and from this point I want to install it on my R shiny server using devtools and install_github function.

Now I am wondering how to start my app within the server. I was naively thinking to install the package and pointing to the server.R file, but this is somehow not working. Not sure where the problems are.

My second try was creating a file called app.R in a folder accessible by the shiny server and in this file I basically load my package, shiny and other needed packages but it somehow complains because of missing variables...

Can somebody give me an advice? I am also happy to answer any question since I am not sure how to ask for this problem properly. Thanks in advance.

EDIT Deploying to shiny server

Since Colin D was asking in the comments, how to deploy these packages on a shiny server, I wanted to demonstrate how I do this.

First of all I install my package on the shiny server directly via the command line as root with the following command.

su - -c "R -e \"devtools::install_github('user/shinypackage')\"" 

The next step is to change the owner of the package folder

chown -R shiny:shiny /usr/local/lib/R/site-library/shinypackage/

Then I restart the shiny server since this was sometimes problematic with caching or so.

systemctl restart shiny-server

These are the steps I do when I update my shiny app. I do this normally again as root in a single line

su - -c "R -e \"devtools::install_github('user/shinypackage')\"" &  chown -R shiny:shiny /usr/local/lib/R/site-library/shinypackage/ & systemctl restart shiny-server

One thing we still need to do is to setup the directory in the shiny-server.conf file. I just added the package path+the application directory where the ui.R and server.R is saved.

  location /shinypackage {
    app_dir /usr/local/lib/R/site-library/shinypackage/application;
    log_dir /var/log/shiny-server;
  }

Then I have to restart the server again by using systemctl restart shiny-server.

This is in use on a Ubuntu Server.

Tempting answered 15/6, 2016 at 9:3 Comment(2)
I do this as a matter of routine. I put my app files in the inst directory of the package and include a function called launch_application which merely calls runApp with my desired default arguments. The app files are found via system.filePacific
Sounds like what I am looking for. What files are in the inst folder then? Just the call of the launch_application function and the library calls? Since I put each function in an extra file in the R folder, I hoped I can export them and just load my package...Tempting
P
30

When I make shiny applications as a stand-alone package, I usually organize the files as so:

In the R directory:

  • All of my methods to support the application (these should be exported if they will be used in either the ui.R, server.R, or global.R files)
  • A launch_application function

The definition of launch_application is similar to:

launch_application <- function(x, ...)
{
  shiny::runApp(appDir = system.file("application", package = [my_pkg]),
                ...)
}

In the inst directory

  • application/server.R
  • application/ui.R
  • application/global.R

After building and installing the package, I then just need to run

library(my_pkg)
launch_application(...)
Pacific answered 15/6, 2016 at 11:14 Comment(9)
Ahhh, now I got it... So server.R and ui.R go into the application folder and only my functions staying in the R folder. I will give it a try though...Tempting
Maybe one more specific question... I am using DT::renderDataTable in my server file. Where should I actually load the library? I was first putting DT as a dependency in my DESCRIPTION file, now, since I moved the server.R into the application directory, while building the package complains, I do not use all dependencies.Tempting
List DT under Suggests and you should be fine.Pacific
Ok, and it took me a while to figure out that I have to set the app_dir in the shiny_server.conf to the output of system.file('application', package='my_pkg')... Since I was creating a file app.R, loading the package and using your suggestion launch_application function but it ended in ERROR: Key / already in use... Not it is working! ThanksTempting
How would you deploy an app with this format on shiny server?Afebrile
I've never used shiny server. So I wouldn't be able to give an informed answer. This may be a good topic to pose as a separate question.Pacific
@ColinD I updated my answer on how I deploy the package directly on the server. Together with a github account, this works in a single line. Write me back if you have questionsTempting
Will this work if using app.R with combined ui and server objects, rather than separately stored in ui.R and server.R ?Capias
Yes. See the appDir argument of ?shiny::runApp for details.Pacific
S
32

There is already an accepted answer with many votes, but I'd like to add a few things, so I'll answer myself as well. For more information, you can read my article Supplementing your R package with a Shiny app.

This is the folder structure I use:

- mypacakge
  |- inst
      |- myapp
         |- ui.R
         |- server.R
  |- R
     |- runApp.R
     |- ...
  |- DESCRIPTION
  |- ...

Inside the R/ folder is where I place all the non-shiny code. The code for the shiny app itself lives in inst/. The R/runApp.R file is defined as

#' @export
runExample <- function() {
  appDir <- system.file("myapp", package = "mypackage")
  if (appDir == "") {
    stop("Could not find myapp. Try re-installing `mypackage`.", call. = FALSE)
  }

  shiny::runApp(appDir, display.mode = "normal")
}

(You can see this in action; for example, shinyalert uses this structure for its demo app).

In a comment, you asked how can this be deployed on a shiny server. It's simple, you can simply have a file /srv/shiny-server/myapp.app.R that calls and runs that package (after you've installed the package on the server):

dir <- system.file("myapp", package = "mypackage")
setwd(dir)
shiny::shinyAppDir(".")

(You can see this in action as well, code here)

Staminody answered 3/4, 2018 at 6:45 Comment(2)
Hi, thanks @DeanAttali, for your code ! I have documented the file myapp/global.R. It contains all the functions used by the application. How can add them to the documentation of the package ?Heidy
Thank you, @DeanAttali, your explanation helps me.Tamikatamiko
P
30

When I make shiny applications as a stand-alone package, I usually organize the files as so:

In the R directory:

  • All of my methods to support the application (these should be exported if they will be used in either the ui.R, server.R, or global.R files)
  • A launch_application function

The definition of launch_application is similar to:

launch_application <- function(x, ...)
{
  shiny::runApp(appDir = system.file("application", package = [my_pkg]),
                ...)
}

In the inst directory

  • application/server.R
  • application/ui.R
  • application/global.R

After building and installing the package, I then just need to run

library(my_pkg)
launch_application(...)
Pacific answered 15/6, 2016 at 11:14 Comment(9)
Ahhh, now I got it... So server.R and ui.R go into the application folder and only my functions staying in the R folder. I will give it a try though...Tempting
Maybe one more specific question... I am using DT::renderDataTable in my server file. Where should I actually load the library? I was first putting DT as a dependency in my DESCRIPTION file, now, since I moved the server.R into the application directory, while building the package complains, I do not use all dependencies.Tempting
List DT under Suggests and you should be fine.Pacific
Ok, and it took me a while to figure out that I have to set the app_dir in the shiny_server.conf to the output of system.file('application', package='my_pkg')... Since I was creating a file app.R, loading the package and using your suggestion launch_application function but it ended in ERROR: Key / already in use... Not it is working! ThanksTempting
How would you deploy an app with this format on shiny server?Afebrile
I've never used shiny server. So I wouldn't be able to give an informed answer. This may be a good topic to pose as a separate question.Pacific
@ColinD I updated my answer on how I deploy the package directly on the server. Together with a github account, this works in a single line. Write me back if you have questionsTempting
Will this work if using app.R with combined ui and server objects, rather than separately stored in ui.R and server.R ?Capias
Yes. See the appDir argument of ?shiny::runApp for details.Pacific
I
4

A lot of packages with proof-of-concept Shiny demos are not designed for deployment on Shiny Server, but instead, include something like this in a function meant to be run from RStudio:

fooRun <- function() {
   app <- shinyApp(appUI, appServer)
   runApp(app, launch.browser = TRUE, ...)
}

This function won't work in Shiny Server (you can't run runApp within runApp) but it gives some clues as to how to create an app.R that can act as a placeholder to use in /srv/shiny-server/foo/app.R

library("foo")
shinyApp(ui = foo:::appUI, server = foo:::appServer)
Ingenuity answered 9/8, 2019 at 18:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.