usethis::use_description(
  fields = list(
    Package = 'monthAppPkg',
    Title = 'An example app-pkg',
    Version = '0.0.0.9000',
    Description = 'A shiny application built inside an R package.',
    "Authors@R" = NULL,
    Author = utils::person(
      given = "Jane",
      family = "Doe",
      role = c("aut", "cre")
    ),
    Maintainer = utils::person(
      given = "Jane",
      family = "Doe",
      email = "Jane.Doeh@email.io"
    ),
    License = "GPL-3"
  )
)1 Whole app game
This chapter is modeled on the Whole Game chapter in R Packages, 2ed.1 We’ll go through the development of the monthAppPkg Shiny app-package (adapted from Mastering Shiny).2
1.1 A toy app-package
We will briefly discuss creating an R package with a Shiny application. Each topic will be explained in detail in the next chapters. In the end, you will have a Shiny application with all the features and functions of an R package.
1.2 Package metadata
Every R package requires a DESCRIPTION file. You can quickly create one using usethis::use_description().3
The values above in the fields list avoids the boilerplate content from use_description().4
The essential seven fields are shown below:5
Package: monthAppPkg
Title: An example app-pkg
Version: 0.0.0.9000
Author: Jane Doe [aut, cre]
Maintainer: Jane Doe <Jane.Doeh@email.io>
Description: A shiny application built inside an R package.
License: GPL-3You will get specific fields automatically for function documentation and dependency management.6
Encoding: UTF-8
Roxygen: list(markdown = TRUE)
RoxygenNote: 7.2.31.3 Data
To include the birthstones.csv data in monthAppPkg, we’ll create a data-raw/ folder with usethis::use_data_raw("stones"). Next, we’ll move the birthstones.csv file into data-raw/, load it into the Global Environment, and an R package data object witho usethis::use_data():
usethis::use_data_raw("stones")✔ Setting active project to '/path/to/monthAppPkg'
✔ Creating 'data-raw/'
✔ Adding '^data-raw$' to '.Rbuildignore'
✔ Writing 'data-raw/stones.R'
• Modify 'data-raw/stones.R'
• Finish the data preparation script in 'data-raw/stones.R'
• Use `usethis::use_data()` to add prepared data to packageMove birthstones.csv to data-raw/birthstones.csv:
fs::file_move(path = "birthstones.csv", new_path = "data-raw/birthstones.csv")Contents of data-raw/stones.R:
## code to prepare `stones` dataset goes here
library(vroom)
stones <- vroom::vroom("data-raw/birthstones.csv")
usethis::use_data(stones, overwrite = TRUE)Rows: 12 Columns: 2                                                                                                                                
── Column specification ──────────────────────────────────────────────────
Delimiter: ","
chr (2): month, stone
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.usethis::use_data(stones)✔ Adding 'R' to Depends field in DESCRIPTION
✔ Setting LazyData to 'true' in 'DESCRIPTION'
✔ Saving 'stones' to 'data/stones.rda'
• Document your data (see 'https://r-pkgs.org/data.html')Data should be documented using roxygen2 which we’ll cover in the data chapter.7
1.4 Dependencies
Every Shiny app-package depends on the shiny package. usethis::use_package()8 adds it under the Imports field the DESCRIPTION file.
usethis::use_package("shiny")✔ Adding 'shiny' to Imports field in DESCRIPTION
• Refer to functions with `shiny::fun()`We’re advised to use explicit namespacing (i.e., pkg::fun()), but we can avoid this by importing all Shiny’s functions into our package namespace using the @import tag from roxygen2.9
1.5 Package code
Create new .R files under R/ using use_r():
usethis::use_r("monthFeedback")✔ Setting active project to '/projects/apps/monthAppPkg'
• Modify 'R/monthFeedback.R'Both UI and server module functions are stored in R/monthFeedback.R and R/birthstone.R. Tests should also be created for each function.
1.6 Loading
Shiny app development typically involves something like the following workflow:
- Write UI/server code
 
