<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title>D1 - Tag - Simon's Blog</title><link>https://blog.leeissonba.com/en/tags/d1/</link><description>D1 - Tag - Simon's Blog</description><generator>Hugo -- gohugo.io</generator><language>en</language><managingEditor>leeissonba@gmail.com (Simon)</managingEditor><webMaster>leeissonba@gmail.com (Simon)</webMaster><copyright>Simon</copyright><lastBuildDate>Mon, 13 Jul 2026 09:44:50 +0800</lastBuildDate><atom:link href="https://blog.leeissonba.com/en/tags/d1/" rel="self" type="application/rss+xml"/><item><title>Hugo + LoveIt Blog Optimization Notes: From Setup to a Reproducible Config</title><link>https://blog.leeissonba.com/en/hugo-loveit-blog-optimization-notes/</link><pubDate>Mon, 13 Jul 2026 09:44:50 +0800</pubDate><author>leeissonba@gmail.com (Simon)</author><guid>https://blog.leeissonba.com/en/hugo-loveit-blog-optimization-notes/</guid><description><![CDATA[<div class="featured-image">
                <img src="https://blog.leeissonba.com/images/posts/hugo-loveit-blog-optimization-notes/featured.jpg" alt="Hugo &#43; LoveIt Blog Optimization Notes: From Setup to a Reproducible Config" referrerpolicy="no-referrer">
            </div><p>A practical recap of the optimizations applied to this site, so the setup can be reproduced against the current repository.</p>
<ul>
<li>Site: <a href="https://blog.leeissonba.com/" target="_blank" rel="noopener noreffer ">https://blog.leeissonba.com/</a></li>
<li>Theme: <a href="https://github.com/dillonzq/LoveIt" target="_blank" rel="noopener noreffer ">LoveIt</a> · Hosting: Cloudflare Workers static assets</li>
<li>Repo: <a href="https://github.com/simonlee-hello/MyBlog" target="_blank" rel="noopener noreffer ">https://github.com/simonlee-hello/MyBlog</a></li>
</ul>
<h2 id="1-background-and-goals">1. Background and goals</h2>
<p>This personal blog runs on Hugo Extended + LoveIt, with these requirements:</p>
<ul>
<li>Chinese as the default language, with an English switch</li>
<li>Draft in Obsidian / Typora, then auto-fill front matter, cover image, English version, and publish</li>
<li>Deploy on Cloudflare with a custom domain</li>
<li>Comments, on-page counters, and backend analytics each in place</li>
<li>Code blocks and videos that do not break the layout</li>
</ul>
<p>Each section lists paths and config points that match the current repo.</p>
<hr>
<h2 id="2-project-layout-and-local-commands">2. Project layout and local commands</h2>
<p>This chapter defines the repository layout, local commands, and ignore rules—the baseline for template overrides, styles, and deploy.</p>
<h3 id="21-key-directories">2.1 Key directories</h3>
<div class="code-block code-line-numbers open" style="counter-reset: code-block 0">
    <div class="code-header language-text">
        <span class="code-title"><i class="arrow fas fa-angle-right" aria-hidden="true"></i></span>
        <span class="ellipses"><i class="fas fa-ellipsis-h" aria-hidden="true"></i></span>
        <span class="copy" title="Copy to clipboard"><i class="far fa-copy" aria-hidden="true"></i></span>
    </div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">.
