Correct way to batch render Rmarkdown files for use with Hugo

Viewed 905

I am trying to render a bunch of .html pages from .Rmd by using rmarkdown::render() on a template .Rmd and pass it some variable through a loop.

for (i in some_vector){
  rmarkdown::render(my_template.Rmd,
                    output_format = "html_document",
                    output_file = ... ,
                    output_dir = ... )
}

The template is set up to expect the variable and renders fine. However, other .Rmd pages in other parts of the site no longer render properly if I generate my .html files then run blogdown::serve_site()

The .html files rendered by blogdown::serve_site() seem to have incorrect headers and missing html parts when rendered automatically by blogdown. The generated html page still retains the yaml header components at the top of the file.

Eg:

---
title = 
date = 
layout = 
author =
--- 

If I don't batch generate my files, and simply run serve_site() on the existing site files then I get no issue. My suspicion is that running rmarkdown::render() changes some session parameter, but I have no idea. My aim is to create the necessary pages myself and then have blogdown render the rest upon serve_site().

Does anyone have any idea what the issue is?

2 Answers

So, I worked out how to generate the correct file outputs. My issue was borne of an ignorance of how blogdown works.

Essentially, when serving site, blogdown does the following:

  1. Locate .Rmd files
  2. Covert to .html files formatted for HUGO
  3. HUGO serves the final .html file to its location in /public

What I was doing was skipping these steps and creating a final rendered .html file through rmarkdown::render() thus creating files that were incompatible with the theming actions carried out by HUGO before serving the final .html.

Instead of manually rendering .Rmd files through a loop and passing it variables, I edit lines of the template and write the output as individual .Rmd files:

file.src <- file("~/R/sample_proforma_2.Rmd", 
                 open = "r")
file.lines <- readLines(file.src)
rmd.list <- list()
for(i in c("sample_117" ,"sample_118", "sample_119", "sample_121")){
  tmp.lines <- file.lines
  tmp.lines[4] <- gsub("empty\\+title", gsub("_", " ", toupper(i)), tmp.lines[4])
  tmp.lines[6] <- gsub("empty\\+title", gsub("_", " ", toupper(i)), tmp.lines[6])
  tmp.lines[9] <- gsub("empty\\+circos", toupper(i), tmp.lines[9])
  tmp.lines[15] <- gsub("empty\\+maf", i, tmp.lines[15])
  tmp.lines[21] <- gsub("empty\\+tag", i, c("- CIRCOS\n- MAF"))
  rmd.list[[i]] <- tmp.lines
}

for (i in names(rmd.list)){
  write.table(rmd.list[[i]],
              paste0("~/content/sample/",i,".Rmd"),
              sep = "",
              quote = FALSE,
              col.names = FALSE,
              row.names = FALSE)
}

I have struggled hours with the same problem. I want to generate thousands of separate pages (with R, Blogdown and Hugo) out of ~10 templates and script everything.

Here is what seems to work:

  1. Have your custom R/build.R to generate the markdown (.md) pages in a loop.
  2. Have Hugo to convert the markdown (.md) file to HTML
  3. Use knitr::knit, not rmarkdown:render, to process the Rmarkdown templates (.Rmd) to markdown (.md)
  4. The only way to get images into right places with the right relative URLs using knit() is to a) set output = 'dest/dir/file_name.md', b) use fig.path='figure' (or whatever you like) AND c) move the fig.path directory under the dest/dir/figure after every single knit().

Otherwise knit() either puts the images under ROOT/figure or creates a relative image links into the .md file like dest/dir/figure/plot.png for a page that is already under dest/dir/.

My R/build.R.

updates <- c( '6.3', '6.4', '6.5');
library('knitr')

dir.create(file.path('content/', 'update'), showWarnings = FALSE);

for (update in updates) {
  dir_name <- paste0('content/update/', update);
  dir.create(file.path(dir_name), showWarnings = FALSE);
  knit(input = 'R/update.rmd', output = paste0(dir_name, '/_index.md'));
  ## THIS IS REQUIRED AFTER EVERY knit()!!! 
  ## otherwise the image links go wrong and/or the next knit() may overwrite the previous plots

  file.rename('figure', paste0(dir_name, '/figure'));    
}

and R/update.rmd:

---
title: Version `r update`
date: `r Sys.Date()`
author: Jylpah
output: md_document
---
This is a test. Version is `r update`. 

```{r, plot, echo=FALSE, fig.path='figure/'}
A <- sample(10,50,replace = TRUE);
hist(A);
```

## Something else

Another plot

```{r, plot_another, echo=FALSE, fig.path='figure/'}
B <- sample(10,50,replace = TRUE);
hist(B);
```

I hope the above is somehow understandable and helps you and others.

Related