- Click Run App
 
- Rinse, repeat
When making the switch from app development to app-package development, calling load_all() is somewhat analogous to clicking on the Run App icon–you’ll do it often (more than any other devtools or usethis function).
devtools::load_all()The output we’re looking for from load_all() is straightforward:
ℹ Loading monthAppPkgload_all() is similar to calling library, but it’s specifically designed to be used during package development. Imagine sourcing all the functions in the R/ folder, but more sophisticated.
1.7 Package tests
Create tests for the code in the R/ folder using use_test()
usethis::use_test("monthFeedbackServer")This will add test- files in tests/testthat/:
tests/
├── testthat/
│   └── test-monthFeedbackServer.R
└── testthat.R
2 directories, 2 filesThe first time you run use_test(), it will detect if your package has the testthat infrastructure (and create the necessary files if you don’t).10 use_test() will also adds the testthat package to the Suggests field in the DESCRIPTION and includes the edition (currently 3).
✔ Adding 'testthat' to Suggests field in DESCRIPTION
✔ Adding '3' to Config/testthat/editionTests are covered in Mastering Shiny,11 on the Shiny website,12 and in various testing packages (like shinytest13 and shinytest214).
1.8 app.R
The contents of app.R have been changed to include a call to pkgload::load_all() the standalone app function (monthApp()), which is stored in the R/ folder.
pkgload::load_all(".")
monthApp()pkgload needs to be listed under Imports in the DESCRIPTION file (just like we did with shiny above).
usethis::use_package("pkgload")✔ Adding 'pkgload' to Imports field in DESCRIPTION
• Refer to functions with `pkgload::fun()`Because we’re only going to use load_all() from pkgload, we’ll use explicit namespacing (i.e., pkg::fun()).15
1.8.1 use_package_doc()
The use_package_doc() creates the R/[[name]-package].R file, which can be used as a single location for declaring dependencies in monthAppPkg:
usethis::use_package_doc()✔ Setting active project to 'projects/apps/monthAppPkg'
✔ Writing 'R/monthAppPkg-package.R'
• Modify 'R/monthAppPkg-package.R'We’ll use @importFrom to add only the load_all() function to the NAMESPACE.
#' @keywords internal
"_PACKAGE"
## usethis namespace: start
#' @importFrom pkgload load_all
## usethis namespace: end
NULL1.8.2 use_build_ignore()
R packages don’t typically have an app.R file in their root folder, so we’ll let devtools know this file should be ignored by creating a .Rbuildignore and include a pattern that excludes app.R whenever the package is built.
usethis::use_build_ignore("app.R")✔ Adding '^app\\.R$' to '.Rbuildignore'It’s best to let use_build_ignore() handle excluding any files or folders from your package builds because it automatically writes the correct regular expression pattern.
1.9 LICENSE
Use one of the usethis license functions to add a LICENSE file.
usethis::use_mit_license()The license file should match the License field in the DESCRIPTION file (in this case, it’s MIT).16
✔ Adding 'MIT + file LICENSE' to License
✔ Writing 'LICENSE'
✔ Writing 'LICENSE.md'
✔ Adding '^LICENSE\\.md$' to '.Rbuildignore'1.10 Document
After writing roxygen2 documentation for the data, modules, and standalone app function, calling devtools::document()() generates the .Rd files and NAMESPACE.17
devtools::document()The output from document() tells us what files have been created (and if there were any errors in them).18
ℹ Updating monthAppPkg documentation
ℹ Loading monthAppPkg
Writing NAMESPACE
Writing NAMESPACE
Writing birthstoneUI.Rd
Writing birthstoneServer.Rd
Writing monthApp.Rd
Writing monthFeedbackUI.Rd
Writing monthFeedbackServer.Rd1.10.1 Namespace
The NAMESPACE file contains the imported and exported functions from monthAppPkg:19
# Generated by roxygen2: do not edit by hand
export(birthstoneServer)
export(birthstoneUI)
export(monthApp)
export(monthFeedbackServer)
export(monthFeedbackUI)
import(shiny)
importFrom(pkgload,load_all)1.11 RStudio project options 
If you’re developing in RStudio, we need to update our .Rproj file to enable the Build pane and keyboard shortcuts:
file.edit("monthAppPkg.Rproj")If your app-package was initially built as an RStudio project (i.e., not as a package), the following fields should be included at the bottom of monthAppPkg.Rproj:
BuildType: Package
PackageUseDevtools: Yes
PackageInstallArgs: --no-multiarch --with-keep.source
PackageRoxygenize: rd,collate,namespaceThese options are also available under Tools > Project Options … > Build Tools
1.12 Git
The use_git() step is performed much earlier in R Packages, 2ed, but I’ve saved it for this step because using Git will prompt the IDE to re-initialize and display the Git pane (and it will also read our new settings in the .Rproj file).
✔ Setting active project to '/projects/apps/monthAppPkg'
✔ Initialising Git repo
✔ Adding '.Rproj.user', '.Rhistory', '.Rdata', '.httr-oauth', '.DS_Store', '.quarto' to '.gitignore'
There are 12 uncommitted files:
* '.gitignore'
* '.Rbuildignore'
* 'app.R'
* 'data/'
* 'DESCRIPTION'
* 'LICENSE'
* 'LICENSE.md'
* 'man/'
* 'monthAppPkg.Rproj'
* 'NAMESPACE'
* ...
Is it ok to commit them?
1: Absolutely not
2: Not now
3: AbsolutelyAgree to commit these files:
Selection: 3
✔ Adding files
✔ Making a commit with message 'Initial commit'
• A restart of RStudio is required to activate the Git pane
Restart now?
1: Not now
2: Negative
3: AbsolutelyRestarting RStudio will activate the Git and Build panes:
This will also activate the devtools keyboard shortcuts:
1.13 Keyboard shortcuts
The devtools keyboard shortcuts are available in RStudio and Positron.
load_all()
Shift + Ctrl/Cmd + L
document()
Shift + Ctrl/Cmd + D
install()
Shift + Ctrl/Cmd + B
test()
Shift + Ctrl/Cmd + T
1.14 Install
Installing monthAppPkg with devtools::install() produces see the following output in the Build pane:
==> devtools::document(roclets = c('rd', 'collate', 'namespace'))
ℹ Updating monthAppPkg documentation
ℹ Loading monthAppPkg
Documentation completed
==> R CMD INSTALL --preclean --no-multiarch --with-keep.source monthAppPkg
* installing to library ‘/path/to/Library/R/x86_64/4.2/library’
* installing *source* package ‘monthAppPkg’ ...
** using staged installation
** R
** data
*** moving datasets to lazyload DB
** byte-compile and prepare package for lazy loading
** help
*** installing help indices
** building package indices
** testing if installed package can be loaded from temporary location
** testing if installed package can be loaded from final location
** testing if installed package keeps a record of temporary installation path
* DONE (monthAppPkg)Back in the Console, RStudio will restart and call library(monthAppPkg):
Restarting R session...
> library(monthAppPkg)We can now launch the app using monthApp()
monthApp()Launch app with the shinypak package:
launch('01_whole-app-game')1.15 Additional files
The following sections cover additional files you should include in your ap-package (but are not required).
1.15.1 README
A README.md file is the initial point of contact for users and/or contributors looking for information about your app-package. use_readme_rmd() will create a README.Rmd (i.e., the file you’ll edit), which serves as the source document for your README.md.
usethis::use_readme_rmd()The README.Rmd pattern is automatically added to the .Rbuildignore, and includes a Git ‘pre-commit’ hook:20
✔ Adding '^README\\.Rmd$' to '.Rbuildignore'
✔ Writing '.git/hooks/pre-commit'1.15.2 NEWS.md
A NEWS.md is helpful for logging updates to your app-package and tracking release information.
usethis::use_news_md()use_news_md() will also prompt me to add and commit this file to the Git repository:
There is 1 uncommitted file:
* 'NEWS.md'
Is it ok to commit it?
1: Negative
2: Yeah
3: Absolutely not
Selection: 2
✔ Adding files
✔ Making a commit with message 'Add NEWS.md'The contents of the NEWS.md are below:21
# monthAppPkg (development version)
* Initial CRAN submission.1.15.3 Vignettes
Vignettes can be used to store detailed tutorials, explanations of core concepts, use-cases, FAQs and troubleshooting, integration with other packages, etc.
use_vignette("monthAppPkg")The first time we call use_vignette() will prompt usethis to add the following fields in the DESCRIPTION:
✔ Adding 'knitr' to Suggests field in DESCRIPTION
✔ Adding 'rmarkdown' to Suggests field in DESCRIPTION
✔ Adding 'knitr' to VignetteBuilderThe following files are also included in the .gitignore:
✔ Adding 'inst/doc' to '.gitignore'
✔ Creating 'vignettes/'
✔ Adding '*.html', '*.R' to 'vignettes/.gitignore'1.16 Recap
In this chapter we’ve covered the steps used to create a package containing a Shiny application.
- The example app comes from the Packages chapter of Mastering Shiny↩︎ 
- I’ve stored the code for this application in the - 01_whole-app-gamebranch of the- saprepository (to avoid confusing it with the actual application repo for this chapter).↩︎
- The Whole Game chapter of R Packages, 2ed begins with the - usethis::create_package()function, which calls- usethis::use_description()internally.↩︎
- At the time this was written, there are over 4,000 hits with the boilerplate value for - Description(i.e.,- "What the package does"), which is a sign of how much- usethishas been adopted (and how often people forget to come back and edit their- DESCRIPTIONfile).↩︎
- If you frequently develop R packages or Shiny apps, consider adding these fields to your - .Rprofile.↩︎
- Always leave an empty final line in the - DESCRIPTION.↩︎
- View the documented - stonesdataset here on GitHub.↩︎
- Whenever you use a function from another package, start by running - usethis::use_package()to ensure it’s in the- DESCRIPTIONfile.↩︎
- I’ve included - @import shinyabove the definition of our standalone app function (- R/launch_app.R), which means I don’t need to add- shiny::when using Shiny functions below- R/.↩︎
- You can also set up the - testthatinfrastructure by calling- usethis::use_testthat()↩︎
- The Testing chapter in Mastering Shiny covers unit tests with - testthat,- shiny::testServer(), and the- shinytestpackage.↩︎
- See the ‘Server Function Testing’ article on the Shiny website for more information on - testServer()↩︎
- Check the - shinytestpackage website and video tutorial for more information on testing your app.↩︎
- shinytest2is an updated verison of- shinytestwith excellent documentation and videos.↩︎
- We typically call - devtools::load_all(), but using- pkgloadreduces the number of dependencies included with- devtools. Read more about- pkgloadin the ‘Conscious uncoupling’ of- devtools.↩︎
- use_mit_license()will automatically include the- LICENSE.mdfile in the root folder (and includes the necessary pattern in the- .Rbuildignoreto exclude it from the package builds).↩︎
- You can include an Roxygen skeleton in the IDE by clicking on Code > Insert Roxygen Skeleton, or using the keyboard shortcut: Option/⌥ + Shift⇧ + Ctrl/Cmd + R↩︎ 
- The files created by - document()rely on the- roxygen2package (and should not be edited manually).↩︎
- We’re importing the everything from - shinyand only- load_allfrom- pkgload):↩︎
- This Git behavior is designed to prevent us from making changes to the - README.Rmdand forgetting to re-render the- README.md. If you find this behavior confusing or would like to disable it, run the following commands in the Terminal:- rm .git/hooks/pre-commit↩︎
- The - Initial CRAN submissionbullet doesn’t apply to- monthAppPkg, so I’ll remove it and re-commit/push the- NEWS.mdfile.↩︎


