Hosting pairs of bookdown pdf/html outputs within single directory

Hi,

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 xyz.github.io/repo/book1. The pdfs could then be downloaded directly using the default download button.

Here's an example directory structure:

/docs
---book1.rmd
---book2.rmd
---book3.rmd
---index.rmd
---index.html
---_output.yml
---book_bibliography.bib

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:

bookdown::gitbook:
  css: style.css
  split_by: none
  config:
    toc:
      before: |
        <li><a href="./">A Minimal Book Example</a></li>
      after: |
        <li><a href="https://github.com/rstudio/bookdown" target="blank">Published with bookdown</a></li>
    download: ["pdf"]
bookdown::pdf_book:
  includes:
    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?

Thanks

Sean

Update:

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
  setwd(wd)

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.
Hence:

  file.remove(file.path(list.files(wd))) 

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'),
               paste0(stock,'\\.pdf'),
               html)
  html <- readr::write_lines(html, file.path(prev_wd, "docs",paste0(stock,".html")))
  
  #Get back to the original directory
  setwd(prev_wd)
  
  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.