在過去的幾年里,開源靜態(tài)網(wǎng)站生成器的數(shù)量增長(zhǎng)迅速孵睬,StaticGen 上幾乎找得到每一種語(yǔ)言實(shí)現(xiàn)的版本播歼。靜態(tài)網(wǎng)站相比動(dòng)態(tài)網(wǎng)站具備無需依賴應(yīng)用服務(wù)器,性能優(yōu)越肪康,部署簡(jiǎn)單等特點(diǎn)荚恶。特別適合生成靜態(tài)文檔,個(gè)人博客磷支,飽受開發(fā)者的青睞。相比學(xué)會(huì)使用食寡,掌握工作原理也尤為重要雾狈。
一個(gè)靜態(tài)網(wǎng)站生成器的工作流程通常有以下幾個(gè)步驟:
- 讀取源文件(e.g. 約定 markdown 格式)
- 資源預(yù)處理
- 模板引擎渲染
- 生成目標(biāo)文件
第一步 讀取源文件
從使用者的角度,我們希望以 markdown 的形式進(jìn)行寫作抵皱,相比純文本更容易控制格式善榛,并且可以靈活地自定義配置(源目錄路徑、目標(biāo)目錄路徑呻畸、頁(yè)面標(biāo)題等等)移盆,覆蓋工具的默認(rèn)配置,這一步很簡(jiǎn)單伤为。
以 Node.js 為例:
// 讀取 markdown 內(nèi)容
readFile(source, (err, data) => {
console.log(data);
})
// 讀取配置內(nèi)容
console.log(require(config))
第二步 資源預(yù)處理
也是靜態(tài)網(wǎng)站生成器的核心工作部分咒循。首先解析 markdown 內(nèi)容,分離頭部元數(shù)據(jù)(通常采用 YAML 格式绞愚,用于單頁(yè)信息配置)與主體內(nèi)容叙甸。
形似:
---
title: Hello World
---
Awesome static site generator
解析成:
const result = {
'path/to/hello-world.md': {
title: 'Hello World',
content: new Buffer('Awesome static site generator.')
}
}
通常的做法是掃描文件,匹配分隔符---
位衩,分割內(nèi)容裆蒸,對(duì)頭部用相應(yīng)格式的引擎解析(e.g. YAML 格式用 yaml-parser,JSON 格式用 JSON.parse)糖驴,對(duì)主體內(nèi)容僚祷,需要把 markdown 內(nèi)容轉(zhuǎn)換成帶有標(biāo)簽的 HTML 片段,用于排版與應(yīng)用樣式贮缕,推薦比較流行的解析器 marked 辙谜。
經(jīng)過轉(zhuǎn)換后:
const markedResult = {
'path/to/hello-world.md': {
title: 'Hello World',
content: new Buffer('Awesome static site generator.'),
html: '<p>Awesome static site generator.</p>'
}
}
對(duì)其它一些靜態(tài)資源(e.g. css, js, png),可以引入一系列工具鏈跷睦,CSS 預(yù)處理器筷弦,編譯器,打包器,流程構(gòu)建工具烂琴,將全部資源相整合爹殊。由此,可以提供一套主題配置奸绷,甚至可以開放主題插件梗夸,豐富內(nèi)容。所有的設(shè)計(jì)出發(fā)點(diǎn)都基于更好的內(nèi)容寫作号醉,而不必折騰繁瑣重復(fù)性的頁(yè)面開發(fā)工作反症。
第三步 模板引擎渲染
在上一步,我們得到了 markdown 解析后的 HTML 片段畔派,接下來要做得就是將 HTML 片段嵌入預(yù)先定義的模板铅碍,復(fù)用頁(yè)面中公共部分(e.g. 導(dǎo)航欄、側(cè)邊欄线椰、底部)胞谈,還可以嵌入變量(默認(rèn)配置及自定義配置)和靜態(tài)資源。
以模板引擎 EJS 為例:
<html>
<head><%= title %></head>
<body>
<% include partials/navbar %>
<%- html %>
</body>
</html>
// EJS 渲染
const ejsResult = ejs.render(str, {
...markedResult['path/to/hello-world.md']
});
我們甚至可以拋棄以往模板引擎渲染這種比較傳統(tǒng)的方式憨愉,改用 MV* 框架(e.g. React, Vue, Angular)烦绳,并結(jié)合服務(wù)端渲染技術(shù),熱替換技術(shù)及其它工具鏈配紫,打造一個(gè)更現(xiàn)代化的靜態(tài)網(wǎng)站生成器径密。
第四步 生成目標(biāo)文件
經(jīng)過前三步的解析,處理躺孝,編譯享扔,轉(zhuǎn)換,我們得到了最終的資源文件,最后一步只需清理目標(biāo)目錄,并輸出所有資源到目標(biāo)目錄邢隧,結(jié)束工作模她。
// 生成目標(biāo)文件
writeFile(destination, ejsResult, err => {
if (err) return console.error(err)
}))
你可能還需要
- 一個(gè)本地服務(wù)器 通過啟動(dòng)一個(gè) Node.js Server 實(shí)時(shí)預(yù)覽界面,監(jiān)聽本地文件改動(dòng),結(jié)合 live-reload 觸發(fā)頁(yè)面自動(dòng)刷新,或者利用 Webpack 熱替換功能。
- 一個(gè)文件數(shù)據(jù)庫(kù) 持久化存儲(chǔ)部分?jǐn)?shù)據(jù)(e.g. 博客發(fā)表時(shí)間呆盖,文件哈希值,文件修改時(shí)間)贷笛,重新編譯可以跳過未改動(dòng)的文件应又。
- 一個(gè)日志系統(tǒng) 記錄編譯過程和編譯結(jié)果,增強(qiáng) debug 可行性乏苦,按 log 層級(jí)格式化輸出不同信息到控制臺(tái)株扛。
- 一個(gè)自動(dòng)化部署方案 整合 Git 和 WebHook尤筐,一鍵發(fā)布到 GitHub Pages 或者自己的網(wǎng)站上。
小結(jié)
本文從宏觀角度解釋了靜態(tài)網(wǎng)站生成器的工作流程(輸入 => 預(yù)處理 => 渲染 => 輸出)洞就。當(dāng)然這個(gè)過程還涉及命令行的解析盆繁,合法性校驗(yàn),錯(cuò)誤捕獲旬蟋,解析器原理油昂,編譯器原理,模板引擎原理倾贰,插件設(shè)計(jì)等等冕碟。See you next time ~