3步构建静态站点生成器

2025-06-04

3步构建静态站点生成器

也许你经历过这种情况:你对自己的个人网站不再满意,它的外观和风格已经无法很好地展现你的个性,是时候重新上线了。我最近也遇到过这种情况,并问过自己:

我究竟真正需要什么?

我尝试过很多CMS系统,总是把自己的网站当作新技术的试验场。对于一个Web开发者来说,这并非坏事,也并非罕见的做法,但这次我想降低复杂性和维护工作量。于是,我萌生了一个绝妙的、全新的、前所未闻的天才想法:

如果我只写原生 HTML 会怎么样?!(ba dum,tss!)

我头晕目眩。这意味着加载时间极短,无需服务器端渲染或预编译,最重要的是:没有依赖,因此无需构建步骤!我高兴得像个圣诞节前的孩子。感觉自己刚刚完成了本世纪的一项重大发明。

但随后我感到一阵幻灭:计算数据怎么办?或者每个 API 检索的数据怎么办?我通常会在我的网站上显示一些 GitHub 和开发人员的帖子统计信息。用 JavaScript 来做这些会导致页面加载时再次产生额外的请求。而且我肯定不想每年都手动更改年龄(好吧,就算我忘了也没什么大不了的😅)。我的大脑疯狂地寻找解决这个问题的方法,以保持最新的成果。最终,它不得不意识到,至少需要一层数据检索和插入。但是,没有任何依赖关系,这能行吗?


事实证明,我本质上想要一个小型的静态网站生成器,我可以选择市面上现有的优秀解决方案之一。但有时,你只想保持无依赖性,保持简单,同时保持最新状态并长期运行,而无需担心它们。

我将其分为 3 个步骤:

  1. 创建标记:进行实际的网页设计工作。编写包含我想要的所有内容的 HTML 和 CSS。
  2. 检索和处理数据:编写一个调用所有 API 的脚本,执行我需要的所有数据操作并将其插入到我的内容中。
  3. 自动化:自动调用 2 中的脚本,以保持内容保持最新

让我们想象一下:

静态站点生成器的架构

还感兴趣吗?那就开始吧。

1. 创建标记



# create the template file
touch template.html


Enter fullscreen mode Exit fullscreen mode

啊,再次编写纯 HTML 代码感觉真好。我相信每个 IDE 都有基本 HTML 结构的快捷方式。对于 VS Code,只需创建一个空的 HTML 文件,键入!并点击TAB

这个可能比点击下一个流行的WordPress主题上的“安装”要麻烦一些。但我个人喜欢编写HTML和CSS,并从零开始构建这样的小型网站,赋予它个性化的风格。我甚至决定不使用JavaScript,但这更像是一种个人挑战,完全没有必要。

如果你不想从头开始,有很多不错的原生 HTML 模板,例如HTML5up。现在,让我们使用这个例子:



<!-- template.html -->
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>My Website</title>
</head>
<body>
  <header>
    I'm a 36 y/o software engineer.
  </header>
  <main>
    <p>I love Open Source.</p>
    <p>I created 123 PRs on GitHub.</p>
  </main>
</body>
</html>


Enter fullscreen mode Exit fullscreen mode

2. 检索和处理数据



# create the script file
touch build.sh


Enter fullscreen mode Exit fullscreen mode

现在事情变得有趣了。为了检索和操作数据,我决定直接使用 Bash。它几乎在所有 Linux 发行版上都可用,并且拥有强大的编程语言,足以检索数据并将其放入我们的 HTML 文件中。因此,对于我们的例子来说,一个可能的构建脚本可能如下所示:



# build.sh

GH_API_URL='https://api.github.com/graphql'
GITHUB_TOKEN='abc_AB12CD34...'

# call the GitHub API via curl
QUERY='{ viewer { pullRequests { totalCount } } }'
RESULT=$(curl -s -i -H 'Content-Type: application/json' -H "Authorization: bearer $GITHUB_TOKEN" -X POST -d "{\"query\": \"query $QUERY\"}" $GH_API_URL | tail -n 1)

# get the data we want
let AGE=(`date +%s`-`date +%s -d 1987-06-05`)/31536000
PR_COUNT=$(echo $RESULT | sed -r 's|.*"totalCount":([0-9]*).*|\1|g')


Enter fullscreen mode Exit fullscreen mode

这里发生了什么?我们使用 curl 调用GitHub GraphQL API,并将 JSON 响应存储在 中$RESULT。请注意,您需要一个访问令牌,您可以在GitHub 设置中生成该令牌。由于我们获取的 JSON 只有一个键,因此我们可以使用和一些正则表达式totalCount提取该键后面的数字。您还可以使用将计算结果直接赋值给变量,这里是根据给定日期计算出的年龄。sedlet

现在还缺少最后一件事,就是将数据插入到模板中。我决定使用常见的模板变量表示法{{...}}(当然,您可以选择任何您喜欢的符号),并修改了 template.html 如下:



