Documenting blog posts with renv

One solution to the ‘ack I can’t re-knit my post’ problem
R
blogging
reproducibility
Author
Affiliation
Published

January 11, 2024

Modified

April 18, 2024

TL;DR

I show how to use the renv::use() function to document the R packages used to write a blogpost.

Help, I’ve fallen and I can’t re-knit my post!

One perennial issue with blogging about R1 is that the blogger may find themselves unable to run the code in a particular post after some time has passed due to package updates that break the code. I call this the “I can’t re-knit my post” problem.

There have been various solutions proposed to this vexing problem, including:

  1. Freezing post computations using Quarto
  2. Writing the post as a static Markdown file
  3. Using renv to maintain one R package library per post

I think Approach 1 (freezing the post) is the most straightforward solution to prevent unintended knit failures, but that does not document the packages used, so it does not help with actually re-running the code later.

I tried a variant of Approach 3 (one renv library per post) previously, but found that it was easy to get confused between different renv environments, and it ended up being more trouble than it was worth.

Using use()

Here, I suggest a simple solution based on the use() function from the renv package, as suggested by that package’s author, @kevinushey. I take the liberty of copying some of the use() documentation here (but I recommend you read the whole thing anyways)2.

renv::use() takes a list of packages and their versions, then:

  • Automatically downloads the requested packages
  • Installs the requested packages (plus their recursive package dependencies) to a temporary library path
  • Activates that library path, so that it’s used subsequently in the script

Basically, instead of maintaining a per-project package library, it re-creates the library for a single script3.

Workflow

First, some setup: if you use renv for your overall website, I recommend telling renv to ignore any scripts in the folder where you store your blog posts, since those will get documented on a per-post basis. For example, if your blog post folder is called posts, add posts to the .renvignore file in the root of your project:

posts

This allows us to have multiple, independent renv.lock files within a single website project without complete chaos.

The rest of the workflow goes like this:

  1. Create blog post, for example, ./posts/2024-01-11_my_post/index.qmd.
  2. Open that post folder in its own instance of VScode or RStudio (so that your working directory is ./posts/2024-01-11_my_post/).
  3. Write post, including code chunks.
  4. Run renv::snapshot(). This will write ./posts/2024-01-11_my_post/renv.lock, but will not modify .Rprofile or create a project library.
  5. Include the line renv::use(lockfile = "renv.lock") in the setup chunk of your post (or a chunk at the very top with #| include: false).
  6. Go back to your main website project and run quarto render or quarto preview to knit the post. Your post will use the package versions stored in the lockfile for that post.
  7. If you need to update the post, repeat steps 2–4, and render again.

Example

This post hasn’t used any code yet, so here is some by way of example.

library(minimal) # my package for testing, which you probably don't have installed
library(digest)

digest(pi)
[1] "6f6167522f32e131f999273c788e4930"

I have gone through the workflow steps above and added the call to renv::use(). Please have a look at the source code of this blog post to see how this works.

Conclusion

I like this approach because we don’t actually create multiple renv projects, so we can avoid headaches related to project-switching (though you still need to use different working directories).

One downside is that given enough time, it may no longer be possible to install the R packages at their specified versions again. However, perhaps this isn’t such a problem after all: it means whoever is trying to run your code most likely also cannot install the packages, so your post needs to be updated!

Another plus is that we can include an appendix at the end of each post linking to the renv.lock file so any interested reader can see what package versions were used.

Finally, this should be used in conjunction with the freeze functionality of Quarto to control when each post gets rendered.

Happy blogging!

Reproducibility

Footnotes

  1. Technically this applies to blogging about anything that includes running code, but this is a blog about R so that’s what you get↩︎

  2. I also couldn’t help but borrow the vignette title. Thanks @kevinushey!↩︎

  3. You might think this means it would take a terribly long time to start up the session each time you work on the script, but thanks to renv’s caching mechanism, it actually is quite fast after the first time↩︎

Reuse

Citation

BibTeX citation:
@online{nitta2024,
  author = {Nitta, Joel},
  title = {Documenting Blog Posts with Renv},
  date = {2024-01-11},
  url = {2024-01-11_using_renv_with_blog},
  langid = {en}
}
For attribution, please cite this work as:
Nitta, Joel. 2024. “Documenting Blog Posts with Renv.” January 11, 2024. 2024-01-11_using_renv_with_blog.