</span></span><span class="line"><span class="cl">├── archetypes/          # new-post templates
</span></span><span class="line"><span class="cl">├── assets/css/          # _custom.scss theme overrides
</span></span><span class="line"><span class="cl">├── content/posts/       # posts (zh .md / en .en.md)
</span></span><span class="line"><span class="cl">├── drafts/              # local drafts (gitignored)
</span></span><span class="line"><span class="cl">├── layouts/             # theme overrides (do not edit themes/LoveIt)
</span></span><span class="line"><span class="cl">├── static/              # images, videos, favicon
</span></span><span class="line"><span class="cl">├── themes/LoveIt/       # Git submodule
</span></span><span class="line"><span class="cl">├── .cursor/skills/      # hugo-blog-publish / loveit-theme
</span></span><span class="line"><span class="cl">├── build.sh / wrangler.jsonc / package.json  # Cloudflare build
</span></span><span class="line"><span class="cl">├── hugo.toml
</span></span><span class="line"><span class="cl">└── Makefile</span></span></code></pre></div></div>
<h3 id="22-common-commands">2.2 Common commands</h3>
<div class="code-block code-line-numbers open" style="counter-reset: code-block 0">
    <div class="code-header language-bash">
        <span class="code-title"><i class="arrow fas fa-angle-right" aria-hidden="true"></i></span>
        <span class="ellipses"><i class="fas fa-ellipsis-h" aria-hidden="true"></i></span>
        <span class="copy" title="Copy to clipboard"><i class="far fa-copy" aria-hidden="true"></i></span>
    </div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">make dev      <span class="c1"># hugo server -D</span>
</span></span><span class="line"><span class="cl">make build    <span class="c1"># HUGO_ENV=production hugo --minify</span>
</span></span><span class="line"><span class="cl">make clean</span></span></code></pre></div></div>
<div class="details admonition note open">
    <div class="details-summary admonition-title">
        <i class="icon far fa-pen-to-square" aria-hidden="true"></i>Note<i class="details-icon fas fa-angle-right" aria-hidden="true"></i>
    </div>
    <div class="details-content">
        <div class="admonition-content">LoveIt loads comments, CDN, and some analytics scripts only when <code>hugo.Environment == production</code>. To verify comments locally, run: <code>HUGO_ENV=production hugo server</code></div>
    </div>
</div>
<h3 id="23-gitignore">2.3 <code>.gitignore</code></h3>
<p><code>public/</code>, <code>resources/</code>, <code>.hugo_build.lock</code>, <code>.cache/</code>, and <code>drafts/</code> are ignored.</p>
<ul>
<li><strong>Does not block deploy</strong>: Cloudflare rebuilds <code>public/</code> with <code>hugo build</code> in CI; the repo does not need build artifacts.</li>
<li>Keep <code>drafts/</code> local; publish into <code>content/posts/</code> after review.</li>
</ul>
<hr>
<h2 id="3-fixing-hugo-deprecation-warnings">3. Fixing Hugo deprecation warnings</h2>
<p>Newer Hugo warns about <code>.Site.LanguageCode</code>, <code>.Language.LanguageName</code>, <code>.Sites</code>, and the <code>languageCode</code> config key.</p>
<p><strong>Rule</strong>: do not edit the theme submodule; override templates under project <code>layouts/</code>.</p>
<table>
	<thead>
			<tr>
					<th>Override file</th>
					<th>Change</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td><code>layouts/baseof.html</code></td>
					<td>use <code>.Site.Language.Locale</code> for <code>lang</code></td>
			</tr>
			<tr>
					<td><code>layouts/_partials/header.html</code></td>
					<td>language switch via <code>hugo.Sites</code> and <code>.Language.Label</code></td>
			</tr>
			<tr>
					<td><code>layouts/_partials/head/seo.html</code></td>
					<td>Locale as above</td>
			</tr>
			<tr>
					<td><code>layouts/_partials/init.html</code></td>
					<td>drop noisy dev warnings; attach comment / analytics in production</td>
			</tr>
			<tr>
					<td><code>layouts/home.rss.xml</code> and other RSS</td>
					<td>Locale as above</td>
			</tr>
	</tbody>
