[{"content":"I\u0026rsquo;d been telling myself I\u0026rsquo;d start a blog for months. Then one afternoon I decided to just do it — no more planning, no more comparing frameworks. A few hours later the site was live. This post is a record of that process: not a tutorial, more of an annotated changelog of mistakes and decisions.\nWhy Hugo I didn\u0026rsquo;t spend long choosing a static site generator. I\u0026rsquo;d used Hexo before and knew what Node.js dependency hell feels like. Jekyll is slow. Gatsby is overkill for a blog. Hugo is a single Go binary — brew install hugo and you\u0026rsquo;re done. No node_modules, no dependency conflicts, and builds so fast you barely notice them happening.\nbrew install hugo hugo version # hugo v0.160.0+extended darwin/arm64 That\u0026rsquo;s the entire install. The extended version includes built-in SCSS compilation, which the theme needs.\nFor the theme, I went with PaperMod. It\u0026rsquo;s clean, fast, and ships with everything I need out of the box: dark mode, search, table of contents, syntax highlighting, multilingual support. Added it as a git submodule so updates are just a git pull:\nhugo new site blog \u0026amp;\u0026amp; cd blog git init git submodule add --depth=1 https://github.com/adityatelange/hugo-PaperMod.git themes/PaperMod Configuration: One YAML File Does Most of the Work Hugo keeps everything in a single hugo.yaml (also supports toml and json — I prefer yaml). My blog is bilingual: Chinese as the default language at the root path, English under /en/. The language config looks like this:\ndefaultContentLanguage: zh defaultContentLanguageInSubdir: false # Chinese gets no prefix languages: zh: languageName: \u0026#34;中文\u0026#34; weight: 1 title: \u0026#34;Forest\u0026#39;s Blog\u0026#34; params: author: \u0026#34;北海\u0026#34; en: languageName: \u0026#34;EN\u0026#34; weight: 2 title: \u0026#34;Forest\u0026#39;s Blog\u0026#34; params: author: \u0026#34;Chunhao Zhang\u0026#34; Bilingual articles use filename suffixes: Chinese is build-blog-with-hugo.md, English is build-blog-with-hugo.en.md. Hugo automatically links them together for language switching.\nThough that \u0026ldquo;automatic linking\u0026rdquo; had a catch — more on that below.\nDeploying to Cloudflare Pages I chose Cloudflare Pages over GitHub Pages for two reasons: GitHub is unreliable from mainland China, and CF Pages has global CDN nodes with a simpler deploy workflow — just push code and it builds automatically.\nBut Cloudflare\u0026rsquo;s Dashboard design confused me for a bit.\nAfter clicking into \u0026ldquo;Workers \u0026amp; Pages\u0026rdquo;, the default view shows Workers (Serverless Functions). The Pages entry is buried at the bottom of the page as an unassuming \u0026ldquo;Looking to deploy Pages? Get started\u0026rdquo; link. I spent a few minutes thinking Pages had been merged into Workers before I spotted it.\nOnce past that, setup was straightforward: connect GitHub repo, select Hugo preset, build command hugo --minify, output directory public. There\u0026rsquo;s one critical environment variable you must set manually:\nVariable Value Why HUGO_VERSION 0.160.0 CF\u0026rsquo;s default Hugo version is outdated and will break the build After deployment I got a blog-6sm.pages.dev domain. Custom domains can be added later, but the free subdomain works fine for now.\nThe Language Switcher Bug After going live, I noticed an annoying bug: clicking the language toggle (中文 ↔ EN) on any article page would redirect to the homepage instead of the translated version of that article.\nDigging into PaperMod\u0026rsquo;s source, I found that the default header.html template uses site.Home.Translations for the language switcher — meaning it always points to the homepage translation, not the current page\u0026rsquo;s translation.\nThe fix was to create an override header.html in the project\u0026rsquo;s layouts/partials/ directory. Hugo\u0026rsquo;s template loading priority is project \u0026gt; theme, so you just copy the theme\u0026rsquo;s header and change one line:\n{{- $translations := .Translations }} {{- if not $translations }} {{- $translations = site.Home.Translations }} {{- end }} Prefer the current page\u0026rsquo;s .Translations, fall back to homepage only when there\u0026rsquo;s no translation available. Small change, but this is genuinely a design flaw in PaperMod — on a multilingual site, switching languages on an article page and landing on the homepage feels broken.\nComments with Giscus For comments I went with Giscus, which is powered by GitHub Discussions. No backend needed — comments live in the repo\u0026rsquo;s Discussions, which is the most natural setup for an open-source blog.\nOne non-obvious config choice: the Discussion category should be Announcements. This category restricts who can create new Discussions (only repo admins — corresponding to initializing a comment thread for an article), while still letting anyone reply. If you pick an open category like General, anyone can create arbitrary Discussions and things get messy.\nGiscus also needs dark mode adaptation. I used a MutationObserver in comments.html to watch for class changes on body and update the Giscus iframe theme dynamically:\nconst observer = new MutationObserver(() =\u0026gt; { const isDark = document.body.classList.contains(\u0026#39;dark\u0026#39;); const theme = isDark ? \u0026#39;noborder_dark\u0026#39; : \u0026#39;noborder_light\u0026#39;; const iframe = document.querySelector(\u0026#39;iframe.giscus-frame\u0026#39;); if (iframe) { iframe.contentWindow.postMessage( { giscus: { setConfig: { theme } } }, \u0026#39;https://giscus.app\u0026#39; ); } }); observer.observe(document.body, { attributes: true, attributeFilter: [\u0026#39;class\u0026#39;] }); This way, toggling dark mode updates the comment section in real time — no jarring white comment box on a dark page.\nMiscellaneous Setup KaTeX math rendering is conditionally loaded. Only articles with math: true in frontmatter pull in the KaTeX CSS and JS, so other pages aren\u0026rsquo;t slowed down.\nrobots.txt explicitly allows AI crawlers (GPTBot, ClaudeBot, PerplexityBot). More and more sites are blocking AI bots by default, but for a technical blog that wants to be cited by both humans and AI systems, open crawling makes sense.\nSyntax highlighting uses Hugo\u0026rsquo;s built-in Chroma engine with the dracula theme. PaperMod includes a code copy button out of the box.\nThe Final Structure Here\u0026rsquo;s what the project looks like:\nblog/ ├── hugo.yaml # Where all config lives ├── content/ │ ├── posts/ # Articles │ ├── about.md / about.en.md # About page │ ├── archives.md # Archive │ └── search.md # Search ├── layouts/partials/ │ ├── header.html # Language switcher fix │ ├── comments.html # Giscus comments │ ├── extend_head.html # KaTeX + Schema │ └── math.html # KaTeX scripts ├── static/ │ ├── favicon.ico # Globe icon │ └── _headers # CF caching policy └── themes/PaperMod/ # git submodule No bloat. The beauty of static sites is that the structure is transparent — no database, no server, no Docker. A YAML config, some Markdown files, a few HTML partials, and you have a complete website.\nLooking Back The whole process took an afternoon. The most time-consuming parts weren\u0026rsquo;t Hugo itself — Hugo\u0026rsquo;s documentation is solid and the learning curve is gentle — but rather the \u0026ldquo;should be simple but somehow isn\u0026rsquo;t\u0026rdquo; stuff: finding the Pages entry in Cloudflare\u0026rsquo;s Dashboard, the language switcher jumping to homepage, picking the wrong Giscus category.\nNone of these were hard problems. But they all required actually hitting the wall, spending time debugging, and figuring out the fix. Writing it down here so I don\u0026rsquo;t step on the same mines twice.\nBlog\u0026rsquo;s up. Time to write some real content.\n","permalink":"https://blog-6sm.pages.dev/en/posts/build-blog-with-hugo/","summary":"\u003cp\u003eI\u0026rsquo;d been telling myself I\u0026rsquo;d start a blog for months. Then one afternoon I decided to just do it — no more planning, no more comparing frameworks. A few hours later the site was live. This post is a record of that process: not a tutorial, more of an annotated changelog of mistakes and decisions.\u003c/p\u003e\n\u003ch2 id=\"why-hugo\"\u003eWhy Hugo\u003c/h2\u003e\n\u003cp\u003eI didn\u0026rsquo;t spend long choosing a static site generator. I\u0026rsquo;d used Hexo before and knew what Node.js dependency hell feels like. Jekyll is slow. Gatsby is overkill for a blog. Hugo is a single Go binary — \u003ccode\u003ebrew install hugo\u003c/code\u003e and you\u0026rsquo;re done. No \u003ccode\u003enode_modules\u003c/code\u003e, no dependency conflicts, and builds so fast you barely notice them happening.\u003c/p\u003e","title":"Building a Blog with Hugo + Cloudflare Pages"},{"content":"Welcome Welcome to my blog! I will share technical articles about AI, LLMs, and software engineering here.\nContent Direction This blog will cover the following areas:\nDeep Technical Articles: In-depth analysis of key technologies in AI/LLM Industry Insights: Tracking the latest developments and trends in AI Engineering Practices: Sharing experiences and best practices in software engineering Tech Stack This blog is built with:\nHugo — High-performance static site generator PaperMod — Clean and elegant Hugo theme Cloudflare Pages — Global CDN deployment # A sample code snippet def hello(): print(\u0026#34;Hello, World!\u0026#34;) hello() Next Steps Stay tuned for more content!\n","permalink":"https://blog-6sm.pages.dev/en/posts/hello-world/","summary":"\u003ch2 id=\"welcome\"\u003eWelcome\u003c/h2\u003e\n\u003cp\u003eWelcome to my blog! I will share technical articles about AI, LLMs, and software engineering here.\u003c/p\u003e\n\u003ch2 id=\"content-direction\"\u003eContent Direction\u003c/h2\u003e\n\u003cp\u003eThis blog will cover the following areas:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eDeep Technical Articles\u003c/strong\u003e: In-depth analysis of key technologies in AI/LLM\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eIndustry Insights\u003c/strong\u003e: Tracking the latest developments and trends in AI\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eEngineering Practices\u003c/strong\u003e: Sharing experiences and best practices in software engineering\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"tech-stack\"\u003eTech Stack\u003c/h2\u003e\n\u003cp\u003eThis blog is built with:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://gohugo.io/\"\u003eHugo\u003c/a\u003e — High-performance static site generator\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://github.com/adityatelange/hugo-PaperMod\"\u003ePaperMod\u003c/a\u003e — Clean and elegant Hugo theme\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://pages.cloudflare.com/\"\u003eCloudflare Pages\u003c/a\u003e — Global CDN deployment\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# A sample code snippet\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003edef\u003c/span\u003e \u003cspan class=\"nf\"\u003ehello\u003c/span\u003e\u003cspan class=\"p\"\u003e():\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nb\"\u003eprint\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;Hello, World!\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003ehello\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"next-steps\"\u003eNext Steps\u003c/h2\u003e\n\u003cp\u003eStay tuned for more content!\u003c/p\u003e","title":"Hello, World"},{"content":"About Me This is a placeholder for the about page. More details coming soon.\nContact GitHub: hahhforest ","permalink":"https://blog-6sm.pages.dev/en/about/","summary":"about","title":"About"}]