Blogdown Tutorial

My experience going through R blogdown install by following Yihui’s instructions at:
https://bookdown.org/yihui/blogdown/

  • the documentation there is superb,
  • but I had only beginner knowledge of HTML, CSS, and HUGO,
  • took me a week to get my site published and start blogging,
  • customizations took the longest, documented in Highlights section, hope you find some of it helpful

Blogdown = static website generator in R, based on Hugo

1.1 installation

install.packages('blogdown')  # install blogdown

blogdown::install_hugo()  # install Hugo
	macOS installs using homebrew
	The latest Hugo version is 0.71.0
	Updated 1 tap (homebrew/core).
	==> New Formulae
	...
	...		
	Bash completion has been installed to:
	  /usr/local/etc/bash_completion.d
	==> Summary
	🍺  /usr/local/Cellar/hugo/0.71.0: 42 files, 74.4MB		

blogdown::update_hugo()
blogdown::hugo_version()  # [1] ‘0.71.0’

1.2 a quick example

(start new Blogdown R project/site)

RStudio GUI way

File > New Project > New Directory > Website using Blogdown > |Create Project|
create new Blogdown project
creates bioinfohippo/
                       .Rproj.user/
                       bioinfohippo.Rproj
                       config.toml
                       content/
                       index.Rmd
                       resources/
                       static/
                       themes/

RStudio Console way

in project directory:
blogdown::new_site(theme = 'gcushen/hugo-academic') 

LiveReload

  • use blogdown::serve_site()
  • website auto-rebuild when any source file modified and saved

/config.toml

  • basic configuration settings

/content/

  • put R Markdown or Markdown source files for posts/ pages
  • can have any directory structure

/public/

  • publishing directory
  • website automatically generated to this directory
  • *.html, *.css, *.js files and images
  • if using github pages instead of Netlify -> upload /public/ to github pages

1.3 RStudio Addins

(GUI for various blogdown functions)

Addins
Serve Site calls blogdown::serve_site()
New Post calls blogdown::new_post()
opens dialog box to enter metadata for blog post
can also generate normal page
scans categories and tags of existing posts
opens markdown file for creating new content
Update Metadata update YAML metadata of currently opened post
edit metadata if you closed it
Insert Image copies image into project directory
adds markdown/HTML code to embed the image

check project = website

Tool > Project Options > Build Tools > Project build tools = Website

! uncheck "Preview site after building"
	  and "Re-knit current preview when supporting files change"

conclusion

if publishing manually on e.g. github pages,

  • do NOT use serve_site(),
  • instead use build_site() before uploading public/ to github

if just previewing before publishing,

  • then use serve_site()

build_site()

  • generating public/ with Blogdown
  • for publishing public/ files manually on e.g. github pages (better to use Netlify - continuous deployment)
RStudio > Build tab > Build Website (calls blogdown::build_site())

every time before publishing website

  • restart R session
  • click Build Website

build_site() vs serve_site()

  • blogdown::serve_site()
    • for previewing your site as you build it
    • builds public/ every time you make change to any file
    • calls blogdown::build_site(local = TRUE)
  • blogdown::build_site()
    • builds public/ once
    • calls blogdown::build_site(local = FALSE))
    ==> rmarkdown::render_site(encoding = 'UTF-8')
    
    Rendering content/post/2015-07-23-r-rmarkdown.Rmd
    Building sites … 
    				   | EN  
    -------------------+-----
      Pages            | 20  
      Paginator pages  |  0  
      Non-page files   |  0  
      Static files     | 12  
      Processed images |  0  
      Aliases          |  0  
      Sitemaps         |  1  
      Cleaned          |  0  
    
    Total in 26 ms
    
    Output created: public/index.html

public/ is default

  • can change it with publishDir = “myNewDirectory” in config.toml

set “relativeurls” = true in config.toml

  • to preview in browser
  • or else website can only be previewed in RStudio viewer
  • (CSS and Javascript links won’t work without relativeurls)