</table>
<p>On the config side, use <code>locale</code> (this site: Chinese <code>zh-CN</code>, English <code>en</code>) instead of deprecated <code>languageCode</code>.</p>
<hr>
<h2 id="4-chinese-default-and-bilingual-content-rules">4. Chinese default and bilingual content rules</h2>
<p>Default language and file naming must stay consistent, or the language switch shows an empty post list.</p>
<h3 id="41-site-languages">4.1 Site languages</h3>
<p>In <code>hugo.toml</code>:</p>
<ul>
<li><code>defaultContentLanguage = &quot;zh-cn&quot;</code></li>
<li><code>[languages.zh-cn]</code> with a smaller weight (primary)</li>
<li><code>[languages.en]</code> for the English site</li>
</ul>
<h3 id="42-file-naming-important">4.2 File naming (important)</h3>
<p>When Chinese is the default:</p>
<table>
	<thead>
			<tr>
					<th>Language</th>
					<th>Path</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td>Chinese</td>
					<td><code>content/posts/{slug}.md</code> (<strong>do not</strong> use <code>.zh-cn.md</code>)</td>
			</tr>
			<tr>
					<td>English</td>
					<td><code>content/posts/{slug}.en.md</code></td>
			</tr>
	</tbody>
</table>
<p>About pages follow the same pattern: <code>content/about/index.md</code> + <code>index.en.md</code>.</p>
<p>If English lives in bare <code>.md</code> and Chinese in <code>.zh-cn.md</code>, switching to <code>/en/</code> will hide English posts—an early footgun on this site.</p>
<h3 id="43-social-links">4.3 Social links</h3>
<p>Set <code>[params.home.profile] social = true</code> and configure <code>[params.social]</code> (GitHub, Email, RSS, etc.). Icons appear on the home profile only then.</p>
<hr>
<h2 id="5-writing-and-publish-workflow">5. Writing and publish workflow</h2>
<p>Conventions from draft to live: front matter, covers, media paths, and how Cursor skills help publish.</p>
<h3 id="51-minimal-publish-flow">5.1 Minimal publish flow</h3>
<ol>
<li>Write Chinese Markdown in Obsidian / Typora / <code>drafts/</code></li>
<li>Publish with Cursor skill <strong><code>hugo-blog-publish</code></strong> (default: front matter, cover, English translation, <code>hugo build</code>, commit + push)</li>
<li>Skip push when only local verification is requested; skip <code>.en.md</code> when Chinese-only is requested</li>
</ol>
<h3 id="52-front-matter-convention">5.2 Front matter convention</h3>
<div class="code-block code-line-numbers open" style="counter-reset: code-block 0">
    <div class="code-header language-yaml">
        <span class="code-title"><i class="arrow fas fa-angle-right" aria-hidden="true"></i></span>
        <span class="ellipses"><i class="fas fa-ellipsis-h" aria-hidden="true"></i></span>
        <span class="copy" title="Copy to clipboard"><i class="far fa-copy" aria-hidden="true"></i></span>
    </div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nn">---</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">title</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">date</span><span class="p">:</span><span class="w"> </span><span class="ld">2026-07-13T12:00:00</span><span class="m">+08</span><span class="p">:</span><span class="m">00</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">draft</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">description</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">categories</span><span class="p">:</span><span class="w"> </span><span class="p">[]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">tags</span><span class="p">:</span><span class="w"> </span><span class="p">[]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">featuredImage</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;/images/posts/{slug}/featured.jpg&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">featuredImagePreview</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;/images/posts/{slug}/featured.jpg&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nn">---</span></span></span></code></pre></div></div>
<ul>
<li>Insert <code>&lt;!--more--&gt;</code> after the first paragraph for the summary</li>
<li>Chinese and English share the same cover / media paths</li>
</ul>
<h3 id="53-media-paths">5.3 Media paths</h3>
<table>
	<thead>
			<tr>
					<th>Type</th>
					<th>Directory</th>
					<th>In-content URL</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td>Cover / images</td>
					<td><code>static/images/posts/{slug}/</code></td>
					<td><code>/images/posts/{slug}/...</code></td>
			</tr>
			<tr>
					<td>Videos</td>
					<td><code>static/videos/posts/{slug}/</code></td>
					<td><code>/videos/posts/{slug}/...</code></td>
			</tr>
	</tbody>
