learnr tutorials: best practice for dependencies?

I have developed a series of learnr tutorials to accompany two of my textbooks. In both cases I have wrapped them in packages (adventr and discovr) rather than deploying on a shiny server (because of large student numbers and the desire to make them available for others without escalating my server costs). I have started to wonder about the best way to deal with dependencies for these packages. The tutorials cover a lot of ground, so across all of the tutorials within a package they use 20-30+ external packages. The tutorials need these external packages to run. So, how best to deal with that?

Currently I list external packages as Imports in the description file of the package and advise people to install using dependenices = TRUE. That way, all dependencies should be installed along with my package and all tutorials within my package will run. But this means users potentially get 30+ packages installed in one hit. I also get warnings when I build the package because of the large number of dependencies. However, if the external packages are not installed on the user's machine, the userswill get errors when they try to run the tutorials.

However, I gather that in the latest release of learnr/RStudio tutorials are compiled directly from the markdown (i.e. I don't need to pre-render the htmls and distribute them), which made me wonder whether a better approach would be to code a require for each package within a particular tutorial ... so, in the setup for each tutorial there is code that checks if the required packages exist and if they don't they are installed. That way, I could have minimal dependencies for the package overall, users won't have to install all dependencies in one hit - they'll get installed on a per-tutorial basis when they run it. Would this approach work?

Any advice/recommendations would be appreciated on best practice for package dependencies for learnr tutorials when wrapped in a package?
Thanks

andy

2 Likes

For the purposes of CRAN, none of your tutorial dependencies need to be included in the DESCRIPTION file. Only dependencies used within the ./R folder are required in the DESCRIPTION file. CRAN treats the inst folder as a tag-along folder that is not inspected.

Within learnr::run_tutorial(name, pkg), learnr will check the packages required to run the tutorial. To view what information learnr believes about a package's tutorials, run tibble::as_tibble(learnr::available_tutorials(pkg)).

If a tutorial dependency is not found, a dialog will come up in the console or Rstudio IDE, asking to install the missing packages.

Note: Similar to packages in the Suggests field, versions can not be enforced.

Note: If you have a Remotes package that you'd like installed, I would add it to the Imports DESCRIPTION field so that is it guaranteed to be installed using the Remotes value


I don't need to pre-render the htmls and distribute them

Correct. Do not include any html or cache file information in the submitted package. Most likely, the user will have to re-render the tutorial as their dependencies will not exactly match your dependencies.


tl;dr Remove all typical, tutorial-only dependencies from the DESCRIPTION file for CRAN purposes. Missing tutorial dependencies will be installed when the tutorial is attempted to run.

(Do not include precompiled tutorial files in the package when submitting to CRAN. Users will most likely re-render the tutorial anyways.)


great hex logo!

1 Like

Thanks @barret that's really helpful.

If a tutorial dependency is not found, a dialog will come up in the console or Rstudio IDE, asking to install the missing packages.

I wasn't aware of this!
Thanks again - much appreciated.
andy

1 Like

@andy_field Glad it helped! :smile::smile:

quick follow up - are shiny, rmarkdown, knitr, and learnr installed by default with RStudio - i.e. can I assume users who have RStudio 1.3 installed automatically have shiny and learnr installed and so I don't need to load these within a learnr r tutorial (because they'll be loaded when the user runs the tutorial)

RStudio does not install any regular R packages without user permission.

To make sure learnr/shiny/rmarkdown/knitr are all installed, maybe add learnr as a single Imports dependency? (It will also help me with reverse dependency checking / tutorial discovery.). This will also help users who work inside a console.

R CMD check might complain that you are not directly using learnr. I get around this by adding something like ignore <- learnr::tutorial in any of your ./R files.


Reading your post a second time, you should only need to library(PKG) packages that are directly being used within your Rmd file. Ex: learnr loads shiny, knitr, rmarkdown internally. This does not make shiny, knitr, or rmarkdown available to the user until you've called library(rmarkdown).


I hope this helps! There is more than one way to interpret your question due to term overloading. :slightly_frowning_face:

Thanks. Sorry for the term overloading and general ambiuguity! I think you've answered the question very clearly, but as a specific example, if I have a shiny app within a tutorial (e.g., I've got a code chunk with context = "server" in the header) would I need library(shiny) within my setup code chunk at the start of the tutorial for that app to work? It sounds like the answer is 'no' (because shiny is loaded internally). However, if I were to include a coding exercise in which the user is expected to use a shiny function, then I would need to load shiny so that it is available to the user.

if I have a shiny app within a tutorial (e.g., I've got a code chunk with context = "server" in the header) would I need library(shiny) within my setup code chunk at the start of the tutorial for that app to work? It sounds like the answer is 'no' (because shiny is loaded internally).

Correct. I believe shiny is already available during context = "server" due to the yaml header of runtime: shiny_prerendered.

(It does not hurt to have extra library(shiny) calls if it helps you remember what is available. I do this a lot!)

However, if I were to include a coding exercise in which the user is expected to use a shiny function, then I would need to load shiny so that it is available to the user.

Correct. :smiley:

If you'd like a package available only for a particular exercise, I would do it in an exercise setup chunk. Ex: ex1-setup

If you'd like a package available for context = "render", context = "server", and exercises, place it in the chunk named setup.

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.