1.4 global options

  • sets some defaults for New Posts (e.g. author, extension)
  • so when you do New Post, some fields auto populate
Option name Default Meaning
servr.daemon interactive() Use a daemonized server?
blogdown.author John Doe The default author of new posts
blogdown.ext .md Default extension of new posts
blogdown.subdir post A subdirectory under content/
blogdown.yaml.empty TRUE Preserve empty fields in YAML?

project specific .Rprofile

file.edit("/Users/minghan/Google Drive/RBlogDown/bioinfohippo/.Rprofile")
	
	options(servr.daemon = 'interactive()',
			blogdown.author = 'Ming Han',
			blogdown.ext = '.Rmd',
			blogdown.subdir = 'post',
			blogdown.yaml.empty = TRUE)

system wide .Rprofile

  • create .Rprofile in home dir (~/)
  • R reads project .Rprofile first, but eventually settles with what’s in system wide ~/.Rprofile

1.5 .Rmd vs .Rmarkdown vs .md

Feature .Rmd .Rmarkdown .md
Run R code yes yes no
Bibliography yes no no
Task list maybe yes yes
MathJax yes maybe maybe
HTML widgets yes no no

.Rmd most complete, but takes a little longer to render compared to .md

rendering/ compilation

  • .md rendered to HTML by Blackfriday (as of HUGO v0.62.0, renders .md with Goldmark)
  • .RMarkdown compiled using rmarkdown and Pandoc
  • blogdown supports LaTex render to HTML, but needs $math$ (backticks)

personal comment:

  • some Hugo themes really don’t play nice with .Rmd (e.g. Academic)
  • getting floating toc to work in Academic theme was a struggle
  • need to learn more about Hugo to come up with custom template (similar to docs but for .Rmd) to fully utilize Academic theme features with .Rmd

setting blogdown rendering options globally

  • instead of setting blogdown rendering options in every .Rmd front matters,
  • can set it globally by
  • creating _output.yml file in project root directory and type:
blogdown::html_page:
  toc: true
  fig_width: 6
  dev: "svg" # device for plots
  • blogdown:html_page inherits from bookdown::html_document2 inherits from rmarkdown::html_document
  • so check ?markdown::html_document for details

personal comments:

  • toc cannot float, can only appear at beginning of document

make blogdown ignore a .Rmd file when compiling

  • rename it to an unknown extension e.g. .Rmdignore

1.6 other Hugo themes

install theme

  • blogdown::install_theme('gcushen/hugo-academic')
  • OR
  • blogdown::new_site(theme = 'gcushen/hugo-academic')
    • this is preferred
    • automatically creates config.toml file in root dir

themes that work well with blogdown

Simple/minimal themes:
XMin https://github.com/yihui/hugo-xmin
Tanka https://github.com/nanxstats/hugo-tanka
simple-a https://github.com/AlexFinn/simple-a
ghostwriter https://github.com/roryg/ghostwriter
Sophisticated themes
hugo-academic https://github.com/gcushen/hugo-academic
hugo-tranquilpeak-theme https://github.com/kakawait/hugo-tranquilpeak-theme
hugo-creative-portfolio-theme https://github.com/kishaningithub/hugo-creative-portfolio-theme
hugo-universal-theme https://github.com/devcows/hugo-universal-theme

personal comments:

  • wish I played around with XMin first, would have been a less steep learning curve
  • but I needed a navbar and side panes for toc
  • minimal themes are good for blogs
  • I eventually settled with hugo-academic, looks clean, has a lot of users so there’s a lot of helps in forums out there
  1. pick a theme

  2. preview and upload website

    • preview site with Addins > Serve Site (never click knit button)
    • upload public/ folder to your github repo, OR
    • easier with Netlify (continuous deployment instead of manually uploading to github after each update)

2.1 Hugo

static sites

  • HTML files
  • same content no matter who visits the page

dynamic sites

  • server side language (e.g. PHP) that sends different content to different users
  • e.g. web forum, user login, server fetches user data from a database
  • renders different content for different users

