4 minute read

I am working on an outline for a textbook for a fullstack programming course. I want to break my outline into lessons and generate a nice HTML view from the markdown files that will become the basis for an interactive textbook. Bookdown is the tool, documentation can be found here. Here is how I set it up and got started.

Installing R with VS Code

Bookdown using the R programming langauge and markdown documents. So the first step is getting R running with the necessary packages. And I want it integrated in VSCode.

  1. Install R: https://cloud.r-project.org/ (make sure to check “Save version number in registry”)
  2. Install VSCode R editor support: https://marketplace.visualstudio.com/items?itemName=REditorSupport.r
  3. In R install languageserver: https://github.com/REditorSupport/languageserver
    • open RGui on Windows
    • run install.packages("languageserver")
    • also install rmarkdown with: install.packages("rmarkdown")
  4. Make sure R is on the system PATH, for me that was C:\Program Files\R\R-4.2.2\bin
  5. Close and re-open VS Code if you cannot access R interactive shell from the command-line. There should also be a new terminal option “R Terminal” that opens an interactive shell.
    • can double check the packages installed with install.packages("languageserver") at the R Terminal, this shouldn’t do anything.

Once that was setup, I made a test R script test.R:

# My first program in R Programming
myString <- "Hello, World!"

print (myString)

And ran R test.R at the terminal. It worked. So R is up and running!

First Steps with Bookdown

To install bookdown for R, I just need to run (at the R terminal):

install.packages("bookdown")

Minimal Example

Bookdown is built on rmarkdown. A demo for staring a project can be found here. However, I used the documentation minimal example here.

render_book()

I downloaded index.Rmd, then in the R terminal I ran:

bookdown::render_book('index.Rmd', 'all')

This generated a folder _book/ with a static HTML version of the content. This is the built book, and all arguments can be found in the documentation:

bookdown::render_book(input = ".", output_format = NULL, ..., clean = TRUE,
  envir = parent.frame(), clean_envir = !interactive(),
  output_dir = NULL, new_session = NA, preview = FALSE,
  config_file = "_bookdown.yml")

By leaving output_format empty, the book is rendered as the first output format specified in the YAML metadata of the first .Rmd file or a separate YAML file _output.yml (see here). When you set preview = TRUE, only the Rmd files specified in the input argument are rendered, which can be convenient when previewing a certain chapter, since you do not recompile the whole book, but when publishing a book, this argument should certainly be set to FALSE.

clean_book()

You can delete the built book with:

bookdown::clean_book(TRUE)

But be careful that things are version controlled with git so you don’t lose anything.

Viewing the Book

To view the static site in the _book/ directory. I installed the VSCode extension Live Preview. All I need to do is select one of the .html files, click the preview button in the code editor, and there it is. I can also just navigate to http://127.0.0.1:3000/_book/ in my browser. It even updates as I add chapters and redo the render_book() command.

If the book is getting long and the pandoc conversion step of render_book() is taking awhile, then an individual chapter can be re-rendered using:

bookdown::preview_chapter("index.md")

Practical Example

Chapter Order

My default, bookdown will render files in the order of their name (e.g., 01-something.Rmd, 02-something-else.Rmd, etc.). I don’t want to provide an order in filenames, because I may want to remix and rematch. So I just need to override this behavior by making a _bookdown.yml file in the book directory and providing a file list:

rmd_files: ["02.Rmd", "01.Rmd", "index.Rmd"]

Filenames that start with an _ underscore are skipped. The file index.Rmd will always be treated as the first even if re-ordered in the list.

I can create an appendix with # (APPENDIX) Appendix {-} at the top of a file, the {-} characters tell markdown not to give this a section number

Front Matter

For now, I want the book to render as a gitbook, which provides nice links and a navigation pane. So the front-matter of the index file should look like so:

# index.Rmd

---
title: "A Book"
author: "Ben"
site: bookdown::bookdown_site 
documentclass: book
output:
  bookdown::gitbook: default
  #bookdown::pdf_book: default
---

The site: bookdown::bookdown_site pair calls bookdown::render_book(), and the output is specified as bookdown::gitbook. The outputs can also be specified in a separate _output.yml document as shown here, which is maybe better from an organizational standpoint. So now if I just run:

bookdown::render_book()

then everything works. Also because I have the _bookdown.yml in my root directory, which render_book() looks for by default, my chapter order and other variables are set correctly.

Markdown

But what if I don’t care about .Rmd files, because I don’t plan to have integrated R code? Well, I can just use .md markdown files! If I changed all the filenames and replace the _bookdown.yml file list with:

# _bookdown.yml

rmd_files: ["02.md", "01.md", "index.md"]

And when I bookdown::render_book() and visit http://127.0.0.1:3000/_book/, then everything looks good!

For the # heading in each file, if I add {-}, then it will skip section numbering.

Publishing on GitHub

I want to create github repo for the project, and I would also like to view the rendered site as updates are made. There are instructions here.

Other useful stuff