<!-- template.html -->
...
  <header>
    I'm a {{age}} y/o software engineer.
  </header>
  <main>
    <p>I love Open Source.</p>
    <p>I created {{pr_count}} PRs on GitHub.</p>
  </main>
...


Enter fullscreen mode Exit fullscreen mode

为了替换它们,我们让脚本复制我们的模板并sed再次使用一些替换正则表达式:



# build.sh
...
cp template.html index.html
sed -i -e "s|{{age}}|$AGE|g;s|{{pr_count}}|$PR_COUNT|g" index.html


Enter fullscreen mode Exit fullscreen mode

瞧!我们现在有一个可供使用的 index.html,其中包含计算出的年龄和 API 检索到的拉取请求数量。

3. 配置和自动化

现在让我们改进一下我们的 Bash 脚本,让它真正可配置。你可能已经注意到,例如 GitHub 令牌和出生日期都被硬编码到脚本中了。一个更好的方法是,特别是对于敏感数据,将所有配置保存在一个单独的文件中。我决定使用一个简单的.env文件,但你可以使用任何适合你情况的文件:



# create a config file
touch .env


Enter fullscreen mode Exit fullscreen mode


# .env
BIRTH_DATE=1987-06-05
GITHUB_TOKEN=ghp_ABCDEFGHIK123456789


Enter fullscreen mode Exit fullscreen mode

要将此配置加载到 bash 脚本中,只需执行source以下命令即可。这样,所有配置变量都会自动成为 bash 变量:



# build.sh
source .env
...
let AGE=(`date +%s`-`date +%s -d $BIRTH_DATE`)/31536000
...


Enter fullscreen mode Exit fullscreen mode

现在我们有了 HTML 模板和一个可配置的 Bash 脚本,它可以生成可服务的 index.html 文件,我们终于可以执行该脚本了——无论何时何地*,我们都可以随意执行。您可以手动运行它,也可以使用 cron 作业或 GitHub 操作等自动化执行。如果您需要将网站迁移到其他服务器,这种灵活性将带来巨大的优势。

* 嗯,不是无限的,因为每次调用 API 的次数是有限制的。只需保持合理的重复次数即可,例如,我决定每 10 分钟调用一次。

总结

所以我们在这里做的是创建一个非常基础和简单的静态站点生成器。让我们最后用 diff 风格来看一下这种方法的优缺点:



+ Lightning fast, no blockers/requests on or after page load
+ Easy to maintain, no npm/composer update etc.
+ Flexible and (almost) tech and location independent
- Might be hard for some people to create/find a HTML template
- Not exactly beginner-friendly, requires knowledge of command line and handling raw data
- Might become less maintainable with a lot of pages


Enter fullscreen mode Exit fullscreen mode

深入研究之后,我可以说,它仍然是我用例(为热爱命令行的开发者打造的单页网站)的最佳选择。如果您想看看我新生成的网站,欢迎随时访问:

https://devmount.com

当然,它是开源的!如果您能将它用作下一个小项目的模板,我将不胜荣幸:

https://github.com/devmount/devmount.com

如果你有什么要补充的,需要解释,或者发现了我没有想到的关键点,请在评论区留言告诉我。

为了方便起见,这里有完整的示例文件,如果你想稍微摆弄一下的话:



<!-- template.html -->
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>My Website</title>
</head>
<body>
  <header>
    I'm a {{age}} y/o software engineer.
  </header>
  <main>
    <p>I love Open Source.</p>
    <p>I created {{pr_count}} PRs on GitHub.</p>
  </main>
</body>
</html>


Enter fullscreen mode Exit fullscreen mode


# .env
BIRTH_DATE=1987-06-05
GITHUB_TOKEN=ghp_ABCDEFGHIK123456789


Enter fullscreen mode Exit fullscreen mode


# build.sh
source .env

GH_API_URL='https://api.github.com/graphql'

# call the GitHub API via curl
QUERY='{ viewer { pullRequests { totalCount } } }'
RESULT=$(curl -s -i -H 'Content-Type: application/json' -H "Authorization: bearer $GITHUB_TOKEN" -X POST -d "{\"query\": \"query $QUERY\"}" $GH_API_URL | tail -n 1)

# get the data we want
let AGE=(`date +%s`-`date +%s -d $BIRTH_DATE`)/31536000
PR_COUNT=$(echo $RESULT | sed -r 's|.*"totalCount":([0-9]*).*|\1|g')

# generate website and replace template variables
cp template.html index.html
sed -i -e "s|{{age}}|$AGE|g;s|{{pr_count}}|$PR_COUNT|g" index.html


Enter fullscreen mode Exit fullscreen mode

发布日期:2024年5月2日

文章来源:https://dev.to/devmount/building-a-static-site-generator-in-3-steps-72e
PREV
如何更正 Git 提交消息
NEXT
4 个提升脚本性能的 PHP 技巧