Blog with R and Hugo
Contents
Hugo is the great tool to build static web sites, i.e. sites with no backend database, just a plain HTML that is generated from a markup code. Such the site can be hosted on multiple platforms including Amazon and GitHub. The blog can be managed directly from RStudio. I tried to use Hugo for my blog and here is the log of this attempt with solutions to problems I encountered.
Basic local setup
Creation of a local landscape of the future blog is the most easy part of the process:\
- Install the package blogdown in RStudio.\
- Create a New Project in the RStudio in a new folder. Fill the field “Theme” to supplement a theme codename in the creation dialog.\
- Call the
blogdown:::serve_site()function from an R command line to enjoy the result.
The themes catalog can be found here. The catalog allows to try a living demo of the themes.
While it is possible to change a theme later with a call to the function blogdown:::new_theme() it is recommended to create the site anew because the theme installer overwrites the config file in the site’s root folder.
The least cluttered and flashy themes to start a technical blog are in my opinion Mainroad and Even.
Theme codename is basically it’s GitHub repository name in the form <author>/<repository>. For example, for theme Mainroad it is “Vimux/Mainroad”.
File catalog structure
| File/Folder | Description |
|---|---|
| config.yaml | Global site parameters (Title, author name, baseURL, etc. will be here). |
| contents | Folder with source code for posts. |
| themes | The theme layout will be here. |
| public | The finally generated content for Internet hosting will be here. |
Post formats
Posts can be written in ordinary Markdown (.md files) or RMarkdown (.Rmd, .RMarkdown files). Depending on the file extension the different parsers will be utilized.
While HUGO authors argue for using RMD format, and it may be the only adequate way for interactive sites, it also has a lot of drawbacks for static sites:
-
The R code will be recalculated for an each post. There are consequences. Firstly, you will need to keep all the source data for computations. And secondly, your R-libraries to change sometime in the future so you may find that your site renders no more.
-
There will be no table of contents displayed on post pages due to some persistent bugs in the parser.
So I prefer to keep computational code separate from presentation layer and to make hard computations beforehand with an output to lightweight Markdown code to copy it then into Hugo.
Posts metadata
All information about the post’s author, date, keywords, tags, categories, etc. is kept in the post’s YAML header. The most convenient way to learn about possible post’s properties is to create its template automatically via Addins->Blogdowns->New Post or by call to blogdown:::new_post().
Customization
Appearance
After the theme is installed it should be customized at least minimally, i.e. by editing the site parameters file config.yaml.
You may want to customize deeply by editing files in the folder “/themes”, but it is theme-dependent. For example, to make a wider central column in the theme Even you will need to edit the variable in the file “\themes\hugo-theme-even\assets\sass\_variables.scss”: $global-body-width: 800px;.
Page templates and templates for parts of pages are stored in the folder “/layout/partials/”.
MathJax
To force Hugo to render math formulas the following needs to be done:
-
To turn on the rendering options in the site’s config file.
-
To include the MathJax rendering code in the template for pages (or may be directly into config.yaml). For example, it is convenient to include the following code in the footer template ("/layout/partials/footer.html").
<script type="text/javascript"
src="https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
</script>
More information about enabling MathJax is here.
If you are using MD format to write posts, you may need to envelope $$ math code blocks in <div></div>. Rendering of math formulas for posts in RMD format should work out of the box.
Comments
Comments are allowed by supplying your Disquss name into the config file:
comment: true
disqusShortname: <yourdiscussshortname>
More information about comments setup is here
Google analytics
By default to turn Google Analytics on in Hugo it is sufficient to supply your Google Analytics tracking ID into the sites’s options file:
googleAnalytics: <Google Analytics ID>.
But there is a ‘but’. This works only for the previous version of GA so called “Universal Analytics” and does not work with the latest version “Google Analytics 4”. However, right on the data stream configuration page Google provides a tracking script that can be included in your pages. I put it into the “footer” partial of the theme, to be sure it is to be executed on every page of the site.
RSS
RSS feed is built it. In the theme Evan a user can get an RSS link from the footer of any page.
Multilingual sites
There are two ways to make multilingual content:
1. By using .en .ru etc. suffixes in posts filenames, eg. index.ru.md.
2. By using the different content sub-directories for each of the languages, i.e.:
content/en/<posts>
content/ru/<posts>
Each language’s content directory is pointed to using the contentDir param in the site’s configuration file. For example:
languages:
en:
title: Datascience, tools and datasets
contentDir: content/en
languageName: English
weight: 2
ru:
title: Datascience, tools and datasets
languageName: Russian
contentDir: content/ru
weight: 1
It is also possible to add content switch to the site’s main menu (at least in the theme Even):
showLanguageSelector: true
It is possible to use the field translationKey in YAML headers of posts. The posts with the same translationKey value will be treated by Hugo as lingual versions of the same post so they may use common resources (eg. figures).
Code syntax highlighting
As is explained here Hugo uses the Pygments library to highlight syntax. This is controlled by the option pygmentsUseClasses in the config file.
If you set it to true you must generate Pygments css-style or download already precompiled CCS-file from here and substitute the “code.CSS” inside the theme with it. The styles gallery may be found here.
In the theme Evan such CSS file is called “_code.scss”. A downloaded new CSS file must replace it. This is the only way in Evan which offers only the single build in code highlighting style. Code rendering may be slightly controlled by other Pygments options, i. e. pygmentsOptions: linenos=false switches off line numbering.
In the theme Mainroad it is possible to set this parameter to false and customize code blocks with a little more transparent syntax, the markup block of parameters in the config file. For instance, it is possible to directly supply style name, to set whether or not Hugo should count code lines, etc.:
markup:
highlight:
style: monokai
anchorLineNos: false
codeFences: true
guessSyntax: false
hl_Lines: ""
lineAnchors: ""
lineNoStart: 1
lineNos: false
lineNumbersInTable: true
noClasses: true
tabWidth: 4
More about syntax highlighting is here.
Customization with shortcodes
You may include so called shortcodes in your posts, that are calls to templates to be executed with a result substituted into the post. Each shortcode is associated with some HTML-template by name. You can create your own shortcodes and templates, allowing to extend the page functionality. Quite powerful mechanism but difficult to debug. Shortcodes are discussed here.
Debugging and publishing the site
The command blogdown::serve_site() compiles all sources and start a local copy of web-server. The site is updated dynamically, so if you change posts the changes will be immediately reflected on site’s pages.
Use blogdown::stop_server() to stop the local server.
Use blogdown::hugo_build() to render output that will be hosted publicly (the output is places in the folder “/public”).
Deploying the site on GitHub
Compiled site may be deployed anywhere, for example in the GitHub repository. The process is staighforward and is described here and requires essentially to create github repository and cloning it to a local machine.
Updating the site content is more tricky. My way is to sync the Hugo output folder ‘/public’ with the local git repository folder using the FreeFileSync program and then detecting and pushing changes to the Internet with Git GUI.
Problems
Future posts
Sometimes it is convenient to create a post that will be always on top in the site’s posts list. For example it will contain links to the most important posts. To do so you will need to set its date somewhere in far future. Unfortunately HUGO will skip such posts by default when rendering the “/public” folder. To change this behavior is to set the following option: buildFuture: true in the config file.
It also is possible to allow or forbid rendering of drafts and expired posts:
buildDrafts: false
buildExpired: true
Always name markdown files as “index”
While it is possible to name source files arbitrarily it is better due to bugs to follow the rules:
* Use a separate folder for each if the posts;
* Place a main content of a post in the files “index.md” or “index.rmd”.
Use the correct date format
It is better to supply a date in a YAML header in the form 2021-03-19T20:00:00-00:00. Otherwise the parser may process it wrongly.
Citations vs. Table of contents
Here we go into problems: due to some bug in the RMD parser and limitations in the MD parser you can either include BIB-style references to a bibliography or display table of contents but not both. Below are the links to some discussions with some inspiring ideas of workarounds but no good solution:
* “Adding a sticky table of contents in Hugo to posts”,
* ".TableOfContents in Markdown",
* “TOC not displaying in Blogdown post (Hugo theme Even)",
* “Preserve toc:true in YAML front matter for Hugo”,
* “customize the template for .TableOfContents #225”.
Half-solution 1: Keep citations, no TOC
The main idea is to keep interim MD-file created when processing of an RMD-source file and rename its suffix to “.Rmd” again for publishing.
Steps:\
- Set YAML header options
keep_md: true,self_contained: no,preserve_yaml: yesforblogdown::html_output.\ - Knitr project RMD file to blogdown::html_output.\
- Copy the created MD file to
/content/post/<post-name>with renaming it toindex.Rmd.\ - Copy the created pictures folder, BIB-file, CLS-file.
The small problem persists: references to the bibliography in the text will be static, i.e. as in a paper book.
Half-soultion 2: Keep TOC, no citations
The main idea is to keep interim MD-file as it is.
Steps:\
- Set YAML header options
keep_md: true,self_contained: no,preserve_yaml: yesforblogdown::html_output.\ - Knitr project RMD file to blogdown::html_output.\
- Copy the created MD file to
/content/post/<post-name>with renaming it toindex.md.\ - Copy the created pictures folder (BIB-file, CLS-file will be useless.)
Unworkable ideas:
1. Compile an html-file with a bibliography and a TOC separately and copy it to Hugo. Error: HTML-file is ignored by Hugo.
2. Use pandoc to augment an interim MD-file with a bibliography. Ex.C:\Program Files\Pandoc\pandoc.exe" r-text.md -t markdown-citations -s --bibliography r-text.bib --csl journal-of-web-semantics.csl --no-highlight -o index.md. Error: The blocks of html-code generated when compiling RMD to MD are marked as code citations block.
3. Compile an html-file with a bibliography and TOC separately and convert it back to MD with PanDoc. Ex. C:\Program Files\Pandoc\pandoc.exe" -w markdown+escaped_line_breaks r-text.html -o index.md --wrap=preserve --atx-headers. Copy an YAML header to a newly generated MD-file. Error: Because of usage of “strict” markup there will be confusion in formatting. But use of PanDoc’s own markup will also cause errors in formatting.
4. Use of shortcodes in RMD causes Hugo to crash due to emptiness in .TableOfContent variable.
Links
1. Configuration manual
2. RMarkdown manual
3. Multilanguage setup
4. Shortcodes manual
5. MaxJax manual.
6. The YAML Fieldguide - list of the YAML header fields
7. Documentation about themes template customization
8. Setting up comments
Author Vladislav Borkus
LastMod 2021-03-19
License (C) Vladislav Borkus