建立博客

Posted by     "LETTER" on Saturday, August 5, 2023

框架对比

框架静态/动态语言访问速度在线编辑特点
hexo静态nodejs非常快不可以文档、主题和插件支持多
hugo静态go不可以部署简单,页面生成快
Jekyll静态ruby不可以github支持使用 Jekyll 设置 GitHub Pages 站点参考
WordPress动态PHP可以灵活度和复杂度最高

博客建立

命令行

Hugo 仓库有预编译好的包releases,支持linux和window平台,可直接下载使用,window建议手动将hugo目录加入系统path路径下,方便后续使用。

Hugo 命令包含所有命令,实际用到就几个,如下:

  • hugo

    public/目录生成您的网站,已经准备好部署到您的web服务器上。

    运行hugo命令并没有删除以前构建生成的文件 。若运行hugo后生成网页不正常, 尝试删除 public/ 目录再次运行。

  • hugo server

    即时显示更新的内容,加上-D 可以渲染 draft。

  • hugo new post/new-content.md

    根据archetypes下的default.md生成新md文件。

主题

在建立博客时,一般使用已有主题模版构建,我这里使用hugo-theme-cleanwhite,也可以从Hugo Themes下载,然后按照主题模版修改配置hugo.toml,典型目录如下:

.
├── .github		# workflows action文件
├── content		# 博客内容,md文件
├── public		# hugo编译生成
├── static		# 放置图像附件等
├── themes		# 主题
└── hugo.toml	# hugo配置

github

参考host-on-github-pages,构建action实现代码上传后自动build和deploy。

  1. GitHub page选择GitHub Actions

  2. 修改hugo.toml配置文件,增加内容

    [caches]
      [caches.images]
        dir = ':cacheDir/images'
    
  3. 构建workflows,创建文件.github/workflows/hugo.yaml,编写内容如下

    name: Build and deploy
    on:
      push:
        branches:
          - main
      workflow_dispatch:
    permissions:
      contents: read
      pages: write
      id-token: write
    concurrency:
      group: pages
      cancel-in-progress: false
    defaults:
      run:
        shell: bash
    jobs:
      build:
        runs-on: ubuntu-latest
        env:
          DART_SASS_VERSION: 1.93.2
          GO_VERSION: 1.25.3
          HUGO_VERSION: 0.152.2
          NODE_VERSION: 22.20.0
          TZ: Europe/Oslo
        steps:
          - name: Checkout
            uses: actions/checkout@v5
            with:
              submodules: recursive
              fetch-depth: 0
          - name: Setup Go
            uses: actions/setup-go@v5
            with:
              go-version: ${{ env.GO_VERSION }}
              cache: false
          - name: Setup Node.js
            uses: actions/setup-node@v4
            with:
              node-version: ${{ env.NODE_VERSION }}
          - name: Setup Pages
            id: pages
            uses: actions/configure-pages@v5
          - name: Create directory for user-specific executable files
            run: |
              mkdir -p "${HOME}/.local"
          - name: Install Dart Sass
            run: |
              curl -sLJO "https://github.com/sass/dart-sass/releases/download/${DART_SASS_VERSION}/dart-sass-${DART_SASS_VERSION}-linux-x64.tar.gz"
              tar -C "${HOME}/.local" -xf "dart-sass-${DART_SASS_VERSION}-linux-x64.tar.gz"
              rm "dart-sass-${DART_SASS_VERSION}-linux-x64.tar.gz"
              echo "${HOME}/.local/dart-sass" >> "${GITHUB_PATH}"
          - name: Install Hugo
            run: |
              curl -sLJO "https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_extended_${HUGO_VERSION}_linux-amd64.tar.gz"
              mkdir "${HOME}/.local/hugo"
              tar -C "${HOME}/.local/hugo" -xf "hugo_extended_${HUGO_VERSION}_linux-amd64.tar.gz"
              rm "hugo_extended_${HUGO_VERSION}_linux-amd64.tar.gz"
              echo "${HOME}/.local/hugo" >> "${GITHUB_PATH}"
          - name: Verify installations
            run: |
              echo "Dart Sass: $(sass --version)"
              echo "Go: $(go version)"
              echo "Hugo: $(hugo version)"
              echo "Node.js: $(node --version)"
          - name: Install Node.js dependencies
            run: |
              [[ -f package-lock.json || -f npm-shrinkwrap.json ]] && npm ci || true
          - name: Configure Git
            run: |
              git config core.quotepath false
          - name: Cache restore
            id: cache-restore
            uses: actions/cache/restore@v4
            with:
              path: ${{ runner.temp }}/hugo_cache
              key: hugo-${{ github.run_id }}
              restore-keys:
                hugo-
          - name: Build the site
            run: |
              hugo \
                --gc \
                --minify \
                --baseURL "${{ steps.pages.outputs.base_url }}/" \
                --cacheDir "${{ runner.temp }}/hugo_cache"
          - name: Cache save
            id: cache-save
            uses: actions/cache/save@v4
            with:
              path: ${{ runner.temp }}/hugo_cache
              key: ${{ steps.cache-restore.outputs.cache-primary-key }}
          - name: Upload artifact
            uses: actions/upload-pages-artifact@v3
            with:
              path: ./public
      deploy:
        environment:
          name: github-pages
          url: ${{ steps.deployment.outputs.page_url }}
        runs-on: ubuntu-latest
        needs: build
        steps:
          - name: Deploy to GitHub Pages
            id: deployment
            uses: actions/deploy-pages@v4
    

评论系统

