library(minimal) # my package for testing, which you probably don't have installed
library(digest)
digest(pi)
[1] "6f6167522f32e131f999273c788e4930"
January 11, 2024
December 6, 2024
I show how to use the renv::use()
function to document the R packages used to write a blogpost.
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:
renv
to maintain one R package library per postI 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.
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:
Basically, instead of maintaining a per-project package library, it re-creates the library for a single script3.
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:
./posts/2024-01-11_my_post/index.qmd
../posts/2024-01-11_my_post/
).renv::snapshot()
. This will write ./posts/2024-01-11_my_post/renv.lock
, but will not modify .Rprofile
or create a project library.renv::use(lockfile = "renv.lock")
in the setup chunk of your post (or a chunk at the very top with #| include: false
).quarto render
or quarto preview
to knit the post. Your post will use the package versions stored in the lockfile for that post.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.
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!
Technically this applies to blogging about anything that includes running code, but this is a blog about R so that’s what you get↩︎
I also couldn’t help but borrow the vignette title. Thanks @kevinushey!↩︎
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↩︎
@online{2024,
author = {},
title = {Documenting Blog Posts with Renv},
date = {2024-01-11},
url = {2024-01-11_using_renv_with_blog},
langid = {en}
}