Setting up a blog using blogdown
For this blog you are reading now, I decided to go with Jekyll and to use .md
files. This was very easy as I only had to fork an already organized repo from barryclark/jekyll-now
that had a theme that I liked. However, at work I wanted to set up a blog using RStudio’s blogdown
which uses Hugo, even though the upfront setup time takes longer. I was particularly interested in this methodology because it allowed me to simply convert my R Notebooks into blog posts, without having to save (and probably re-save plots) and refer to the location of the png files.
The blogdown package utilizes Hugo for blog generation, as opposed to Jekyll. However, the creater of blogdown claims that migrating a blog from Jekyll to Hugo is as simple as finding a new theme and updating the YAML metadata. Perhaps I will switch this blog over to Hugo if I decide I really want to be able to reproduce plots with ease.
blogdown
Because there are many sources devoted to describing how to use blogdown to generate a website, I will not go into a level of detail that would allow the reader of this blog post to generate their own blog. However, I will attempt to direct to the reader to the resources I found helpful and will fill in the gaps where I felt the resources fell short.
Setup
My first attempt to set up a blog utilized this blog post. This blogger went the first of two potential avenues to integrate Hugo with Github Pages:
-
Have one repository with a default branch named
sources
and amaster
branch that only contains the content of thepublic/
folder, the only files Hugo will allow to generate the blog. -
Have two repositories, each with only a master branch. The first I have called
blog_setup
which contains the R project and all of the files generated by blogdown. The second is calledblog
(for the sake of a nice url), which contains only the contents of thepublic/
folder from theblog_setup
repository.
Single repository method
While Amber’s blog was enormously helpful, I felt it was the more difficult approach for many reasons:
-
Setting up both the
setup.sh
anddeploy.sh
scripts made the process of setting up Github and deploying the site more of a black box than the two-repository alternative. If running thesetup.sh
file failed, I was left without a master branch and found myself having to start over. -
It made it harder to revert to old versions or to branch on Github because the
master
/sources
branching structure could not be altered.
Two-repository method
The next blog post I read detailed the two-repository method, which I found much more graceful to work with. The following is a summary of the steps you would need to take to build a blog in the same fashion:
-
Set up a
blog_setup
and ablog
repository on Github. Clone the repos to a directory on your machine. Make sure to set up Github Pages on yourblog
repository through theSettings
tab. -
Create an R project within the
blog_setup
directory of your local machine. Open it, install the development version of blogdown usingdevtools::install_github('rstudio/blogdown')
, and load the library. Then use thenew_site()
function to populate yourblog_setup
folder with the necessary files and folders. -
Select a Hugo theme. This can be tricky, because some themes don’t play so well with blogdown. I initially liked the “Bootstrap Premium” theme, but discovered it became very difficult to work with because it had functionality for multiple languages. I ended up settling on “Hugo Bootswatch” because it has a simple interface and very basic
config.toml
file. Install your theme with the Github link as follows:install_theme("nilproductions/hugo-bootswatch", theme_example = T, update_config = T)
. This will update your site files to adopt your chosen theme. Note: I didn’t have much success “switching” between themes. It seems blogdown can handle it, but theconfig.toml
file adapts components of both themes which didn’t help when I had the overly complexconfig.toml
from the Bootstrap Premium theme. - Edit your
config.toml
file.- Change the baseurl to the site you are publishing to. For me at work, this was
"https://github.comverge.com/pages/jmaddalena/blog/"
- Change the publishDir to your
blog
repo. Using the “~/” shortcut does not work properly!!
- Change the baseurl to the site you are publishing to. For me at work, this was
-
To build the site and send the contents of your
public/
folder to yourblog
directory, runbuild_site()
within your R project. You can also runserve_site()
to preview the site within R. Ifbuild_site()
is ran first,serve_site()
will be fairly quick to show the results of the build. However ifserve_site()
is ran first,build_site()
still has to compile everything on its own. - To publish your built website, you will need to push all of your new content to GitHub. Remember, you will have to do so for both repositories (though
blog
is the only one that is required for the website to work). Once you have pushed to GitHub, you should be able to view your new blog at your specified baseurl.
Content
Once I got my blog up and running, I needed to alter the content to consist of my project documentation R notebooks, as well as Markdown files such as this blog setup post. I also needed to get under the hood a bit to adjust the interface.
Adding new posts
I was greatly disappointed when I realized blogdown does not support R notebooks. This meant I could not use interactive plots, code folding, and many other nice features that .Rmd
files do not support. However, I was able to convert my notebooks to .Rmd
files (which do knit to .html
) and hide the code and other unwanted output with the following global options setup:
```{r global_options, include=FALSE}
knitr::opts_chunk$set(echo=FALSE, warning=FALSE, message=FALSE)
```
The blogdown package has a new_post()
function that will automatically put new content, such as an R markdown file, in the content/post
folder of your blog_setup
directory. This can be handy, but you can also copy an .Rmd
file from elsewhere on your computer and put it into the content/post
folder. In doing so, you may have to change the front matter (YAML) to look like the following:
---
title: "Long-Term System Load Forecast Improvements"
author: "Julia Maddalena"
date: 2017-07-23T21:13:14-05:00
categories: ["R"]
tags: ["Belford", "Long-term", "Weather", "Epoch", "GBM", "Holidays"]
---
Including images
To include images that are not generated with code, place the image (preferably as .png
) in the blog_setup/static/img/
folder. Images for all blog posts can live in this directory.
Customization
CSS
I had some issues with the default css of the Bootswatch theme when it came to tables. In converting from notebooks to .Rmd
, I had to wrap all my table-generating code in the kable()
function, the knitr package’s way to generate html tables. When I knit the function within R, the tables look nice and default to taking up the entire div width. However, when I built or served the site, the tables looked very scrunched together with no horizontal padding within the columns. I ultimately realized this was one of the seven .css
files in blog_setup/themes/hugo-bootswatch/static/css
that was causing the padding in my tables to disappear.
Rather than attempting to find the problem across seven files, it is much easier to create a custom .css
file whose contents will override any contradicting code in the other .css
files. This can be done by creating a custom.css
file and placing it with the other .css
files in themes/hugo-bootswatch/static/css
. Then, to tell Hugo to use this file and to prioritize it over the other style sheets, open themes/hugo-bootswatch/layouts/partials/header.html
and add <link rel="stylesheet" href="/css/custom.css">
below the other stylesheet links.
Reference: Custom CSS
Using LaTeX Typesetting
If your post includes math formulas using LaTeX syntax, e.g. $\frac{-b + \sqrt{b^2 - 4ac}}{2a}$ , you will need to load the mathjax javascript library by placing a snippet of text in your headers partial (e.g. blog_setup/themes/hugo-bootswatch/layouts/partials/header.html
) as described here.
Custom Summary
By default, Hugo uses the first 70 characters of a post to show as the summary of the content of each blog post. This rarely creates a good summary, as it combines the first 70 characters whether or not they are headers, table of contents, or other undesired text that begins the post. This post claims to be the solution to setting user-defined summary breaks in the content, but their solution only worked for the .Md
files, not for the .Rmd
files. To allow for a custom summary in my .Rmd
files, I had to add a summary:
taxonomy to the YAML of each post that I wanted to override Hugo’s default summary. In addition, to tell Hugo to use this summary if present in a post, I had to edit the blog_setup/themes/hugo-bootswatch/layouts/index.html
file as follows:
Replace <p></p>
with <p> </p>
as described as a cumbersome solution here.
Caching
If no caching structure is in place for .Rmd files, the build_site()
function will start to take longer and longer as the number of posts on the blog accumulate. I don’t recommmend setting cache = TRUE
in the global options of your .Rmd file that has not been finalized, as any changes to the source code will not be recognized as long as the code chunk itself remains the same.
If you have set a document to cache but have made any changes to the document or the source code, I have found that setting cache = FALSE
in just that document and re-building the site will update the changes. At this point, you can set cache = TRUE
again, and build twice (to save and read the caches) to maintain cached changes.*
*Caveat: this has not produced consistent results for me. Caching seems to be very risky until the post is finalized and you’ve moved on to new things.
Conclusion
While the process of setting up a blog using blogdown, Hugo, and Github Pages was more difficult than I first anticipated, I am pleased to have gotten a blog up and running that behaves as desired. With .Rmd
allowed as content, I can now reproduce blog posts with ease, without having to resave plot images. I can also make writing the blog post part of my workflow, testing functions that read and manipulte data, and generate plots or and tables, adding supportive text as I go.