</table>
<p>Recommended video markup:</p>
<div class="code-block code-line-numbers open" style="counter-reset: code-block 0">
    <div class="code-header language-html">
        <span class="code-title"><i class="arrow fas fa-angle-right" aria-hidden="true"></i></span>
        <span class="ellipses"><i class="fas fa-ellipsis-h" aria-hidden="true"></i></span>
        <span class="copy" title="Copy to clipboard"><i class="far fa-copy" aria-hidden="true"></i></span>
    </div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl"><span class="p">&lt;</span><span class="nt">video</span> <span class="na">controls</span> <span class="na">playsinline</span> <span class="na">preload</span><span class="o">=</span><span class="s">&#34;metadata&#34;</span> <span class="na">src</span><span class="o">=</span><span class="s">&#34;/videos/posts/{slug}/demo.mp4&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">video</span><span class="p">&gt;</span></span></span></code></pre></div></div>
<p>External image URLs and Bilibili / YouTube embeds stay as-is; Bilibili can use LoveIt&rsquo;s <code>bilibili</code> shortcode.</p>
<h3 id="54-loveit-writing-skill">5.4 LoveIt writing skill</h3>
<p>There is also a <strong><code>loveit-theme</code></strong> skill (linked from publish): quick reference for admonition, image, mermaid, math, Giscus, visit counters, and more. Publish may lightly upgrade tips to <code>admonition</code> or Bilibili links to shortcodes.</p>
<p>Official docs: <a href="https://hugoloveit.com" target="_blank" rel="noopener noreffer ">LoveIt</a>.</p>
<hr>
<h2 id="6-layout-fixes-code-and-video">6. Layout fixes: code and video</h2>
<p>Production issues: long code lines overflow the code box; <code>&lt;video&gt;</code> width did not match content width. Fixed in <code>assets/css/_custom.scss</code>:</p>
<ul>
<li>Code blocks: <code>max-width: 100%</code>, <code>overflow-x: auto</code>, <code>pre-wrap</code> when needed</li>
<li><code>video</code>: <code>width/max-width: 100%</code>, <code>display: block</code>, <code>height: auto</code></li>
</ul>
<p>Still wrap extremely long command lines in the source for readability.</p>
<hr>
<h2 id="7-deploy-to-cloudflare-workers">7. Deploy to Cloudflare Workers</h2>
<p>Static hosting follows the <a href="https://gohugo.io/host-and-deploy/host-on-cloudflare/" target="_blank" rel="noopener noreffer ">official Hugo Cloudflare guide</a>; this site uses Workers static assets.</p>
<h3 id="71-repo-files">7.1 Repo files</h3>
<table>
	<thead>
			<tr>
					<th>File</th>
					<th>Role</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td><code>wrangler.jsonc</code></td>
					<td>Worker name (e.g. <code>simons-blog</code>), <code>assets.directory = ./public</code></td>
			</tr>
			<tr>
					<td><code>build.sh</code></td>
					<td>Install Hugo Extended, update submodule, <code>HUGO_ENV=production hugo build</code></td>
			</tr>
			<tr>
					<td><code>package.json</code></td>
					<td>Helps enable build cache</td>
			</tr>
	</tbody>
