ETC5523: Communicating with Data
Tutorial 11: Package and audit a Shiny app
🎯 Objectives
By the end of this tutorial, you will be able to:
- add a package function that launches a Shiny app; and
- audit an app before web deployment.
Install the packages used in this tutorial if you do not already have them:
install.packages(c("devtools", "rsconnect", "usethis"))Bring the etc5523-wpl-share project you used in the workshop. If you missed the workshop, or would like a clean copy containing everything completed in class, clone the workshop-progress branch:
#| eval: false
#| echo: true
git clone --branch workshop-progress --single-branch \
https://github.com/numbats/etc5523-wpl-share.gitOpen wplshare.Rproj, restart R, then install any dependencies declared by the package:
devtools::install_deps(dependencies = TRUE)Run the app and confirm that the number, plot and table agree when Minimum runs is exactly 150 in season 2024/25:
shiny::runApp("inst/app")In the workshop, we completed Steps 1–3: running the app, inspecting its reactive graph and replacing the repeated filters with selected_batters(). This tutorial continues from that point with Steps 4 and 5.
4. Make the app launchable from the package
The repository already has the structure of an R package. Files under inst/app will be installed with it.
Create R/run_app.R, then add a documented, exported run_app() function:
usethis::use_r("run_app")The function should:
- locate the installed
appdirectory withsystem.file(); and - pass that directory to
shiny::runApp().
Generate the documentation, install the package and test the launcher:
devtools::document()
devtools::install()
wplshare::run_app()Why would a path such as /Users/name/wpl-share/inst/app fail for another package user?
5. Audit the web deployment
Treat the hosting service as a clean Linux computer that receives only the app bundle. Mark each item ready, not ready, or not applicable:
- all required files are inside
inst/app; - file paths are relative and match the exact case of the file names;
- package dependencies can be detected from the app code;
- there is no
install.packages()call in the app; - no password, token or secret is stored in the repository;
- every possible input state produces a useful response; and
- any durable writes use storage outside the app’s local filesystem.
Ask rsconnect what it detects:
rsconnect::appDependencies("inst/app")Which audit item does the current app handle least well? Make one improvement and rerun the app.
Extra practice: a clean-room handover test
Exchange repositories with a partner. Open your partner’s project in a fresh R session and test whether the package can be installed and run without relying on their source directory or your installed copy of wplshare.
Create a temporary package library, install the package into it, then launch the app from that installation:
test_library <- file.path(tempdir(), "wplshare-library")
dir.create(test_library, showWarnings = FALSE)
devtools::install(lib = test_library)
library(wplshare, lib.loc = test_library)
wplshare::run_app()Record any missing dependency, path assumption or unclear setup instruction. Fix one issue, restart R and repeat the handover test.
Installing into test_library prevents your partner’s package from replacing the usual installed copy of wplshare. The temporary installation is removed when R clears its temporary directory.