A Detailed Walkthrough of build.ps1
Single page build analysis
build.ps1 is the core of the entire static site generation system. It loads various HTML components, performs placeholder replacement, injects dynamic data, and outputs a complete .html file. It supports two languages (Chinese and English), two page types (homepage and blog), and draft mode. Through different parameter combinations, it can handle various build scenarios: building the homepage, building blog posts, including drafts, generating English versions, and more.
1. Parameter Design
The script accepts 5 named parameters covering the following scenarios:
param(
[string]$PageName = "index", # Output filename (without .html)
[string]$Title = "DragonRS Void", # <title> tag content
[string]$ContentFile = "", # Body content file path
[switch]$IncludeDrafts, # Whether to include drafts
[string]$Lang = "zh" # Language: zh / en
)
$PageName directly determines the output path: index outputs to the project root, while other pages output to dist/ (Chinese) and dist/en/ (English)[1].
2. Component Loading
The script's first step is loading all HTML component templates from the src/components/ directory, using Get-Content -Raw -Encoding UTF8 to read each file as a string.
The loaded templates include header, banner, sidebars (left and right), and footer. English pages (-Lang en) automatically load sidebar-right-en.html.
Additionally, to support blog pages' independent sidebar layout (left TOC + right slim sidebar), the script loads 6 blog-specific templates including blog left/right sidebars (Chinese and English versions), TOC item template, and TOC scroll container template.
These templates are independent from the homepage sidebar — the homepage left side remains the guestbook, while the right side remains search + latest articles + changelog + badges[2].
3. Guestbook Injection
The script reads guestbook data from data/runtime/guestbook.txt, takes the last $MaxMessages (default 20) entries, reverses the order so the newest appears first, and begins parsing.
Data format (pipe-delimited): new format has 6 fields (name|email|content|ip|time|show_ip), old format has 5 fields (name|content|ip|time|show_ip) for backward compatibility.
Each message is filled into the guestbook-item.html template. If the user provided an email, the name becomes a clickable mailto link. All entries are concatenated and placed into the scrollable guestbook-container.html, then injected into the left sidebar by replacing <!-- GUESTBOOK_MESSAGES -->.
4. Changelog Injection
Similar to the guestbook, but with two key differences: the data source is data/changelog.txt (format: YYYY-MM-DD|content), entries do not need reversing since changelog.txt is already in chronological order. Maximum display count is $MaxChangelog (default 300).
In English mode, the container title is automatically localized. Injected into the right sidebar via <!-- CHANGELOG -->.
5. Latest Posts Injection
The latest posts list is not generated by build.ps1 — it's pre-built by generate-archive.ps1 and output to src/components/latest-posts.html. build.ps1 only reads it and injects it into <!-- LATEST_POSTS -->.
This "pre-generate + inject" design avoids build.ps1 scanning all blog files each time, improving single-page build speed[3].
6. Draft Detection
After reading the content file, the script checks for draft: true. Normal builds skip drafts entirely. Using -IncludeDrafts outputs drafts with a draft- prefix. Drafts don't appear in archives, tag clouds, RSS, or search indexes.
7. Language Switch Links
The right sidebar has a <!-- LANG_SWITCH_URL --> placeholder. The script calculates the switch link based on current language: English pages link to Chinese, Chinese pages link to /en/ versions.
The language switch is now injected into all sidebars — homepage, blog (both languages) — ensuring it works everywhere[4].
8. Blog Sidebar Separation & TOC Generation
Blog pages use a separate layout: left sidebar becomes TOC directory (auto-generated from body headings), right sidebar keeps search + latest articles, removes changelog and badges, adds article tags and feature buttons.
TOC generation extracts all <font size="5" color="#ff66cc"> heading tags from the body, auto-assigns anchor IDs, and builds the directory list. Key trick: processing from back to front to avoid index shifting when inserting anchors[5].
Article tag injection extracts tags from <!-- tags: xxx --> metadata and generates links to /tags.html#TagName. All injections apply simultaneously to both Chinese and English blog sidebars[6].
9. Footnote System (Most Complex Part)
Footnote processing has three steps:
Step 1: Extract definitions — Regex matches [^N]: content patterns, storing in hash table $fnDefs.
Step 2: Replace references — [^N] in the body becomes superscript anchor links.
Step 3: Build definition list — Table at article end with footnote numbers linking back to references.
Bidirectional anchors ensure readers can jump to footnotes and back — no JavaScript required[7][8][9].
10. Article Navigation (Previous/Next)
For blog pages, the script auto-generates previous/next navigation by scanning all blog content files, extracting dates, filtering drafts, sorting by date, and finding the current article's position.
11. Page Assembly & Output
All parts are concatenated: header + banner + table(left + content + right) + footer. Asset paths are corrected (assets/ → /assets/), last updated time injected into footer, title replaced, then output as UTF-8 with BOM[10].
Summary
build.ps1 is a typical template engine + data injection architecture with no external dependencies, implemented entirely in pure PowerShell. It handles backward compatibility, precise footnote matching, build-time navigation computation, blog/homepage sidebar switching, and global asset path replacement.
Currently Get-Content -Raw requires PowerShell 3.0+, meaning the build script cannot run on real Windows 95[11].
| [1] | Output paths consider language: English index → dist/en/index.html, Chinese index → project root; other pages go to dist/ or dist/en/ by language.
|
| [2] | Homepage left = guestbook, right = search + latest + changelog + badges. Blog left = TOC, right = search + latest + tags + features. Templates are completely independent.
|
| [3] | Single-page builds only replace placeholders. When new articles are added, run generate-archive.ps1 first.
|
| [4] | Language switch links injected into all sidebar variables for homepage and blog compatibility.
|
| [5] | TOC uses pure HTML anchors — same mechanism as footnotes, a standard HTML 3.2 practice.
|
| [6] | Latest posts and language switch also apply to both Chinese and English blog sidebars.
|
| [7] | Core footnote regex matches definitions until next definition or paragraph end.
|
| [8] | The [8] in the body is itself a footnote reference.
|
| [9] | All interactions use pure HTML without JavaScript. Anchor jumps work in IE5.5+.
|
| [10] | UTF-8 BOM ensures correct Chinese encoding. Without it, IE5.5 may render as Latin-1.
|
| [11] | Get-Content -Raw requires PowerShell 3.0 (2012). Windows 95 only had DOS batch and VBScript.
|
|