</table>
<p>The Cloudflare project name should match <code>name</code> in <code>wrangler.jsonc</code>.</p>
<h3 id="72-dashboard-notes">7.2 Dashboard notes</h3>
<ul>
<li>Static-only Worker: <strong>do not</strong> set <code>HUGO_BASEURL</code> under runtime Variables and Secrets</li>
<li>Put build-related vars under <strong>Build variables</strong>, or hardcode <code>baseURL</code> in <code>hugo.toml</code> (this site uses <code>https://blog.leeissonba.com</code>)</li>
<li>Bind the custom domain under Workers → Domains</li>
</ul>
<h3 id="73-submodule">7.3 Submodule</h3>
<p>The theme is a submodule. Cloudflare build must run <code>git submodule update --init --recursive</code>; local clones need the submodule too.</p>
<hr>
<h2 id="8-comments-giscus">8. Comments: Giscus</h2>
<p>Valine (LeanCloud) was considered; the site settled on <a href="https://giscus.app/" target="_blank" rel="noopener noreffer ">Giscus</a> (GitHub Discussions).</p>
<h3 id="81-prerequisites">8.1 Prerequisites</h3>
<ol>
<li>Repository is <strong>Public</strong></li>
<li><strong>Discussions</strong> enabled</li>
<li>Install the <a href="https://github.com/apps/giscus" target="_blank" rel="noopener noreffer ">giscus GitHub App</a> and grant this repo</li>
</ol>
<h3 id="82-site-config-hugotoml">8.2 Site config (<code>hugo.toml</code>)</h3>
<div class="code-block code-line-numbers open" style="counter-reset: code-block 0">
    <div class="code-header language-toml">
        <span class="code-title"><i class="arrow fas fa-angle-right" aria-hidden="true"></i></span>
        <span class="ellipses"><i class="fas fa-ellipsis-h" aria-hidden="true"></i></span>
        <span class="copy" title="Copy to clipboard"><i class="far fa-copy" aria-hidden="true"></i></span>
    </div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-toml" data-lang="toml"><span class="line"><span class="cl"><span class="p">[</span><span class="nx">params</span><span class="p">.</span><span class="nx">page</span><span class="p">.</span><span class="nx">comment</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">  <span class="nx">enable</span> <span class="p">=</span> <span class="kc">true</span>
</span></span><span class="line"><span class="cl">  <span class="p">[</span><span class="nx">params</span><span class="p">.</span><span class="nx">page</span><span class="p">.</span><span class="nx">comment</span><span class="p">.</span><span class="nx">giscus</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="nx">enable</span> <span class="p">=</span> <span class="kc">true</span>
</span></span><span class="line"><span class="cl">    <span class="nx">repo</span> <span class="p">=</span> <span class="s2">&#34;simonlee-hello/MyBlog&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="nx">repoId</span> <span class="p">=</span> <span class="s2">&#34;R_kgDOTVNnWg&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="nx">category</span> <span class="p">=</span> <span class="s2">&#34;Announcements&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="nx">categoryId</span> <span class="p">=</span> <span class="s2">&#34;DIC_kwDOTVNnWs4DBC6N&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="nx">mapping</span> <span class="p">=</span> <span class="s2">&#34;pathname&#34;</span></span></span></code></pre></div></div>
<p><code>repoId</code> / <code>categoryId</code> are public GitHub GraphQL node IDs. They appear in page source and are <strong>not secrets</strong>—safe to publish with the site config.</p>
<p>Disable per page with <code>comment: false</code>.<br>
Loaded only in production builds; locally use <code>HUGO_ENV=production</code>.</p>
<p>Comment data lives in the repo&rsquo;s Discussions.</p>
<hr>
<h2 id="9-analytics-two-complementary-layers">9. Analytics: two complementary layers</h2>
<table>
	<thead>
			<tr>
					<th>Purpose</th>
					<th>Tool</th>
					<th>Notes</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td>Owner dashboard</td>
					<td>Cloudflare Web Analytics</td>
					<td>Zone covers <code>leeissonba.com</code>; <code>blog.*</code> traffic already shows up—filter by Host</td>
			</tr>
			<tr>
					<td>On-page numbers</td>
					<td>Self-hosted Worker + D1 (<code>services/web-analytics</code>)</td>
					<td>Footer site PV/UV + post meta page views; you own the data</td>
			</tr>
	</tbody>
</table>
<p>Cloudflare Web Analytics <strong>cannot</strong> render counts on the public page (no public front-end API). Busuanzi/Vercount were tried earlier and dropped because third-party counters can reset.</p>
<p>This site follows <a href="https://github.com/yestool/analytics_with_cloudflare" target="_blank" rel="noopener noreffer ">analytics_with_cloudflare</a>, with site-wide <code>spv</code> / <code>suv</code> as in <a href="https://bytejog.com/posts/hugo/hugo_analytics/" target="_blank" rel="noopener noreffer ">Hugo self-hosted visit counters</a>. Reproduce against the repository.</p>
<h3 id="91-architecture">9.1 Architecture</h3>
<ul>
<li><strong>Separate Worker</strong> <code>web-analytics</code> (not the blog static Worker <code>myblog</code> / <code>simons-blog</code>)</li>
<li><strong>D1</strong> database <code>web_analytics</code> stores visits</li>
<li>Browser <code>POST /api/visit</code>: insert one row; optionally return page <code>pv</code> and site <code>spv</code> / <code>suv</code></li>
<li>Hugo loads the script only in <strong>production</strong> (same gate as Giscus)</li>
</ul>
<h3 id="92-deploy-the-counter-api-cloudflare">9.2 Deploy the counter API (Cloudflare)</h3>
<p>Work in the subdirectory (do not confuse with the root Hugo <code>wrangler.jsonc</code>):</p>
<div class="code-block code-line-numbers open" style="counter-reset: code-block 0">
    <div class="code-header language-bash">
        <span class="code-title"><i class="arrow fas fa-angle-right" aria-hidden="true"></i></span>
        <span class="ellipses"><i class="fas fa-ellipsis-h" aria-hidden="true"></i></span>
        <span class="copy" title="Copy to clipboard"><i class="far fa-copy" aria-hidden="true"></i></span>
    </div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nb">cd</span> services/web-analytics
</span></span><span class="line"><span class="cl">npm install
</span></span><span class="line"><span class="cl">npx wrangler login
</span></span><span class="line"><span class="cl">npx wrangler d1 create web_analytics
</span></span><span class="line"><span class="cl"><span class="c1"># Write the returned database_id into this directory&#39;s wrangler.jsonc</span>
</span></span><span class="line"><span class="cl">npm run initSql
</span></span><span class="line"><span class="cl">npm run deploy</span></span></code></pre></div></div>
<p>Notes:</p>
<ul>
<li><code>npm run deploy</code> passes <code>--config wrangler.jsonc</code>. Using the repo-root config will try Hugo&rsquo;s <code>build.sh</code> and fail</li>
<li>Dashboard → Workers → <code>web-analytics</code> → add a custom domain such as <code>analytics.leeissonba.com</code> (<code>workers.dev</code> is blocked in some regions)</li>
<li>Smoke test: <code>POST https://analytics.your-domain/api/visit</code> with <code>hostname</code>, <code>url</code>, <code>spv: true</code>, etc.; expect <code>{&quot;ret&quot;:&quot;OK&quot;,&quot;data&quot;:{...}}</code></li>
</ul>
<h3 id="93-wire-hugo-front-end">9.3 Wire Hugo front end</h3>
<p>Key files:</p>
<table>
	<thead>
			<tr>
					<th>Path</th>
					<th>Role</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td><code>services/web-analytics/</code></td>
					<td>Worker + D1 source and <code>wrangler.jsonc</code></td>
			</tr>
			<tr>
					<td><code>assets/js/analytics.js</code></td>
					<td>Call API; fill <code>#page_pv</code> / <code>#site_pv</code> / <code>#site_uv</code></td>
			</tr>
			<tr>
					<td><code>layouts/_partials/plugin/web-analytics.html</code></td>
					<td>Inject fingerprinted script in production only</td>
			</tr>
			<tr>
					<td><code>layouts/_partials/footer.html</code></td>
					<td>Site PV/UV placeholders + load script once</td>
			</tr>
			<tr>
					<td><code>layouts/posts/single.html</code></td>
					<td>Post meta “views” <code>#page_pv</code></td>
			</tr>
			<tr>
					<td><code>hugo.toml</code> → <code>[params.webAnalytics]</code></td>
					<td>Toggle and <code>baseURL</code></td>
			</tr>
	</tbody>
</table>
<p>Config example:</p>
<div class="code-block code-line-numbers open" style="counter-reset: code-block 0">
    <div class="code-header language-toml">
        <span class="code-title"><i class="arrow fas fa-angle-right" aria-hidden="true"></i></span>
        <span class="ellipses"><i class="fas fa-ellipsis-h" aria-hidden="true"></i></span>
        <span class="copy" title="Copy to clipboard"><i class="far fa-copy" aria-hidden="true"></i></span>
    </div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-toml" data-lang="toml"><span class="line"><span class="cl"><span class="p">[</span><span class="nx">params</span><span class="p">.</span><span class="nx">webAnalytics</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">  <span class="nx">enable</span> <span class="p">=</span> <span class="kc">true</span>
</span></span><span class="line"><span class="cl">  <span class="nx">baseURL</span> <span class="p">=</span> <span class="s2">&#34;https://analytics.leeissonba.com&#34;</span>  <span class="c"># must match custom domain</span></span></span></code></pre></div></div>
<p>Footer placeholders:</p>
<div class="code-block code-line-numbers open" style="counter-reset: code-block 0">
    <div class="code-header language-html">
        <span class="code-title"><i class="arrow fas fa-angle-right" aria-hidden="true"></i></span>
        <span class="ellipses"><i class="fas fa-ellipsis-h" aria-hidden="true"></i></span>
        <span class="copy" title="Copy to clipboard"><i class="far fa-copy" aria-hidden="true"></i></span>
    </div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl">Site visits <span class="p">&lt;</span><span class="nt">span</span> <span class="na">id</span><span class="o">=</span><span class="s">&#34;site_pv&#34;</span><span class="p">&gt;</span>-<span class="p">&lt;/</span><span class="nt">span</span><span class="p">&gt;</span> · Visitors <span class="p">&lt;</span><span class="nt">span</span> <span class="na">id</span><span class="o">=</span><span class="s">&#34;site_uv&#34;</span><span class="p">&gt;</span>-<span class="p">&lt;/</span><span class="nt">span</span><span class="p">&gt;</span></span></span></code></pre></div></div>
<p>Post meta placeholder:</p>
<div class="code-block code-line-numbers open" style="counter-reset: code-block 0">
    <div class="code-header language-html">
        <span class="code-title"><i class="arrow fas fa-angle-right" aria-hidden="true"></i></span>
        <span class="ellipses"><i class="fas fa-ellipsis-h" aria-hidden="true"></i></span>
        <span class="copy" title="Copy to clipboard"><i class="far fa-copy" aria-hidden="true"></i></span>
    </div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-html" data-lang="html"><span class="line"><span class="cl">Views <span class="p">&lt;</span><span class="nt">span</span> <span class="na">id</span><span class="o">=</span><span class="s">&#34;page_pv&#34;</span><span class="p">&gt;</span>-<span class="p">&lt;/</span><span class="nt">span</span><span class="p">&gt;</span></span></span></code></pre></div></div>
<p>Implementation notes:</p>
<ul>
<li>Load the script <strong>once in the footer</strong> to avoid double counting</li>
<li>Do not use the upstream demo’s <code>document.head.innerHTML += …</code> (rebuilds <code>&lt;head&gt;</code> and can break theme scripts)</li>
<li>Local check: <code>HUGO_ENV=production hugo server</code>; plain <code>hugo server</code> does not load or count</li>
<li>Push the blog repo and wait for the static rebuild before numbers appear in production</li>
</ul>
<h3 id="94-acceptance">9.4 Acceptance</h3>
<ol>
<li>Open any post: meta views show a number; refresh should increase it</li>
<li>Footer site PV / UV show numbers</li>
<li>In Cloudflare, check request volume on the <strong><code>web-analytics</code></strong> Worker (not the zero-request static <code>myblog</code> app)</li>
</ol>
<hr>
<h2 id="10-config-switch-cheat-sheet">10. Config switch cheat sheet</h2>
<div class="code-block code-line-numbers open" style="counter-reset: code-block 0">
    <div class="code-header language-toml">
        <span class="code-title"><i class="arrow fas fa-angle-right" aria-hidden="true"></i></span>
        <span class="ellipses"><i class="fas fa-ellipsis-h" aria-hidden="true"></i></span>
        <span class="copy" title="Copy to clipboard"><i class="far fa-copy" aria-hidden="true"></i></span>
    </div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-toml" data-lang="toml"><span class="line"><span class="cl"><span class="c"># comments</span>
</span></span><span class="line"><span class="cl"><span class="p">[</span><span class="nx">params</span><span class="p">.</span><span class="nx">page</span><span class="p">.</span><span class="nx">comment</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">  <span class="nx">enable</span> <span class="p">=</span> <span class="kc">true</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># on-page counters (self-hosted Worker + D1)</span>
</span></span><span class="line"><span class="cl"><span class="p">[</span><span class="nx">params</span><span class="p">.</span><span class="nx">webAnalytics</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">  <span class="nx">enable</span> <span class="p">=</span> <span class="kc">true</span>
</span></span><span class="line"><span class="cl">  <span class="nx">baseURL</span> <span class="p">=</span> <span class="s2">&#34;https://analytics.leeissonba.com&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c"># home social icons</span>
</span></span><span class="line"><span class="cl"><span class="p">[</span><span class="nx">params</span><span class="p">.</span><span class="nx">home</span><span class="p">.</span><span class="nx">profile</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">  <span class="nx">social</span> <span class="p">=</span> <span class="kc">true</span></span></span></code></pre></div></div>
<p>Keep theme overrides under project <code>layouts/</code> and <code>assets/</code> so LoveIt submodule upgrades stay smaller.</p>
<hr>
<h2 id="11-reproduction-checklist">11. Reproduction checklist</h2>
<p>When aligning a fresh copy with this site:</p>
<ol>
<li><i class="far fa-square" aria-hidden="true"></i> Hugo Extended + <code>git submodule update --init</code></li>
<li><i class="far fa-square" aria-hidden="true"></i> <code>hugo.toml</code>: <code>baseURL</code>, default language, social, Giscus, <code>webAnalytics</code></li>
<li><i class="far fa-square" aria-hidden="true"></i> Cloudflare blog project name matches root <code>wrangler.jsonc</code> <code>name</code></li>
<li><i class="far fa-square" aria-hidden="true"></i> <code>layouts/</code> deprecation overrides + footer / posts/single / web-analytics partial</li>
<li><i class="far fa-square" aria-hidden="true"></i> <code>assets/css/_custom.scss</code> for code and video; <code>assets/js/analytics.js</code> in place</li>
<li><i class="far fa-square" aria-hidden="true"></i> Cloudflare blog: connected repo, build script, custom domain, <code>HUGO_ENV=production</code></li>
<li><i class="far fa-square" aria-hidden="true"></i> Giscus App installed; Discussions enabled</li>
<li><i class="far fa-square" aria-hidden="true"></i> (Optional) Web Analytics filter for <code>blog.</code> host</li>
<li><i class="far fa-square" aria-hidden="true"></i> Deploy <code>services/web-analytics</code>: D1 + Worker + custom domain matching <code>baseURL</code></li>
<li><i class="far fa-square" aria-hidden="true"></i> Cursor skills: <code>hugo-blog-publish</code> + <code>loveit-theme</code></li>
<li><i class="far fa-square" aria-hidden="true"></i> Smoke-test one post: bilingual, <code>featuredImage</code>, local media paths, <code>&lt;!--more--&gt;</code>; verify views in production</li>
</ol>
<hr>
<h2 id="12-references">12. References</h2>
<ul>
<li><a href="https://hugoloveit.com" target="_blank" rel="noopener noreffer ">LoveIt docs</a></li>
<li><a href="https://gohugo.io/host-and-deploy/host-on-cloudflare/" target="_blank" rel="noopener noreffer ">Host on Cloudflare (Hugo)</a></li>
<li><a href="https://giscus.app/" target="_blank" rel="noopener noreffer ">Giscus</a></li>
<li><a href="https://github.com/yestool/analytics_with_cloudflare" target="_blank" rel="noopener noreffer ">analytics_with_cloudflare</a></li>
<li><a href="https://bytejog.com/posts/hugo/hugo_analytics/" target="_blank" rel="noopener noreffer ">Hugo self-hosted visit counters (Worker + D1)</a></li>
<li>This repo: <code>services/web-analytics/README.md</code></li>
<li>Cloudflare Dashboard → Analytics &amp; Logs → Web Analytics</li>
</ul>]]></description></item></channel></rss>