使用Giscus 作为评论系统,参考Hugo 博客引入 Giscus 评论系统,hugo-theme-cleanwhite中已有配置,按步骤启用即可。

  1. Install the Giscus app on your GitHub repo

  2. 仓库开启Discussions

  3. 从 giscus 官网获取配置信息然后在目录layouts\partials\comments.html中修改为对应信息

      [params.giscus]
      data_repo="your GitHub repo"
      data_repo_id="your repo id"
      data_category="your category"
      data_category_id="your category id"
      data_mapping="pathname"
      data_reactions_enabled="1"
      data_emit_metadata="0"
      data_theme="light"
      data_lang="en"
      crossorigin="anonymous"
    
  4. [params]设置giscus = true

站点统计

使用https://busuanzi.ibruce.info/,添加到layouts\partials\footer.html里面即可。

Latex显示

参考Mathematics in Markdownhugo 如何使用 KaTeX 来显示数学公式,hugo支持KaTeX和MathJax,hugo-theme-cleanwhite中默认支持KaTeX,但不支持内联,所以需手动增加:

math/katex-render.html

<script>
  document.addEventListener("DOMContentLoaded", function() {
    if (typeof renderMathInElement !== "undefined") {
      renderMathInElement(document.body, {
        delimiters: [
          // Display mode delimiters
          { left: "$$", right: "$$", display: true },
          { left: "\\[", right: "\\]", display: true },
          // Inline mode delimiters
          { left: "$", right: "$", display: false },
          { left: "\\(", right: "\\)", display: false }
        ],
        throwOnError: false
      });
    }
  });
</script>

math/katex-css.html新增内容

<!-- KaTeX JavaScript Library -->
{{ $jsFile := cond hugo.IsProduction "katex.min.js" "katex.js" -}}
{{ $jsUrl := printf "https://unpkg.com/katex@latest/dist/%s" $jsFile -}}
{{ with try (resources.GetRemote $jsUrl) -}}
  {{ with .Err -}}
    {{ errorf "Could not retrieve KaTeX js file from CDN. Reason: %s." . -}}
  {{ else with .Value -}}
    {{ with resources.Copy (printf "js/%s" $jsFile) . -}}
      {{ $jsHash := . | fingerprint "sha512" -}}
<script defer src="{{- .RelPermalink -}}" integrity="{{- $jsHash.Data.Integrity -}}" crossorigin="anonymous"></script>
    {{ end -}}
  {{ else -}}
    {{ errorf "Could not retrieve js file %q from CDN. Reason: invalid KaTeX version %q." $jsUrl "latest" -}}
  {{ end -}}
{{ end -}}

<!-- KaTeX Auto-render Extension -->
{{ $autoRenderFile := cond hugo.IsProduction "auto-render.min.js" "auto-render.js" -}}
{{ $autoRenderUrl := printf "https://unpkg.com/katex@latest/dist/contrib/%s" $autoRenderFile -}}
{{ with try (resources.GetRemote $autoRenderUrl) -}}
  {{ with .Err -}}
    {{ errorf "Could not retrieve KaTeX auto-render file from CDN. Reason: %s." . -}}
  {{ else with .Value -}}
    {{ with resources.Copy (printf "js/%s" $autoRenderFile) . -}}
      {{ $autoRenderHash := . | fingerprint "sha512" -}}
<script defer src="{{- .RelPermalink -}}" integrity="{{- $autoRenderHash.Data.Integrity -}}" crossorigin="anonymous"></script>
    {{ end -}}
  {{ else -}}
    {{ errorf "Could not retrieve auto-render file %q from CDN. Reason: invalid KaTeX version %q." $autoRenderUrl "latest" -}}
  {{ end -}}
{{ end -}}

head.html增加katex-render.html

    <!-- KaTeX CSS  -->
    {{ $noop := .WordCount }}
    {{ if .Page.Store.Get "hasMath" -}}
        {{ partial "math/katex-css.html" . -}}
        {{ partial "math/katex-fonts.html" . -}}
        {{ partial "math/katex-render.html" . -}}
    {{ end -}}

内容管理

参考Page bundles

Leaf Bundles 单篇文章

适用于单个、独立的、不包含子页面的内容项。

content/
└── posts/
    └── my-article/          <-- **叶子包目录** (URL Segment: /posts/my-article/)
        ├── index.md         <-- **文章内容** (必需,告诉 Hugo 这是一个单页)
        └── images/          <-- **文章专有图片目录** (可选,但推荐)
            ├── main-photo.jpg
            └── graph.png
        └── assets/          <-- **其他资源** (如 PDF、JS、特殊 CSS)
            └── related-doc.pdf

关键点

  • 文件名: index.md 必须存在。

  • 引用方式: 在 index.md 中,资源通过相对路径引用(例如:images/main-photo.jpg)。

  • 输出 URL: 页面 URL 通常指向目录名(例如 /posts/my-article/)。

Branch Bundles 章节或列表页

适用于章节首页列表页(如博客文章列表页)或作为包含其他子页面的容器

content/
└── products/                 <-- **分支包目录** (URL Segment: /products/)
    ├── _index.md             <-- **章节或列表页内容** (必需,告诉 Hugo 这是一个列表页)
    └── banner.jpg            <-- **章节列表页专有图片**
    └── specific-product-1/   <-- 子页面 (另一个叶子包或普通 Markdown)
        └── index.md
    └── specific-product-2/   <-- 子页面
        └── index.md

关键点

  • 文件名: index.md 必须存在。

  • 引用方式:目录内的资源(如 banner.jpg)是列表页章节页独有的。

  • 输出 URL: 页面 URL 通常指向目录名(例如 /products/)。

static 共享资源

不属于任何特定文章的共享资源

static/
├── images/                   <-- 全局共享图片 (如 Logo, Favicon)
│   └── site-logo.png
└── css/                      <-- 自定义全局 CSS
    └── custom.css

关键点

  • 引用方式: 在 Markdown 或模板中,必须使用绝对路径省略 static(例如:/images/site-logo.png)。