static site generators

  • Hugo, Jekyll, Hexo

advantage of Hugo

  • easy install
  • fast rendering
  • large community

blogdown = Hugo with Rmarkdown

blogdown default folder structure

	config.toml
	content/
	static/
	themes/
	layouts/

2.2 config file

  • config.toml
  • sets global configuration for entire site

Hugo

  • first searches for config.toml (Tom’s Obvious Minimal Language),
  • then config.yaml (Yet Another Markup Language)
  • Hugo prefers .toml, but can also use .yaml

for blogdown

  • use TOML for config file
  • use YAML for data format for metadata

2.2.1 TOML syntax

argument style
key = value char strings in quotes
boolean in bare lowercase

table in TOML with [ ]

    [social]
    github = "https://github.com/rstudio/blogdown"
    twitter = "https://twitter.com/rstudio"

array of tables with [[ ]]

        [[menu.main]]
		name = "Blog"
		url = "/blog/"
	
	[[menu.main]]
		name = "Categories"
		url = "/categories/"

	[[menu.main]]
		name = "About"
		url = "/about/"

array of tables in TOML

  • Hugo interprets array of tables as MENU
  • if in /config/_default/menu.toml, will generate menu links
  • menu names defined here, location and style of menu specified elsewhere

2.2.2 options

/config.toml

title = "BioinfoHippo"
baseurl = "/" (URL for your site, default set to "/")
copyright = "John Doe © {year}"
relativeurls = true
theme = "hugo-academic"
hasCJKLanguage = false  # Set `true` for Chinese/Japanese/Korean languages.
enableEmoji	= true or false, e.g. 😄 in markdown
etc etc

ignoreFiles

  • list of filename pattern (regex) for Hugo to ignore and not render
  • specify at least these
["\\.ign$", "\\.ipynb$", ".ipynb_checkpoints$", "\\.Rmd$", "\\.Rmarkdown$", "_files$", "_cache$"]

permalinks

  • rules to generate permanent link
[permalinks]
  authors = "/author/:slug/"
  tags = "/tag/:slug/"
  categories = "/category/:slug/"
  publication_types = "/publication-type/:slug/"
  • blogdown recommend using :slug instead of :title
  [permalinks]
posts = "/:year/:month/:day/:title/"
		
[permalinks]
posts = "/:year/:month/:day/:slug/"

slugs:

  • simply an unique character string used to identify a specific post
  • slug does not change even if post title changes
  • post title may change, but want link to post to stay permanent
  • :slug falls back to :title if field name “slug” not set in YAML metadata of the post
  • set a fixed :slug, so link to post is fixed, and can update title
  • e.g. slug = “blogdown-love”
    • old title = “I love blogdown”
    • new title = “why blogdown is the best”
    • doesn’t matter, slug link is still “blogdown-love”

/config/_default/params.toml

theme = "minimal"
font = "my_font_set"
font_size = "M"
highlight = true
math = true
diagram = true
email = "mhan@unb.ca"
date_format = "Jan 2, 2006"
etc etc

not sure where to find these…

  • author (edit: found it in /content/home/about.md)
  • publishDir (can set other than public/)
  • theme (directory name under themes/)
  • uglyURLs

2.3 /content/ dir

  • can have arbitrary directory structure in content/
  • common one is:
	├── _index.md
	├── about.md
	├── vitae.md
	├── post/
	│   ├── 2017-01-01-foo.md
	│   ├── 2017-01-02-bar.md
	│   └── ...
	└── ...

2.3.1 YAML metadata

  • “front matters”
  • each page should start with YAML metadata
	title
	date
	author
	categories
	tags
	etc...

	draft = true (posts not rendered with build_site() or hugo_build(), only renders in preview with Addins > Serve Site)
	publishdate	=	2019, May 5 (specify future publish date, again still renders in preview)
	weight = 100 (if 2 posts have same date, use weight to order them)
	slug = uniqueID	(char string as tail of URL)

