Using Rmarkdown with Eleventy

I write a lot of R in my life. I’m also a web developer that does most of my writing on this blog in markdown. Up until now these two worlds have been separate. I know and use Rmarkdown at work to write reports but, it always has seemed like a pain to get Rmarkdown to work on this site which is generated using 11ty (Eleventy). Up until now, to get my R work on this site, I have been writing R in another document and manually copying over code and outputs to markdown files. Given how inefficient that process is, I figured it was time to figure out how to write Rmarkdown and render it more seamlessly with this site.

To be clear, this isn’t some automated system to get Rmarkdown to build with Eleventy. What it is, is a system to write Rmarkdown, then render that document to a markdown file using R so that Eleventy, or another static site generator, can build it into the site. This also isn’t a process for folks who just want to write Rmarkdown and nothing else. For those folks I’d recommend something like Blogdown or the new Quarto. This is kind of a unique case because I post about things other than R on my blog so I like the flexibility of a non R centric system.

As proof of concept, this page is a Rmarkdown document that I’m rendering to a md document and converting to html with Eleventy.

Eleventy Setup & Configuration

First, you need to put your Rmarkdown file in a folder, that resides with the rest of your posts (mine is just named blog/). The folder should be named like a post typically would be with the post slug. For example, I put this post in a folder named 2023-02-03-test-rmd/ (see the url). Within that folder create an Rmarkdown file and name it index.Rmd. Now after you write your post, you can run rmarkdown::render("2023-02-03-test-rmd/index.Rmd") and a index.md file will be rendered in your slug named folder. Additionally, a folder of images named index_files/ will be created with all of your assets that Rmarkdown generates, which is typically just images of plots. The image paths that are created during the render in the md file should work without any Eleventy changes (after completing the next step). I’m not sure about other static site generators, but I would imagine this would work in most.

Next, we need to make some Eleventy config (.eleventy.js for most) changes, so that images generated by Rmarkdown will be added to the _site folder in the correct location. Rmarkdown render generates all documents in the current folder, including the images. The way I have my 11ty site setup currently is that I put all images in a assets folder that is outside the posts folder and I add a pass through copy to the site folder of just that assets folder. No other images are copied to the site folder. If the goal is to make this as easy as possible we need to add a line to our configuration that will copy all images to our _site folder from the blog (or whatever your posts folder is), keeping their file location. To do this you can add a addPassthroughCopy() in your .eleventy.js configuration file that will copy all images within a specific folder.

module.exports = function(eleventyConfig){
eleventyConfig.addPassthroughCopy("blog/r/**/*.png")
}

I limited to the copy to my blog/r/ folder because that is where Rmarkdown files will be, and I don’t want to copy over my assets/ folder twice which would return an error. That’s it. That is all the Eleventy configuration you need to do. Now let’s move on the Rmarkdown file.

Rmarkdown front matter

The front matter in your Rmardown post should be whatever it is for a typical post and additional an output: section for Rmarkdown. Once your Rmarkdown is rendered to md Eleventy will ignore your output: tag. My front matter for this post looks like this:

---
layout: post
title: 'Using Rmarkdown with Eleventy'
author: 'Michael Schmidt'
date: '2023-02-03'
tags: ["Test Tag"]
# Above this is Eleventy. Below this is Rmarkdown
output:
md_document:
variant: commonmark
preserve_yaml: TRUE
df_print: tibble
---

The output section tells Rmarkdown that this is a markdown document with md_document, that is rendered using commonmark syntax, preserving the yaml (otherwise it is removed), and the df_print: tibble is optional to output tables in truncated fashion.

The last thing I needed to do was add a chunk option for my Rmarkdown chunks that would wrap the chunk outputs in code blocks. If you don’t do this they are printed as plain text. You can do this like so:

knitr::opts_chunk$set(
class.output="r"
)

After that you should be able to write Rmarkdown in you Eleventy site. When you render the Rmarkdown, it should create a markdown document that can be ingested by Eleventy to make static html.

As proof, below is just Rmarkdown rendered with `rmarkdown::render(“path/to/index.Rmd”)

library(palmerpenguins)
library(tidyverse)
penguins
## # A tibble: 344 × 8
## species island bill_length_mm bill_depth_mm flipper_length_mm body_mass_g sex year
## <fct> <fct> <dbl> <dbl> <int> <int> <fct> <int>
## 1 Adelie Torgersen 39.1 18.7 181 3750 male 2007
## 2 Adelie Torgersen 39.5 17.4 186 3800 female 2007
## 3 Adelie Torgersen 40.3 18 195 3250 female 2007
## 4 Adelie Torgersen NA NA NA NA <NA> 2007
## 5 Adelie Torgersen 36.7 19.3 193 3450 female 2007
## 6 Adelie Torgersen 39.3 20.6 190 3650 male 2007
## 7 Adelie Torgersen 38.9 17.8 181 3625 female 2007
## 8 Adelie Torgersen 39.2 19.6 195 4675 male 2007
## 9 Adelie Torgersen 34.1 18.1 193 3475 <NA> 2007
## 10 Adelie Torgersen 42 20.2 190 4250 <NA> 2007
## # … with 334 more rows

This is some text.

penguins%>%
ggplot(aes(island, bill_length_mm))+
geom_boxplot()+
labs(title="Made this in Rmarkdown")+
geom_jitter(width=0.1, alpha=0.5, size=2)+
theme_minimal()