Coding Blog using Hugo
Requirements
The home page must list all the articles (only the links with title) in the md files. Clicking the link will go to view article page that shows the title and body. It should support code syntax highlighting.
Creating a blog with Hugo is straightforward and manageable. Here are the general steps you need to follow:
Step 1: Install Hugo
First, you’ll need to install Hugo. It’s available for Windows, MacOS, and Linux. You can check out the official Hugo Installation Guide for specific instructions for your OS.
Step 2: Create a new Hugo site
Once you’ve installed Hugo, open your terminal and navigate to the directory where you want your new site to be. Then, run the following command:
|
|
Replace “my-blog” with the name you want for your blog.
Step 3: Add a theme
Next, you need to choose a theme for your blog. You can find a lot of great themes at Hugo Themes. For this guide, let’s use the “Ananke” theme. You can add it with the following commands:
|
|
And add the theme to your site configuration:
|
|
Step 4: Create content
Now, you’re ready to start adding content. Hugo uses Markdown for its content files. To create a new post, use the following command:
|
|
This will create a new file at content/posts/my-first-post.md
. Open this file in your text editor and you’ll see something like:
|
|
Underneath, you can start writing your blog post in Markdown. For example:
|
|
Notice that draft
has been changed to false
. If draft
is set to true
, Hugo won’t include the page in the built site.
Hugo also supports code syntax highlighting out of the box using Chroma. You can use it like so:
|
|
To make sure syntax highlighting is enabled, add the following lines to your `hugo.toml` file:
```toml
pygmentsCodeFences = true
pygmentsStyle = "monokai"
You can replace "monokai"
with the name of any style included with Chroma.
Step 5: Build and Run the site
Finally, you can build your site with the following command:
|
|
And you can run your site locally with:
|
|
Visit localhost:1313
in your browser to see your site. The -D
flag tells Hugo to include content marked as a draft.
Clicking on the title of a post in the list on the homepage will take you to that post’s page, where you can see the title and content of the post.
Remember to save and commit any changes you make to your content. When you’re ready to publish your site, you’ll need to host it somewhere. GitHub Pages and Netlify are both good options that integrate
Using Fuse.js with Hugo
Sure, Fuse.js is another popular and powerful option for search functionality in static sites like those built with Hugo. Here are steps on how to integrate Fuse.js with Hugo:
Step 1: Adding HTML for the Search Box
First, you’ll need to modify your site’s header or the navigation bar to include a search box. The header is usually defined in the file layouts/partials/header.html
or layouts/partials/nav.html
(this can vary depending on the theme). You can add the following HTML code in the appropriate position where you want the search box to appear:
|
|
Step 2: Including the Necessary JavaScript Library
Next, you will need to include Fuse.js in your site. Add the following line to your layouts/partials/footer.html
file or layouts/partials/scripts.html
file (again, the exact file can vary depending on the theme):
|
|
Step 3: Generating the Search Index File
To create the search index file that Fuse.js can use to perform searches, you need to add the following to your site’s configuration file (config.toml
):
|
|
Next, create a new file at layouts/index.json
with the following content:
|
|
This will create a JSON file at the root of your site (index.json
) that includes the URL, title, and content of each page.
Step 4: Implementing the Search Functionality
Finally, you’ll need to add some JavaScript code to load the search index and perform searches when the user types into the search box. You can add the following code to your layouts/partials/footer.html
file or layouts/partials/scripts.html
file:
|
|
In this code, indexData
is the search index data that was loaded from index.json
. The fetch('/index.json')
fetches the data from the index.json
and fuse.search(this.value)
is the function that performs the search whenever the user types into the search box.
Note: Fetch API needs a server to work. If you try to use the fetch
function with the file://
protocol, it will not work. You can use hugo server
to run your website locally for testing.
Displaying Search Results
To display search results, you’ll want to create a container in your HTML where the results can be displayed. This could be a simple unordered list. The JavaScript code can then dynamically populate this list with the search results.
Follow these steps:
Add a search results container to your layout: This could be a simple unordered list beneath your search box. Here’s how you might modify the navbar in your layout:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
<div class="navbar-item"> <div class="field has-addons"> <div class="control"> <input id="search" class="input" type="text" placeholder="Search"> </div> <div class="control"> <button id="searchBtn" class="button is-info"> Search </button> </div> </div> <!-- Add this ul to your layout --> <ul id="search-results"></ul> </div>
Modify your JavaScript code: You need to modify the
oninput
event handler in your JavaScript code to update the search results container whenever the user types into the search box. Here’s how you might do it:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
window.onload = function () { fetch('/index.json') .then(response => response.json()) .then(data => { const fuse = new Fuse(data, { keys: ['title', 'content'], includeScore: true }); const searchBox = document.getElementById('search'); const resultsContainer = document.getElementById('search-results'); searchBox.oninput = function () { // Clear previous results resultsContainer.innerHTML = ''; const results = fuse.search(searchBox.value); // Add new results to the results container for (let result of results) { const li = document.createElement('li'); const a = document.createElement('a'); a.href = result.item.permalink; a.textContent = result.item.title; li.appendChild(a); resultsContainer.appendChild(li); } }; }); }
This code first clears the search results container whenever the user types into the search box. It then populates the container with the new search results. Each result is a list item containing a link to the post.
With these changes, your search box should dynamically display search results as the user types into it. Each result is a link to a post, and the results update in real time as the user types.
If you want to display search results on the page instead of the navigation bar, you’ll need to move the <ul id="search-results"></ul>
element to a location outside of the navigation bar.
Here’s a sample of how you might structure your baseof.html
file to include a search results container:
|
|
In this layout, the search results container (#search-results-section
) is separate from the navigation bar and the main content. The search results will be displayed in this container when the user types into the search box.
You may also want to update the JavaScript code to clear the main content when displaying search results. For example:
|
|
This updated JavaScript code will clear both the previous search results and the main content when the user types into the search box. This way, only the search results will be displayed on the page.
Using Bulma with Hugo
Let’s walk through the process of building a simple Hugo site with Bulma CSS from scratch.
Step 1: Create a New Hugo Site
We’ll start by creating a new Hugo site:
|
|
Step 2: Add Bulma CSS to Your Site
Download Bulma CSS into your static
directory:
|
|
Then, in your layouts/partials
directory, create a head.html
file and include the Bulma CSS:
|
|
Step 3: Create a Layout for Your Site
In the layouts/_default
directory, create a baseof.html
file that defines the basic layout for your site:
|
|
Here, the block
directives are placeholders that can be filled in by other templates.
Step 4: Create a Header with a Navigation Bar
Create a header.html
file in your layouts/partials
directory that defines the header block:
|
|
This creates a navigation bar with Home, Articles links, and a search box.
Step 5: Create a Layout for the List of Posts
Next, we’ll create a list layout for displaying the list of posts. In the layouts/posts
directory, create a list.html
file:
|
|
This lists the titles of all posts as links.
Step 6: Create a Layout for Individual Posts
Finally, we’ll create a layout for individual posts. In the layouts/posts
directory, create a single.html
file:
html
<!-- layouts/posts/single.html -->
{{ define "main" }}
<section class="section">
<div class="container">
<div class="content">
<h1>{{ .Title }}</h1>
{{ .Content }}
</div>
</div>
</section>
{{ end }}
This displays the title and content of an individual post.
You can now create some posts in the content/posts
directory and view your site by running hugo server
. The search box does not work yet - we previously discussed how to add search functionality using JavaScript libraries like Fuse.js or Lunr.js.
Remember that this is a very basic setup and you might need to add more styles or functionality to suit your needs. You can consult the Hugo documentation and the Bulma documentation for more information.
You can use the Bulma CSS classes to style and position your search results. You can wrap your search results list in a container
class to center it and provide a maximum width. Then, you can further wrap it in a section
class to provide some vertical spacing.
Here’s how you can adjust your baseof.html
file:
|
|
This will make sure that your search results are properly contained and centered, with a comfortable amount of vertical spacing. Remember to clear the search results container whenever a new search is conducted or when the search input is cleared.
If the positioning still doesn’t look right, it’s likely that some additional custom CSS will be needed. Bulma is a very flexible framework, but there are times when the built-in classes might not provide the exact positioning or styling you’re looking for. In those cases, you can write some custom CSS to tweak the layout to your liking.
Code Syntax Highlighting
Hugo has built-in support for syntax highlighting through the use of Chroma. Here’s how you can enable it:
First, add the following lines to your site’s configuration file (for example,
config.toml
) to enable syntax highlighting:1 2 3 4 5 6 7 8 9 10
[markup] [markup.highlight] codeFences = true guessSyntax = false highlightInClient = false lineNos = true lineNumbersInTable = true noClasses = true style = "monokai" tabWidth = 4
You can adjust these options according to your needs. The
style
option determines the color scheme of the highlighted code. “monokai” is just one example, you can choose another style from Chroma’s style gallery.Then, you can include code in your markdown files using code fences, and Hugo will automatically highlight it. Here’s an example:
1 2 3
```python def hello_world(): print("Hello, world!")
Make sure to replace "python" with the appropriate language identifier for your code.
Note: If you set noClasses = false
in the configuration, then Hugo will use CSS classes to style the code. You will need to include the appropriate CSS on your site. You can generate this CSS using the hugo gen chromastyles --style=monokai > static/css/syntax.css
command and then include it in your head.html
partial:
|
|
The public Folder
Can I delete everything in the public folder to force hugo to regenerate the files to pickup the changes?
Yes, you can safely delete everything in the public
folder. The public
directory is where Hugo generates the static website files, and it’s safe to delete because Hugo will regenerate these files every time you run the server or build the site.
To delete the public
folder, you can use this command in your terminal:
|
|
Then, you can run Hugo again to regenerate the site:
|
|
After running this command, your public
directory should be filled with new, up-to-date files generated from your content and layout files.
In general, if you’re running the hugo server
command for local development, Hugo should automatically regenerate the site when it detects changes in your files. However, manually deleting the public
folder can be useful in some cases if you want to be sure you’re starting from a clean state.
The content Folder
Do I need to put the md files inside content/posts folder ?
Yes, according to the structure and configurations we have discussed, your Markdown (.md
) files representing your blog posts should be placed inside the content/posts/
directory.
Here is the reasoning:
In Hugo, the content organization directly reflects your URL structure. If you place an .md
file directly under the content/
directory, it will be treated as a standalone page. On the other hand, if you place it under content/posts/
, it’s considered a part of the “posts” section. The “posts” section is what we’ve set up to display on the home page as a list of all articles.
So, for each of your blog posts, create a new Markdown file inside the content/posts/
directory. Each file should start with a front matter section, where you specify metadata like the title and date. Here’s an example:
|
|
After creating your posts, run your Hugo server again, and you should see the titles of all your posts listed on the home page. Clicking a title will take you to the respective post’s page.
The home Page
You can add static text by creating a custom homepage layout. Hugo allows you to override the list page layout for the homepage.
Follow these steps to create a custom homepage layout:
In the
layouts
directory, create a new file calledindex.html
. This will serve as the layout for your homepage.Open
index.html
and enter the following content:1 2 3 4 5 6 7 8 9 10
{{ define "main" }} <div class="content"> <h1>Welcome to my blog</h1> <p>Some interesting static text here...</p> <h2>Articles:</h2> {{ range .Site.RegularPages }} <h2><a href="{{ .Permalink }}">{{ .Title }}</a></h2> {{ end }} </div> {{ end }}
This layout first displays a static welcome message, followed by a list of all your articles.
Save your
index.html
file.
With this setup, when you visit your homepage, you will see a welcome message followed by a list of all your articles. This is because Hugo uses the index.html
layout for the homepage when it exists.
The range .Site.RegularPages
line is a loop that generates a list of all your pages across all sections (in your case, the articles in the “posts” section).
Don’t forget to restart your Hugo server after making these changes, so that the new layout is used.
Deploying Hugo to AWS Amplify
I did not have any luck running the build and get the Go runtime working on Netlify, Vercel or AWS Amplify. I generate the files for production by running:
|
|
and deploy all the files under the static folder to the blog.
What should be the baseURL for development and production in toml file?
In Hugo, the baseURL
parameter in the configuration file is the URL on which your site will be built.
For local development, the baseURL can typically be set to the root ("/") or to “http://localhost:1313”, which is the default server address when running Hugo server locally.
For example:
|
|
For a production build, you should set baseURL
to the domain name or IP address where your site will be hosted.
For example, if your website domain is www.example.com:
|
|
If your Hugo project needs to be built differently for different environments (such as local development vs production), you can use Hugo’s environment feature.
You can define the environment when building your site with the HUGO_ENV
environment variable. Then you can use the getenv
function in your config file to change the baseURL based on the environment:
|
|
When running Hugo, specify the environment:
|
|
Hugo will use the corresponding baseURL based on the HUGO_ENV
variable.