2.3.2 body

  • check out markdown or Rmarkdown syntax

2.3.3 shortcode

<blockquote class="twitter-tweet">
  <p lang="en" dir="ltr">Anyone know of an R package for
	interfacing with Alexa Skills?
	<a href="https://twitter.com/thosjleeper">@thosjleeper</a>
	...
  </p>
  &mdash; Jeff Leek (@jtleek)
  <a href="https://twitter.com/jtleek/status/852205086956818432">
	April 12, 2017
  </a>
</blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8">
</script>

becomes

in .md
{\{< tweet 852205086956818432 >\}} backslash only to show code

in .Rmd
blogdown::shortcode('tweet', '852205086956818432')

2.4 themes

2.5 templates

  • theme = templates (in /themes/hugo-academic/layouts/) + web assets (in /themes/hugo-academic/assets/)
  • web assets = CSS, JS files, images, videos
  • assets determine appearance + functionality of website + embedded content

2.5.1 XMin Hugo theme example

  • dig into later

2.5.2 implement more features

  1. google analytics
  1. disqus comments
  1. syntax highlighting via highlight.js
  2. math expressions through MathJax
  3. table of contents
	output:
		blogdown:html_page:
			toc: true
  • if .md, have to modify single.html template, before content
		{{ if .Params.toc }}
		{{ .TableOfContents }}
		{{ end }}
  1. display categories and tags in post
  2. add pagination
  3. add github edit button

2.6 custom layouts

  • if customize a theme, future author updates may conflict with your tweaks
your-website/
		├── config.toml
		├── ...
		├── themes/
		│      └── hugo-xmin/
		│             ├── ...
		│             ├── layouts/
		│             │      ├── ...
		│             │      └── partials
		│             │             ├── foot_custom.html
		│             │             ├── footer.html
		│             │             ├── head_custom.html
		│             │             └── header.html
		│	        └── static/
		│                    ├── style.css
		│		       └── ...
		│
		├── layouts
		│	└── partials
		│		├── foot_custom.html
		│		└── head_custom.html
		└── static/
			├── style.css
			└── ...

customize in 2 ways

1. in config.toml (without touching template files)
2. use layouts/ to override templates in themes/

  • e.g., the file layouts/partials/foot_custom.html, when provided, will override themes/hugo-xmin/layouts/partials/foot_custom.html

2.7 static files

  • static/ stores web assets (images, CSS, JS files)
  • all files in static/ copied to public/ when Hugo renders website
  • put local images in static

applications of static files

style.css

  • e.g. static/style.css will override themes/static/style.css
		body {
		  font-family: "Comic Sans MS", cursive, sans-serif;
		}
		code {
		  font-family: "Courier New", Courier, monospace;
		}

render .Rmd to any format

  • .Rmd file with output NOT generated by blogdown::html_page()
  • more info https://bookdown.org/yihui/blogdown/methods.html#methods
  • e.g. .Rmd file generates PDF,
    • putting the .Rmd file in static/, blogdown will generate PDF,
    • and Hugo will just copy PDF file into public/
    • need to write custom “build” script R/build.R with blogdown::build_dir("static")

3.1 netlify deployment

  • login to Netlify with github username to link Netlify with Github

Netlify continuous deployment with GitHub Repo

  • host all source files (not just public/) in a github repo
  • Netlify create new sites from github repo
  • Netlify supports Hugo
	Deploy settings
	repository			https://github.com/username/repo
	branch				master
	build command			hugo
	publish directory		public
  • may need to create environment variable HUGO_VERSION
  • need version 0.62.0 to work
	Build environment variables
	HUGO_VERSION		0.24.1	(or latest)	
  • may take few minutes to deploy on Netlify for first time
  • but later updates are incremental

auto-update

  • now git push to github repo and
  • Netlify calls Hugo to render website automatically

domain name

  • custom domain name, need to configure some DNS records, point it to Netlify server
Previous