# install.packages('pak')
::pak('mjfrigaard/shinypak') pak
4 Development
After creating a DESCRIPTION
file with the mandatory fields, moving the .R
files into the R/
folder, and configuring the project build tools in .Rproj
, we’re ready to test our app-package functionality with the devtools
package.
By ‘functionality’, I mean our app-package can call the devtools
functions for loading the code in R/
, creating documentation, and successfully installing the package from the source files.
If you’d like a refresher on chapters 1 & 2, I’ve provided a summary of these topics below:
4.1 Developing packages with devtools
If you’re new to package development, having a little background on the devtools
package is helpful. Earlier versions of devtools
contained most of the functions used for package development. In version 2.0, devtools
went under a conscious uncoupling, which means there was a “division of labor” for its core functionality:
The
usethis
package contains the functions for creating package folders and files (.R
files, tests, vignettes, etc.).usethis
is also automatically loaded when you calllibrary(devtools)
.Loading and building your app-package is handled by
pkgload
andpkgbuild
For app-packages destined for CRAN, the
R CMD check
is handled byrcmdcheck
andrevdepcheck
Installing packages from non-CRAN repositories (i.e.,
install_github()
) is handled byremotes
You don’t have to install all of these packages (they will be loaded with devtools
), but the information is essential because it affects the dependencies in your app-package:
‘Package developers who wish to depend on
devtools
features should also pay attention to which package the functionality is coming from and depend on that rather thandevtools
. In most cases, packages should not depend ondevtools
directly.’ - devtools 2.0.0, tidyverse blog
We will cover this topic more in the dependencies chapter.
4.2 Building shinyrPkgs
Let’s assume we’re continuing with the app project we converted manually in the previous branch of shinyrPkgs
(the files and folders are below).
See the 03.1_description
branch of shinyrPkgs
.
shinyrPkgs/
├── DESCRIPTION
├── R
│ ├── mod_scatter_display.R
│ ├── mod_var_input.R
│ └── utils.R
├── README.md
├── app.R
├── man
├── movies.RData
├── shinyrPkgs.Rproj
└── www
└── shiny.png
4 directories, 9 files
We’re backing up to the branch we created by manually editing the DESCRIPTION
file to show the connection between the devtools
functions and specific fields in the DESCRIPTION
file.1
4.2.1 DESCRIPTION
The version of shinyrPkgs
in this branch has a DESCRIPTION
file with the seven mandatory fields:
# in Terminal
$ cat DESCRIPTION
Package: shinyrPkgs
Version: 0.0.0.9000
Type: Package
Title: Shiny App-Packages
Description: An R package with a collection of Shiny applications.
Author: John Smith [aut, cre]
Maintainer: John Smith <John.Smith@email.io>
License: GPL-3
Leave an empty final line in the DESCRIPTION
4.2.2 shinyrPkgs.Rproj
However, the .Rproj
file is still configured to work with a Shiny project:2
# in Terminal
$ cat shinyrPkgs.Rproj
Version: 1.0
RestoreWorkspace: Default
SaveWorkspace: Default
AlwaysSaveHistory: Default
EnableCodeIndexing: Yes
UseSpacesForTab: Yes
NumSpacesForTab: 2
Encoding: UTF-8
RnwWeave: Sweave
LaTeX: XeLaTeX
4.3 Package development habits
The differences between developing an R package and a Shiny app can be boiled down to a handful habits, each of which calls a devtools
function:
I’ll use bold to indicate each devtools
habit and accompanying function.
Load all the functions and data in your app-package with
load_all()
Document the app-package functions and data with
document()
Install the app-package with
install()
In the sections below, I’ll cover each function and my opinion about how it should be used when your Shiny app becomes an app-package.3
4.3.1 Load
Install devtools
install.packages("devtools")
library(devtools)
usethis
is automatically loaded/attached with devtools
.
Loading required package: usethis
‘
load_all()
removes friction from the development workflow and eliminates the temptation to use workarounds that often lead to mistakes around namespace and dependency management’ - Benefits ofload_all()
, R Packages, 2ed
load_all()
is the most common devtools
function we’ll use during development because we should load the package when anything changes in the R/
folder.
Ctrl/Cmd + Shift + L
::load_all() devtools
Using load_all()
is similar to calling library(shinyrPkgs)
because it loads the code in R/
along with any data files. load_all()
is also designed for iteration (unlike using source()
), and when it’s successful, the output is a single informative message:
ℹ Loading shinyrPkgs
4.3.2 Document
The document()
function from devtools
serves two purposes:
Writing the package
NAMESPACE
fileCreates the help files in the
man/
folder
devtools
is smart enough to recognize the first time document()
is called, so when I initially run it in the Console, it prompts me that the roxygen2
version needs to be set in the DESCRIPTION
file:
Ctrl/Cmd + Shift + D
::document() devtools
ℹ Updating shinyrPkgs documentation
First time using roxygen2. Upgrading automatically... Setting `RoxygenNote` to "7.3.2"
devtools
relies on roxygen2
for package documentation, so the RoxygenNote
field is required in the DESCRIPTION
. You may have noticed calling document()
also calls load_all()
, which scans the loaded package contents for special documentation syntax before writing the NAMESPACE
file (we’ll cover the NAMESPACE
in the chapter on Dependencies).
ℹ Loading shinyrPkgs Writing NAMESPACE
If we open the NAMESPACE
file, we see it’s empty (and that we shouldn’t edit this file by hand).
![](images/dev_namespace.png)
NAMESPACE
file
The last few output lines warn us to include the Encoding
field in the DESCRIPTION
. devtools
won’t automatically add Encoding
(like it did with RoxygenNote
above), so we’ll need to add it to the DESCRIPTION
file manually:
Warning message:
roxygen2 requires Encoding: "UTF-8" ℹ Current encoding is NA
Package: shinyrPkgs
Version: 0.0.0.9000
Type: Package
Title: movies app
Description: A movies data Shiny application.
Author: John Smith [aut, cre]
Maintainer: John Smith <John.Smith@email.io>
License: GPL-3
RoxygenNote: 7.2.3
Encoding: UTF-8
- 1
-
The
Encoding
value shouldn’t include quotes like the warning message above (i.e.,UTF-8
)
- 2
-
Always leave an empty final line in the
DESCRIPTION
After adding the required fields to the DESCRIPTION
file,4 we’ll document()
the package again using the keyboard shortcut:
In the Build pane, we see the following:
==> devtools::document(roclets = c('rd', 'collate', 'namespace'))
ℹ Updating shinyrPkgs documentation
ℹ Loading shinyrPkgs Documentation completed
Document the package whenever changes are made to any roxygen2
syntax (or settings).
4.3.3 Install
The final package development habit to adopt is regularly installing the package with devtools::install()
.
Ctrl/Cmd + Shift + B
::install() devtools
install()
will prompt the following output in the Build pane:
==> R CMD INSTALL --preclean --no-multiarch --with-keep.source shinyrPkgs
* installing to library ‘/path/to/local/install/shinyrPkgs-090c61fc/R-4.2/x86_64-apple-darwin17.0’
* installing *source* package ‘shinyrPkgs’ ...
** using staged installation
** R
** byte-compile and prepare package for lazy loading
No man pages found in package ‘shinyrPkgs’
** 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 (shinyrPkgs)
There are a few connections worth making in this initial install()
output:
The first line in the output should look familiar–we saw both of these settings in the
shinyrPkgs.Rproj
file from the previous chapterPackageInstallArgs: --no-multiarch --with-keep.source
No man pages found in package 'shinyrPkgs'
tells us none of the code inR/
has adequately been documented (which we’ll cover in theroxygen2
chapter)install()
attempts to install the package from the*source*
files and a ‘bundle’ or source tarball file (i.e.,.tar.gz
)help
files are built, along with other documentation (like vignettes)DONE (shinyrPkgs)
meansshinyrPkgs
was successfully installed!
Install a package after the initial setup, after major changes to the code, documentation, or dependencies, and before committing or sharing.
Launch app with the shinypak
package:
launch('04_devtools')
4.3.4 Check?
devtools::check()
performs a series of checks to ensure a package meets the standards set by CRAN. You can consider check()
as a ‘quality control’ function for documentation, NAMESPACE
dependencies, unnecessary or non-standard folders and files, etc. R Packages recommends using check()
often, but I agree with the advice in Mastering Shiny on using check()
with app-packages,
‘I don’t recommend that you [call
devtools::check()
] the first time, the second time, or even the third time you try out the package structure. Instead, I recommend that you get familiar with the basic structure and workflow before you take the next step to make a fully compliant package.’
However, I’ve included an example of running check()
on shinyrPkgs
in the callout box below to demonstrate how it works.
Recap
Creating an app-package involves adopting some new devtools
habits, and the initial contents of shinyrPkgs
hopefully helped demonstrate the purpose of each function.
The following section will cover documenting functions with roxygen2
If you create or convert your Shiny app project with
usethis::create_package()
, a few fields (i.e.,Roxygen
andRoxygenNote
) are added automatically without explaining their role or purpose.↩︎If you created your Shiny app using the New Project Wizard, your
.Rproj
file has been configured to work with project, not a package.↩︎The topics covered in this section shouldn’t be considered a replacement for the ‘Whole Game’ chapter in R packages (2 ed) or the ‘Workflow’ section of Mastering Shiny (and I highly recommend reading both).↩︎
Always leave an empty final line in the
DESCRIPTION
file.↩︎By convention, files that begin with
.
(dot files) are considered hidden.↩︎