pak::pkg_deps_tree("rlang")35 🏗️ Dependency hell
Mastering dependency management
This chapter covers a few packages and tools to help explore, understand and keep track of your app-package dependencies.1 It’s not likely you’ll build an application that only relies on shiny, so it’s important to 1) know the packages and versions required for your application to function, and 2) ensure these packages are included in the correct DESCRIPTION field (or NAMESPACE).
35.1 Exploring dependencies
The first package we’ll cover is pak, which is, “A Fresh Approach to R Package Installation.” pak includes two tools I’ve found to be incredibly helpful for understanding the dependencies in a given package (or a package I’m building): dependency trees and the dependency explainer.
Launch app with the shinypak package:
launch('28_dependency-hell')35.1.1 Trees
pak::pkg_deps_tree() shows us the dependencies for a particular package. To demonstrate how this function works, we’ll explore the dependencies in three packages:
rlang: “Functions for Base Types and Core R and ‘Tidyverse’ Features”lifecycle: “Manage the Life Cycle of your Package Functions”, andvctrs: “Vector Helpers”
Let’s start with the rlang package:
rlang 1.1.1 ✨
Key: ✨ newrlang is “a collection of frameworks and APIs for programming with R” and it’s built with only base R packages (that’s why it’s DESCRIPTION file only Imports the utils package):
Imports:
utilsNow lets look at lifecycle:
pak::pkg_deps_tree(pkg = "lifecycle")lifecycle 1.0.3 ✨ ⬇ (123.60 kB)
├─cli 3.6.1 ✨
├─glue 1.6.2 ✨
└─rlang 1.1.1 ✨lifecycle depends on cli, glue, and rlang.
If we look at the DESCRIPTION file for lifecycle, it also imports cli, glue, and rlang (and specifies versions for cli and rlang)
Imports:
cli (>= 3.4.0),
glue,
rlang (>= 1.1.0)Finally, lets look at the dependencies in the vctrs package. The DESCRIPTION file for vctrs imports cli, glue, lifecycle, and rlang
Imports:
cli (>= 3.4.0),
glue,
lifecycle (>= 1.0.3),
rlang (>= 1.1.0)If we check the dependency tree, we see the cli, glue, and rlang are listed twice (once for vctrs, and again for lifecycle):
pak::pkg_deps_tree(pkg = "vctrs")vctrs 0.6.4 ✨
├─cli 3.6.1 ✨
├─glue 1.6.2 ✨
├─lifecycle 1.0.3 ✨ ⬇ (123.60 kB)
│ ├─cli
│ ├─glue
│ └─rlang 1.1.1 ✨
└─rlang
Key: ✨ new | ⬇ downloadvctrs depends on cli, glue, rlang, and lifecycle (which also depends on cli, glue, and rlang)
35.1.2 Explain
We can show dependency relationships with pak::pkg_deps_explain(). For example,
How does lifecycle depend on rlang?
pak::pkg_deps_explain("lifecycle", "rlang")lifecycle -> rlang How does vctrs depend on rlang?
pak::pkg_deps_explain("vctrs", "rlang")vctrs -> lifecycle -> rlang
vctrs -> rlangvctrs directly depends on rlang and lifecycle (which also depends on rlang).
35.1.3 Depends
So far we’ve been including add-on functions to the Imports field in the DESCRIPTION, which ensures the package is installed with our app-package, but not attached to the search list. However, if we include a package in the Depends field, it’s installed and attached.
This is rarely needed, but a great example is the relationship between devtools usethis:
pak::pkg_deps_explain("devtools", "usethis")devtools -> usethisIn the DECRIPTION file for devtools, usethis is listed with a version number under Depends:
Depends:
usethis (>= 2.1.6)35.1.4 Case study: devtools
The conscious uncoupling of devtools split package development across multiple packages. Let’s see how this works, starting with the commonly used devtools function load_all()
35.1.4.1 pkgload
load_all() is handled by the pkgload package, which “Simulate[s] Package Installation and Attach”.
How does devtools depend on pkgload?
pak::pkg_deps_explain("devtools", "pkgload")devtools -> pkgload
devtools -> roxygen2 -> pkgload
devtools -> testthat -> pkgloadThis relationship shows the three actions that call load_all() during package development:
devtools::load_all()actually callspkgload::load_all()devtools::document()anddevtools::test()also callpkgload::load_all()
pak::pkg_deps_explain("devtools", "roxygen2")devtools -> roxygen2pak::pkg_deps_explain("devtools", "testthat")devtools -> testthat 35.2 Tracking dependencies
The following packages will help keep your app-package dependencies managed in the DESCRIPTION file and the code below R/:
35.2.1 attachment
attachment was introduced in the golem chapter, but you don’t have to use the golem framework to take advantage of it’s functions. att_amend_desc() will update the package dependencies in the DESCRIPTION file.
attachment::att_amend_desc()Saving attachment parameters to yaml config file
Updating sap documentation
ℹ Loading sap
Writing NAMESPACE
Writing NAMESPACE
ℹ Loading sap
[+] 6 package(s) added: cli, tools, fst, ggplot2movies, glue, waldo.attachment::att_amend_desc() will automatically create a dev/ folder with a YAML configuration file:
dev
└── config_attachment.yaml
1 directory, 1 fileconfig_attachment.yaml contents:
path.n: NAMESPACE
path.d: DESCRIPTION
dir.r: R
dir.v: vignettes
dir.t: tests
extra.suggests: ~
pkg_ignore: ~
document: yes
normalize: yes
inside_rmd: no
must.exist: yes
check_if_suggests_is_installed: yesThis can be deleted, but if you’re going to continue using attachment it’s worth customizing some of the options for your app-package.
35.2.2 sinew
The sinew package also warrants mentioning because it can help ensure you’re namespacing functions from add-on packages, although it’s not automated like attachment::att_amend_desc(). The primary function in sinew is pretty_namespace().
sinew::pretty_namespace(con = "app.R")All Shiny app-packages will inherently depend on shiny, so including more dependencies can make developers justifiably uneasy. In this appendix, we’ll explore the package dependencies using the dependency lookup features from the pak package
35.2.3 desc
The desc package provides functions for creating, reading, writing, and manipulating DESCRIPTION files. You can include additional dependencies to your DESCRIPTION using the desc_set_dep() function.
library(desc)
desc_set_dep("glue", "Imports")
desc_get("Imports")Imports:
bslib,
cli,
glue,
ggplot2,
logger,
rlang,
sass,
shiny,
shinythemes,
stringr,
toolsTry to avoid dependency hell.↩︎
