Skip to main content

Migrating existing page to hugo static site generator

·1227 words·6 mins
hugo
pdyc
Author
pdyc
Table of Contents

TLDR: How to migrate existing site to Hugo

When i was migrating my Easyanalytics landing page to Hugo (static site generator) it took me long time to figure out how to do it. This was because its documentation often serves as a reference rather than a comprehensive guide. Moreover, existing tutorials tend to focus on building new sites with existing themes, leaving experienced developers and those migrating from other systems with limited guidance.

This article aims to bridge that gap, I am assuming you are already familiar with HTML and CSS and have gone through Basic tutorial for Hugo. We will take a top-down approach, using existing HTML, css, JS and replicate the same functionality in Hugo. This way you will understand how to migrate your existing UI to Hugo.

Creating basic website using HTML, CSS and JS

Let's create a simple website using HTML, CSS, and JavaScript. This website will serve as the foundation for later replication in Hugo.

  <!DOCTYPE html>
  <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <link rel="stylesheet" href="styles.css">
      <title>Your Website Title</title>
    </head>
    <body>
      <header>
        <h1>Your Website</h1>
      </header>
      <main>
        <section class="hero">
          <h2>Welcome to Your Website</h2>
          <p>Discover the amazing features we offer.</p>
        </section>

        <section class="features">
          <h3>Key Features</h3>
          <ul>
            <li>Feature 1</li>
            <li>Feature 2</li>
            <li>Feature 3</li>
          </ul>
        </section>

        <!-- Add more sections as needed -->

      </main>
      <footer>
        <p>&copy; 2024 Your Website. All rights reserved.</p>
      </footer>
      <script src="script.js"></script>
    </body>
  </html>
  body {
      font-family: Arial, sans-serif;
      margin: 0;
      padding: 0;
  }

  header {
      background-color: #333;
      color: #fff;
      text-align: center;
      padding: 1rem;
  }

  main {
      padding: 2rem;
  }

  .hero {
      background-color: #f0f0f0;
      padding: 2rem;
  }

  .features {
      margin-top: 2rem;
  }

  footer {
      background-color: #333;
      color: #fff;
      text-align: center;
      padding: 1rem;
  }
  // Display an alert when the page loads
  window.onload = function () {
      alert("Welcome to Your Website!");
  };

This basic structure includes a header, a main content area with a hero section and key features, and a footer. The corresponding CSS file (styles.css) provides minimal styling for a clean and responsive layout. JavaScript code demonstrates an alert on page load.

Replicating the Same Site in Hugo:

Now that we've created a basic website using HTML, CSS, and JavaScript, let's explore how to replicate the same site in Hugo

In your terminal, run the following commands:

hugo new site your-hugo-site
cd your-hugo-site

This sets up a new Hugo site with a basic structure. It would look something like the one given below

Hugo Site Directory Structure:

/your-hugo-site
├── content
├── layouts
│   └── partials
├── static
│   ├── styles.css
│   └── script.js
└── config.toml
  • /content: Contains content files.
  • /layouts: Holds HTML layout files.
  • /layouts/partials: Contains partial HTML files for header, footer, etc.
  • /static: Houses static assets like CSS and JS.

Hugo separates HTML and content; content can be written in markdown or org format(Emacs org file format) while any HTML would be in "layouts" folder. Although there are ways to include custom HTML in content file and place content in the layout template, it's not considered the idiomatic way.

HTML in Layouts: In Hugo, HTML is organized within layouts. Create a new file named layouts/_default/landing.html in your Hugo project and copy and paste the following code, incorporating your existing HTML.

  <!DOCTYPE html>
  <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <link rel="stylesheet" href="{{ "styles.css" | absURL }}">
      <title>Your Website Title</title>
    </head>
    <body>
      <header>
        <h1>Your Website</h1>
      </header>
      <main>
        <section class="hero">
          <h2>Welcome to Your Website</h2>
          <p>Discover the amazing features we offer.</p>
        </section>

        <section class="features">
          <h3>Key Features</h3>
          <ul>
            <li>Feature 1</li>
            <li>Feature 2</li>
            <li>Feature 3</li>
          </ul>
        </section>

        <!-- Add more sections as needed -->

      </main>
      <footer>
        <p>&copy; 2024 Your Website. All rights reserved.</p>
      </footer>
      <script src="{{ "script.js" | absURL }}"></script>
    </body>
  </html>

