Zola daisyUI blog

Zola daisyUI blog

Introduction

I created a blog template using Zola + daisyUI, so I am writing this article as a reminder for myself as well.

This article describes why I created it, the setup procedure, and so on.


Why did I create it?

I had been thinking about sharing personal information through GitHub Pages for some time, but I finally got around to building the application.

mosaos/zola-daisyui-blog

* An actual example can be found here.

At first, I tried implementing a simple version with React/TypeScript (I had already made it possible to display Markdown), and I also tried using Astro based on AI advice. In the end, I settled on the following technology stack.

  • Zola
    An SSG (Static Site Generator) written in Rust
  • daisyUI
    A component library for Tailwind CSS
  • GitHub Pages
    A requirement from the beginning

The reason I stopped using Node.js was simply that I did not want to end up in a maintenance hell.

I work on React projects in my professional work as well, but Node.js-based projects tend to have:

  • Many related packages
  • A lot of security (vulnerability) fixes
  • Many breaking changes

The fact that I am particularly bothered by breaking changes may also be because Java (such as Spring Boot) is my strongest language. Having to perform maintenance even though the actual application itself has not changed is one thing when doing it for work, but it is a hassle for a personal information-sharing site.

For these reasons, I ended up with the configuration above.

Some people may say that daisyUI also requires Node.js, but if you use something like the full.css published via CDN, you can use Tailwind / daisyUI without a Tailwind/daisyUI build process. (It includes everything, though.)

There may also be arguments about optimization, but avoiding maintenance hell is the most important requirement for me, so using resources from a CDN is perfectly fine.


Features

This is the template I created. See README.md for details, but it has the following features.
Most of these are essentially characteristics of Zola/daisyUI and so on.

  • Responsive Design
    A simple and easy-to-use layout that also supports mobile devices, powered by daisyUI and Tailwind CSS.
  • Markdown-based
    Blog posts and portfolio works can be easily created using Markdown. Articles can also display a Table of Contents (TOC).
  • Multilingual Support
    A multilingual switcher is included by default. It can be extended to any number of languages as needed.
  • Static Site Generation (SSG)
    Fast and secure, with no need for server-side runtimes such as Node.js.
  • Dev Containers Support
    The development environment can be set up quickly, reducing the effort required for environment setup.
  • Tag Support
    Content can be organized and categorized using tags.
  • Image Carousel / Slideshow
    A carousel is included for displaying multiple photos or images, such as portfolio works.

Development Environment

I have tested it with the following environment.

  • Windows 11
  • WSL2 (Ubuntu)
  • docker-ce
    Used when using Dev Containers. This is not Docker Desktop, so it can also be used in companies that do not have a Docker Desktop license.
  • VS Code

Setup

The application part is registered on GitHub as a template project. The recommended procedure is as follows.

Since symbolic links are used to check the site locally, WSL2 is recommended (when using Windows).
I don't know about Mac.

Creating the Repositories

  1. Access mosaos/zola-daisyui-blog.
  2. Click Use this template > Create a new repository and create it as your own repository (such as my-portfolio). Private is also fine.
  3. Create a separate repository for the content, such as my-portfolio-content. Private is fine.
    This separates the application and content so that the application part can be updated more easily if it is updated in the future. If you do not want the extra hassle, you can also keep everything in my-portfolio from step 2 without separating the content.
  4. Create a repository for GitHub Pages (Public). If you want to publish the site directly under the domain, use username.github.io as the repository name.

Check the Site Locally First

If you did not separate the content repository, you do not need to replace it with a symbolic link.

Without Dev Containers

Create a symbolic link from the application-side content directory to the content repository.

Delete the content directory on the application side (my-portfolio):

cd /path/to/my-portfolio
rm -rf content

Create a symbolic link to the content repository (my-portfolio-content).
The following assumes that my-portfolio and my-portfolio-content are in the same directory.

ln -s ../my-portfolio-content content

With Dev Containers

Symbolic links do not work here, so mount the directory instead.

Do not delete the content directory in my-portfolio; just remove its contents.

Add the following mounts definition to devcontainer.json in my-portfolio.

    "forwardPorts": [
        1111
    ],
    // Bind-mount the content repository on the host to the Zola content directory in the container
    "mounts": [
        {
            "source": "${localWorkspaceFolder}/../my-portfolio-content",
            "target": "${containerWorkspaceFolder}/content",
            "type": "bind"
        }
    ]
    // "remoteUser": "root"

After configuring this, run Rebuild Container. If the contents of content are visible (linked) from the Dev Container, the setup was successful.

Check the Site

Check the site locally.

cd /path/to/my-portfolio

If you are using a Dev Container, open VS Code and check from the Dev Container terminal.

Otherwise, you can check it using Zola installed on WSL2 (Ubuntu).

code .
zola serve --interface 0.0.0.0 --port 1111 --base-url /

In VS Code, a dialog saying Your application running on port 1111 is available. See all forwarded ports will appear. Click Open in Browser, and if the site is displayed, everything is OK.

If you are not using VS Code, open http://localhost:1111/ and check that the site is displayed.

Adjust .gitignore

Once you have confirmed that it works, exclude the contents of the content directory on the my-portfolio side so that the files in my-portfolio-content are not managed in multiple places. Add the following:

content/**

You may also want to run the following in my-portfolio:

git rm --cached -r content

At this point, the local development/checking environment is ready.

You can now add content or customize the application part as needed.

Prepare a PAT (GitHub Personal Access Token)

From here, the setup is for publishing the site to GitHub Pages using GitHub Actions.

This is not necessary if you plan to generate the SSG site manually using Zola locally/in a Dev Container and publish the generated pages yourself.

my-portfolio needs access to the separate private repository (my-portfolio-content) and the public repository (username.github.io). Prepare a PAT using the following procedure.

  1. Open Tokens (classic) from Settings > Developer settings > Personal access tokens, using your account icon on the upper right.

  2. Click Generate new token (classic).

  3. Enter a description in Note (such as portfolio deploy token) and set the expiration date.

    • Recommended:
      From a security perspective, 30 days or 60 days (regular renewal is required)
    • Compromise for personal use:
      If you want to reduce the effort of renewing it, 90 days (a reminder email will be sent shortly before expiration)

    No expiration is not recommended because the risk is high if the token is leaked.

  4. Under Select scopes, check:

    • repo
  5. Click Generate token at the bottom of the page and keep the generated token somewhere safe. (It cannot be displayed again once you close the page.)

Register the Token in GitHub Secrets

Register the issued token as a secret in the application-side repository (my-portfolio).

  1. Open your my-portfolio repository page.

  2. Go to Settings > Secrets and variables > Actions.

  3. Click New repository secret.

    • Name: GH_PAT (or another easy-to-understand name)
    • Secret: Paste the PAT string you copied earlier.
  4. Click Add secret to save it.

Create the GitHub Actions Workflow

Create a GitHub Actions configuration file in the root of the application-side repository (my-portfolio).

This configuration is based on the author's setup, so change it as appropriate.

.github/workflows/deploy.yml

name: Build and Deploy Zola Site

on:
  push:
    branches:
      - main # use master instead if your repository uses master

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    steps:
      # 1. Check out the application repository
      - name: Checkout my-portfolio
        uses: actions/checkout@v4

      # 2. Check out the content repository (Private) directly into the content/ directory
      - name: Checkout my-portfolio-content
        uses: actions/checkout@v4
        with:
          repository: mosaos/my-portfolio-content # username/content repository name
          token: ${{ secrets.GH_PAT }}
          path: content

      # 3. Install Zola
      - name: Setup Zola
        uses: taiki-e/install-action@v2
        with:
          tool: zola@0.17.2 # Match the version used in the development environment

      # 4. Build the site with Zola
      - name: Build Zola site
        run: zola build

      # 5. Push the build output (public/) to the mosaos.github.io repository
      - name: Push to mosaos.github.io
        env:
          GH_TOKEN: ${{ secrets.GH_PAT }}
        run: |
          git config --global user.name "GitHub Actions Bot"
          git config --global user.email "actions@github.com"

          # Move to the public directory containing the build output
          cd public

          # Initialize it as a Git repository and push
          git init
          git checkout -b main
          git remote add origin https://x-access-token:${{ secrets.GH_PAT }}@github.com/mosaos/mosaos.github.io.git
          git add -A
          git commit -m "Deploy from my-portfolio CI/CD at $(date)"
          git push -f origin main

After creating the configuration file, commit and push it.

Before committing/pushing, change base_url in config.yml to the URL of your own GitHub Pages site.

If the Action runs successfully, everything is OK. At this point, if content has not been registered yet, the Action will fail, but after registering content, rerun it and make sure it completes successfully.

GitHub Pages Settings on the Deployment Destination (username.github.io)

  1. Open Settings > Pages in the username.github.io repository.
  2. Configure Build and deployment:
    • Source: Select Deploy from a branch.
    • Branch: Select main (or master) and / (root) as the folder, then click Save.

Triggering a Build When content Is Updated

With the configuration above, an update to my-portfolio (a push to main) triggers Actions.

Normally, it is more convenient for the site to be updated when content is updated.

In this case, add the following configuration to both the application-side (my-portfolio) and content-side (my-portfolio-content) repositories.

Application Side (my-portfolio)

Modify the on: section of .github/workflows/deploy.yml on the application side so that it can wait for a signal (repository_dispatch) from the content side.

.github/workflows/deploy.yml

Add the following near the beginning.

Register the GH_PAT secret in the same way as you did for the application-side repository.

name: Build and Deploy Zola Site

on:
  push:
    branches:
      - main # or master
  # Add a setting to receive events from an external repository (the content repository)
  repository_dispatch:
    types: [content_updated]

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    #  ( the rest is omitted )

Content Side (my-portfolio-content)

.github/workflows/deploy.yml

Create a new configuration file.

name: Trigger App Build on Content Push

on:
  push:
    branches:
      - main # Match the main branch used to manage articles (Markdown)

jobs:
  trigger_dispatch:
    runs-on: ubuntu-latest
    steps:
      - name: Repository Dispatch
        uses: peter-evans/repository-dispatch@v3
        with:
          token: ${{ secrets.GH_PAT }} # Register the same GH_PAT as a Secret on the content side
          repository: mosaos/my-portfolio # Target application-side repository
          event-type: content_updated # Must exactly match the name configured in types on the application side (be careful with hyphens)

Keeping Up with Updates to zola-daisyui-blog

Register the Upstream Repository

A repository created with Use this template is completely independent of the original repository, unlike a Fork.

If you want to keep your repository up to date with changes to the original template repository, set this up first.

Move to the root of the project you created:

cd my-portfolio

Add the upstream repository:

git remote add upstream https://github.com/mosaos/zola-daisyui-blog

You can check whether it was registered correctly with:

git remote -v

Apply Changes from the Original Template

First, fetch the changes:

git fetch upstream

With a normal merge, Git may consider the histories unrelated, so merge with --allow-unrelated-histories.

git merge upstream/main --allow-unrelated-histories

The changes from the original template will be merged. If there are conflicts between the parts you modified and the template updates, resolve them.

Once the conflicts have been resolved, commit the changes.

Finally, push them to your own repository and you are done.