Hosting pairs of bookdown pdf/html outputs within single directory


I'm creating many dynamic reports using bookdown, and would like the share the output html and pdf files via github.

This is trivial for a single document, but I can't figure out how to render many unique rmarkdown files (with bookdown yaml styling) to both pdf and html while hosting the output within a single directory. The goal is to have documents be accessible using simple urls, such as The pdfs could then be downloaded directly using the default download button.

Here's an example directory structure:


Document yaml is the following:

title: Book 1
author: ''
always_allow_html: yes
bibliography: ./docs/book_bibliography.bib
link-citations: yes
site: bookdown::bookdown_site
biblio-style: apalike
github-repo: my_repo

And here's the _output.yml file:

  css: style.css
  split_by: none
      before: |
        <li><a href="./">A Minimal Book Example</a></li>
      after: |
        <li><a href="" target="blank">Published with bookdown</a></li>
    download: ["pdf"]
    in_header: preamble.tex
  latex_engine: xelatex
  citation_package: natbib
  keep_tex: yes

The index.html file is used to make the gh pages site accessible.

When I run bookdown::render_book("book1.rmd"), all of the files are merged together and duplicate label errors appear. Anyone have any ideas?




I figured out how to do this. The first step was to write specific book.rmd files (e.g. book1.rmd) into a temporary directory along with an _output.yml file. bookdown::render_book() expects the book.rmd file to be in the working directory, so my workflow involved a setwd() statement.

input_file <- "book1.rmd"
#Extract Rmd from project directory
  prev_wd <- here::here()
  rmd <- readr::read_lines(file.path(prev_wd,paste0("docs/",input_file)))
  output <- readr::read_lines(file.path(prev_wd,"docs/_output.yml"))
  #Create a temporary directory to build the book
  wd <- tempdir()
  #bookdown::render_book() requires that your input_file is in the wd
  #NOTE: Bookdown will try to knit all Rmds into one (and break) if you try to knit 
  #directly from /docs

You need to make sure the temporary directory is empty prior to dropping in a new .Rmd or else bookdown::render_book() will try to merge the individual files into a single (breaking) .Rmd file.


Next I removed the extension from the filename so I could paste it into a _bookdown.yml file created inside the temporary directory. This file should be written each time a new .Rmd is rendered.

  #Pull out name of file without extension
  stock <- stringr::str_remove(input_file, "\\.rmd|\\.Rmd")
  #Creates yml file in temp directory. Important for getting download button
  temp_book_yml <- paste0('book_filename: "',paste0(stock),'_.rmd"\ndelete_merged_file: true')

I then wrote the .Rmd file of interest and both .yml files (_output + _bookdown) to the temporary directory. Once you've made it this far, you can call bookdown::render_book(). Note the I've re-routed the rendered bookdown files to my /docs directory. This is the directory that will host the files as github pages. All html and pdf files are written out to this directory.

  #Write critical files for creating book with downloadable pdfs
  readr::write_lines(temp_book_yml, file.path(wd, "_bookdown.yml"))
  write(rmd, file.path(wd,input_file))
  write(output, file.path(wd,"_output.yml"))
  bookdown::render_book(input = input_file,
                        output_format = "all",
                        output_dir = file.path(prev_wd,"docs"))

My goal is to have simple URLs that can be accessed from the github repo; however, bookdown::render_book() seems to want input files to have different names from output files (e.g. index.rmd vs. _main.rmd), and will break otherwise. To avert this, I added an underscore to the input filename above and removed it below.

  #Simplifies filenames by removing extra underscores. These underscores are necessary to build
  #the pdf
  file.rename(from = file.path(prev_wd,"docs",paste0(stock,"_.pdf")),
              to = file.path(prev_wd,"docs",paste0(stock,".pdf")))
  file.rename(from = file.path(prev_wd,"docs",paste0(stock,"_.html")),
              to = file.path(prev_wd,"docs",paste0(stock,".html")))

The same thing needs to happen within the output html document, or else you'll be linking to a pdf that doesn't exist

  #Read in html and alter pdf filename for downloading 
  html <- readr::read_lines(file.path(prev_wd, "docs",paste0(stock,".html")))
  html <- gsub(paste0(stock,'_\\.pdf'),
  html <- readr::write_lines(html, file.path(prev_wd, "docs",paste0(stock,".html")))
  #Get back to the original directory
  message(paste(input_file, "rendered to"), prev_wd)

good luck

1 Like

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