This layout file references external CSS and JS files. Lets see how to include them in this template.

Including CSS in Hugo: Place your existing styles.css file in the static folder at the root of your Hugo project. Hugo automatically includes files from this directory in the generated site.

Including JS in Hugo: Similarly, move your script.js file to the static folder.

Adding Content for HTML to Take Effect: Now, let's create content files for Hugo. In the content folder, create a new file named _index.md. Add your desired content in Markdown format. For example:

---
title: "Your Website Title"
date: 2024-01-02T12:00:00Z
layout: "landing"
hero: "Welcome to Your Website"
features:
  - "Feature 1"
  - "Feature 2"
  - "Feature 3"
---

Ensure that the layout field in the front matter explicitly points to "landing". This is the secret sauce for forcing any content page to to be rendered by layout template of your choice. If you skip it Hugo will follow complex rules to decide how to render the site based on the location of content in content directory.

Also take a note of _index.md file, it is special file in Hugo that is used to render the root of the directory. If we create a new file say toc.md, hugo will generate a page named '/toc' but what about the / i.e. root? to add content corresponding to root Hugo has special convention of using _index.md.

Run following command to see your website

hugo server -D

You can see that we have additional metadata for hero and features. We can access this with .Params.<metdata key>. Lets change our template to access it.

  <!DOCTYPE html>
  <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <link rel="stylesheet" href="{{ "styles.css" | absURL }}">
      <title>{{ .Title }}</title>
    </head>
    <body>
      <header>
        <h1>Your Website</h1>
      </header>   
      <main>
        <section class="hero">
          <h2>{{ .Params.hero }}</h2>
        </section>
        <section class="features">
          <h3>Key Features</h3>
          <ul>
            {{ range .Params.features }}
            <li>{{ . }}</li>
            {{ end }}
          </ul>
        </section>
      </main>
      <footer>
        <p>&copy; 2024 Your Website. All rights reserved.</p>
      </footer>
      <script src="{{ "script.js" | absURL }}"></script>
    </body>
  </html>

It directly incorporates the content from the front matter, using {{ .Params.hero }} and {{ range .Params.features }}.

Using Partials for Reusable HTML Components: Now that we've created a basic website using HTML, CSS, and JavaScript, let's explore how to enhance code modularity in Hugo by separating common HTML components into their own templates using partials. This technique allows for the inclusion of shared elements, like headers and footers, in any page template.

Create separate partial files for common elements like headers and footers in the layouts/partials folder.

header.html:

  <header>
    <h1>Your Website</h1>
  </header>

footer.html:

  <footer>
    <p>&copy; 2024 Your Website. All rights reserved.</p>
  </footer>

Now, modify your layouts/_default/landing.html to include these partials:

  <!DOCTYPE html>
  <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <link rel="stylesheet" href="{{ "styles.css" | absURL }}">
      <title>{{ .Title }}</title>
    </head>
    <body>
      {{ partial "header.html" . }}
      <section class="hero">
        <h2>{{ .Params.hero }}</h2>
      </section>
      <section class="features">
        <h3>Key Features</h3>
        <ul>
          {{ range .Params.features }}
          <li>{{ . }}</li>
          {{ end }}
        </ul>
      </section>
      {{ partial "footer.html" . }}
      <script src="{{ "script.js" | absURL }}"></script>
    </body>
  </html>

This approach enables you to keep commonly used HTML components in separate partials, promoting code reusability and easier maintenance.

By following these steps, you've successfully integrated your existing HTML, CSS, and JS code into Hugo templates, enabling static site generation with Hugo's powerful features.

Conclusion

In this tutorial, we've explained how to migrate your existing page to Hugo. You can read hugo docs if you want to dig deeper and understand specific features of hugo. In this tutorial series i am taking the approach of explaining how to do X in hugo and only explaining the concepts necessary to get the job done.

Related

How to use org mode in Hugo
·967 words·5 mins
hugo
Did you know that Hugo supports formats other than markdown for content?
I don't know what i did last summer
·918 words·5 mins
easyanalytics indiehacking
TLDR: How author forgot his own code, ended up wasting time and learned importance of documenting the code.
Easyanalytics - web analytics for cloudflare 🗓️ plan & execution 📋
·1337 words·7 mins
indiehacker easyanalytics
This page lists project plan and execution details of easy analytics.