基于Eleventy与new.css构建极简静态博客:从技术选型到部署实践
1. 项目概述:一个AI开发者代理的静态博客
最近在折腾个人博客,发现了一个挺有意思的开源项目,叫“Rook's Gambit”。这是一个由名为“Rook”的AI开发者代理(Agent)维护的技术博客。项目本身结构清晰,技术栈选型也很有特点,使用了静态站点生成器Eleventy(11ty)搭配一个名为“new.css”的终端风格主题。对于想快速搭建一个极简、高效、且自带“极客范儿”博客的开发者来说,这个项目提供了一个非常不错的起点和参考。我自己也基于它做了一些定制和深度使用,今天就来拆解一下这个项目的核心设计、实操细节以及我在部署和内容管理过程中踩过的一些坑。
这个博客的定位很明确:一个纯粹以内容为中心的开发者日志。它没有复杂的后台,没有数据库,所有文章都是Markdown文件,通过11ty编译成静态HTML。这种架构决定了它的核心优势:速度快、安全性高、几乎零维护成本,并且可以轻松托管在GitHub Pages、Netlify、Vercel等任何静态托管服务上。特别适合像我这样,希望把精力聚焦在写作本身,而不是折腾服务器和运维的开发者。
2. 技术栈选型与设计思路解析
2.1 为什么是Eleventy(11ty)?
在众多静态站点生成器(SSG)中,11ty可能不像Hugo或Gatsby那样名声在外,但它有几个独特的优势,恰好契合了这个AI代理博客的需求。
首先,零配置与灵活性的平衡。11ty号称“更简单的静态站点生成器”,它确实可以开箱即用,但你也能通过配置文件(.eleventy.js或eleventy.config.js)进行深度定制。对于Rook's Gambit这个项目,它需要在子目录(/agents/rook/)下部署,这通过11ty的pathPrefix配置可以轻松实现,避免了路径混乱的问题。很多其他SSG在处理子路径时,需要额外的插件或复杂的重写规则,而11ty原生支持就很好。
其次,模板语言的自由选择。11ty不强制你使用某一种模板语言,它支持Liquid、Nunjucks、Handlebars、Markdown等多种语言,甚至可以在同一个项目中混用。这给了开发者极大的自由度。从项目代码看,它主要使用了Nunjucks,这种语法对于有Jinja2或Django模板经验的开发者来说非常友好,功能强大且逻辑清晰。
最后,构建速度极快。由于11ty不捆绑前端框架(如React),它的构建过程非常轻量和快速。对于一个博客项目,文章数量增长后,构建速度是一个很重要的考量点。我实测过一个包含上百篇文章的项目,11ty能在几秒内完成全量构建,这对于自动化部署流程(如GitHub Actions)的体验提升是巨大的。
2.2 “new.css”主题:极简主义的终端美学
项目的视觉风格由new.css框架定义。这不是一个传统的CSS框架(如Bootstrap),而是一个“极简的、类终端风格的CSS框架”。它的设计哲学是:仅通过语义化HTML标签来定义样式,无需添加额外的CSS类。
这意味着,你写一个<h1>,它自动就是终端风格的大标题;写一个<code>块,它自动呈现为等宽字体加背景色。这种设计带来了几个好处:
- 极致的写作体验:作者只需要关注Markdown内容本身(即语义化结构),无需分心去考虑样式类名。
- 极小的体积:整个框架的CSS文件非常小,对页面加载速度有极大提升。
- 独特的风格:终端风格在技术博客中辨识度很高,能立刻营造出“开发者专属”的氛围。
当然,这种设计也有局限。如果你想进行深度定制,比如改变颜色方案或布局结构,就需要直接修改new.css的源码或覆盖其样式,而不是通过添加类名的方式。对于追求高度定制化的开发者来说,这可能是一个需要考虑的点。不过对于Rook's Gambit这个项目,这种“约定大于配置”的风格恰恰符合其简洁、专注内容的定位。
2.3 子目录部署的考量
项目明确配置了pathPrefix用于子目录(/agents/rook/)托管。这是一个非常实用的设计,尤其适用于以下场景:
- 作为大型网站的一部分:比如你的个人主站在根目录,而博客只是其中一个子版块(如
yourdomain.com/blog)。 - GitHub Pages的项目站点:GitHub Pages支持用户仓库(
username.github.io)和项目仓库两种。项目仓库的站点默认地址就是username.github.io/repo-name,这正是子目录结构。 - 多代理/多博客管理:从项目中的
AGENTS.md文件可以推测,这可能是一个更大项目的一部分,其中包含多个“代理”(Agent),每个代理都有自己的博客子目录。这种结构便于统一管理。
在11ty中配置pathPrefix后,所有资源路径(CSS、JS、图片)和内部链接都需要通过{{ ‘/path/to/file’ | url }}过滤器进行处理,以确保在子目录下能正确加载。这是使用11ty进行非根部署时必须注意的关键点,否则很容易出现404错误。
3. 项目结构与核心文件详解
拿到一个开源项目,理清其目录结构是第一步。Rook's Gambit的结构非常典型,遵循了11ty的最佳实践。
rook-blog/ ├── _site/ # 构建输出目录(.gitignore忽略) ├── src/ # 源代码目录 │ ├── posts/ # 博客文章(Markdown文件) │ ├── css/ # 样式文件(包含new.css) │ ├── js/ # 可选的JavaScript脚本 │ └── _includes/ # 模板组件(Nunjucks) │ ├── layouts/ # 基础布局模板 │ └── (其他局部模板) ├── eleventy.config.js # 11ty核心配置文件 ├── package.json # 项目依赖和脚本 └── README.md # 项目说明3.1 核心配置文件:eleventy.config.js
这个文件是项目的大脑。我们来看一下它通常需要配置的关键部分(基于项目描述和常见实践):
module.exports = function(eleventyConfig) { // 1. 设置路径前缀,用于子目录部署 eleventyConfig.addPassthroughCopy("src/css"); eleventyConfig.addPassthroughCopy("src/js"); eleventyConfig.addPassthroughCopy("src/images"); // 2. 配置输入、输出目录 return { dir: { input: "src", output: "_site", includes: "_includes", data: "_data" }, pathPrefix: "/agents/rook/", // 关键配置:子目录路径 templateFormats: ["md", "njk", "html"], markdownTemplateEngine: "njk", htmlTemplateEngine: "njk" }; };关键配置解析:
addPassthroughCopy: 这条指令告诉11ty,将src/css/等目录下的文件原样复制到输出目录(_site)中。这对于静态资源(样式表、脚本、图片)是必须的,因为11ty默认只处理模板文件。pathPrefix: “/agents/rook/”: 这是项目的灵魂配置。它确保了所有生成的页面链接和资源引用都会自动带上这个前缀。markdownTemplateEngine: “njk”: 这指定了Markdown文件将使用Nunjucks模板引擎进行预处理。这非常重要,因为它允许你在Markdown文章中使用Nunjucks的模板语法,比如调用{{ ‘/css/style.css’ | url }}过滤器来生成正确的资源路径。
3.2 文章模板与Front Matter
所有博客文章都存放在src/posts/目录下,文件名格式为YYYY-MM-DD-post-title.md。这种命名方式不仅便于按日期排序,也使得URL清晰易读。
每篇文章的头部都有一个YAML格式的Front Matter,用于定义元数据:
--- title: “深入理解JavaScript事件循环” date: 2023-10-27T14:30:00 description: “本文通过实例详细讲解了浏览器中JavaScript事件循环的工作原理,以及宏任务与微任务的区别。” tags: - JavaScript - 前端 - 核心概念 ---Front Matter各字段解读与实操技巧:
title和description: 除了用于页面显示,更是SEO(搜索引擎优化)的关键。description会生成页面的<meta name=“description”>标签,是搜索结果中显示的片段,务必简洁、准确地概括文章核心。date: 注意格式是ISO 8601(YYYY-MM-DDTHH:MM:SS)。你可以省略时间部分,只写日期。这个日期用于文章排序和存档页面的生成。tags: 这是一个数组,用于给文章打标签。在11ty中,你可以非常方便地创建一个“标签”合集页面,自动聚合所有包含某个标签的文章。这是组织内容、提升站内导航体验的利器。
实操心得:我建议在Front Matter中增加一个
slug字段。有时文章的标题可能很长或者包含特殊字符,你不希望它直接出现在URL中。你可以设置slug: “understanding-js-event-loop”,然后在11ty配置中通过permalink函数来生成更简洁、友好的URL,这对SEO和可读性都有好处。
4. 从零开始的完整搭建与部署流程
假设你现在想基于Rook's Gambit搭建自己的博客,以下是详细的步骤和注意事项。
4.1 本地开发环境搭建
获取代码:
git clone https://github.com/haliphax-ai/rook-blog.git my-blog cd my-blog安装依赖: 项目使用npm管理依赖,执行
npm install。这一步会安装11ty及其相关插件。如果网络较慢,可以考虑配置国内镜像源或使用yarn、pnpm等替代工具。启动本地开发服务器:
npm start这通常对应着
package.json中scripts下的“start”: “eleventy --serve”命令。--serve参数会启动一个本地服务器(默认在http://localhost:8080),并启用热重载功能。当你修改任何源文件(Markdown、模板、CSS)时,浏览器页面会自动刷新,开发体验非常流畅。编写第一篇文章: 在
src/posts/目录下,新建文件2023-10-27-my-first-post.md。按照上述Front Matter格式填写标题、日期和描述,然后在下面用Markdown语法开始写作。保存后,立即在浏览器中查看效果。
4.2 构建与生产发布
当文章写完,准备发布到线上时,需要执行构建命令:
npm run build这对应“build”: “eleventy”脚本。11ty会读取所有模板和内容,进行渲染,并将最终的静态文件输出到_site目录。你可以直接检查这个目录,里面就是完整的、可以托管到任何Web服务器上的网站文件。
构建过程深度解析:
- 数据聚合:11ty首先会读取
_data目录下的全局数据文件(如site.json),以及每篇文章的Front Matter。 - 模板渲染:它遍历所有模板文件(.njk, .md等),将数据注入模板。对于文章列表页,它会使用“合集”(Collections)功能,自动将所有文章按日期排序并传递给模板。
- 资源复制:通过
addPassthroughCopy指定的静态资源被复制到输出目录。 - 路径处理:所有在模板中使用了
| url过滤器的链接,都会自动加上pathPrefix中配置的前缀。 - 文件生成:最终,一个个HTML、CSS、JS文件在
_site目录下生成。
4.3 部署到GitHub Pages(实战示例)
这是最常用且免费的托管方式之一。假设你的GitHub用户名是yourusername,仓库名是my-blog。
修改配置:在
eleventy.config.js中,将pathPrefix修改为你的仓库名。因为项目站点的访问地址是https://yourusername.github.io/my-blog/。pathPrefix: process.env.NODE_ENV === ‘production’ ? ‘/my-blog/’ : ‘’,这里用了一个小技巧:通过环境变量
NODE_ENV来判断是开发环境还是生产环境。开发时路径前缀为空,方便本地预览;构建生产包时,前缀生效。创建GitHub仓库:在GitHub上新建一个名为
my-blog的公共仓库。关联并推送代码:
# 移除原有的git历史(如果是克隆的rook-blog) rm -rf .git git init git add . git commit -m “Initial commit” git branch -M main git remote add origin https://github.com/yourusername/my-blog.git git push -u origin main配置GitHub Actions自动部署: 在项目根目录创建
.github/workflows/deploy.yml文件:name: Deploy to GitHub Pages on: push: branches: [ main ] jobs: build-and-deploy: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v3 - name: Setup Node.js uses: actions/setup-node@v3 with: node-version: ‘18’ - name: Install Dependencies run: npm ci - name: Build run: NODE_ENV=production npm run build - name: Deploy uses: peaceiris/actions-gh-pages@v3 with: github_token: ${{ secrets.GITHUB_TOKEN }} publish_dir: ./_site publish_branch: gh-pages # 部署到gh-pages分支这个工作流会在你每次推送代码到
main分支时自动触发:安装依赖、构建项目,并将_site目录下的内容推送到仓库的gh-pages分支。GitHub Pages会自动从gh-pages分支获取内容并发布。启用GitHub Pages:在仓库的
Settings -> Pages页面,将Source设置为Deploy from a branch,分支选择gh-pages,根目录/。保存后,稍等几分钟,你的博客就可以通过https://yourusername.github.io/my-blog/访问了。
5. 深度定制与功能扩展指南
原项目是一个极简的起点,但一个成熟的博客通常需要更多功能。以下是几个常见的扩展方向。
5.1 添加代码高亮
技术博客离不开代码片段。原生的new.css只是给<code>和<pre>加了基本样式,没有语法高亮。我们可以集成Prism.js。
安装Prism:
npm install prismjs创建高亮模板:在
src/_includes/下创建一个code.njk宏(macro)或短代码(shortcode)。// 在 eleventy.config.js 中添加 const Prism = require(‘prismjs’); const loadLanguages = require(‘prismjs/components/’); // 加载你需要的语言,例如javascript, bash, python loadLanguages([‘javascript’, ‘bash’, ‘python’, ‘css’, ‘markup’]); eleventyConfig.addPairedShortcode(‘code’, function(content, language) { const highlighted = Prism.highlight(content, Prism.languages[language], language); return `<pre class=“language-${language}”><code class=“language-${language}”>${highlighted}</code></pre>`; });在文章中使用:
{% code “javascript” %} function hello() { console.log(‘Hello, Rook!’); } {% endcode %}
5.2 实现文章搜索功能
静态站点的搜索是一个经典问题。一个轻量级的方案是使用lunr.js在客户端实现搜索。
生成搜索索引:在构建时,创建一个包含所有文章标题、描述、内容和URL的JSON索引文件。
// 在 eleventy.config.js 中添加 eleventyConfig.addCollection(‘searchIndex’, function(collectionApi) { return collectionApi.getAll().filter(item => item.data.tags).map(item => ({ title: item.data.title, description: item.data.description, content: item.templateContent, url: item.url, tags: item.data.tags })); });然后,在模板中生成这个索引的JSON文件。
创建搜索页面:新建一个
search.njk页面,引入lunr.js和上面生成的索引JSON。编写JavaScript代码,读取索引,提供实时搜索和结果展示功能。优化体验:对于文章数量很多(比如超过100篇)的博客,索引文件可能会很大。可以考虑只索引标题、描述和标签,或者对内容进行截断,以控制文件大小,提升页面加载速度。
5.3 优化SEO与社交媒体分享
虽然11ty生成的静态站点对SEO天生友好,但我们还可以做得更好。
- 自动生成Sitemap:使用
@quasibit/eleventy-plugin-sitemap插件,可以自动生成sitemap.xml,帮助搜索引擎抓取。 - 优化Open Graph和Twitter Cards:在
_includes/layouts/base.njk这样的基础布局中,动态生成<meta property=“og:title”>、og:description、og:image等标签。这些标签决定了你的文章在微信、Twitter、LinkedIn等社交媒体上分享时的预览效果。图片(og:image)尤其重要,可以设置为文章首图,或者一个统一的博客Logo。 - 规范链接(Canonical URL):确保每个页面都有正确的
<link rel=“canonical”>标签,指向页面的权威网址,避免重复内容问题。
6. 常见问题与故障排查实录
在实际使用和部署过程中,我遇到并解决了一些典型问题。
6.1 路径错误导致CSS/JS无法加载
问题现象:本地开发一切正常,但部署到GitHub Pages(或其他子目录)后,页面样式丢失,控制台报错找不到CSS/JS文件。
根本原因:模板中的资源链接没有使用| url过滤器,或者pathPrefix配置不正确。
解决方案:
- 检查模板:确保所有资源引用都像这样:
<link rel=“stylesheet” href=“{{ ‘/css/new.css’ | url }}”>。注意路径以/开头。 - 检查配置:确认
eleventy.config.js中的pathPrefix与你的实际部署路径完全一致。对于GitHub Pages项目站点,通常是‘/repository-name/’。 - 环境变量区分:如前所述,使用环境变量来区分开发和生产环境的
pathPrefix是最佳实践。
6.2 文章日期排序混乱或无法显示
问题现象:文章列表页的文章顺序不对,或者文章的发布日期没有显示。
原因分析:
- Front Matter日期格式错误:确保日期格式是
YYYY-MM-DD或YYYY-MM-DDTHH:MM:SS。错误的格式会导致11ty无法正确解析。 - 合集(Collection)配置:默认情况下,11ty会按照文件创建日期排序。为了按文章Front Matter中的
date字段排序,你需要在创建合集时指定排序方式。
解决方案:在eleventy.config.js中,可以这样配置一个按日期降序排列的文章合集:
eleventyConfig.addCollection(‘posts’, function(collectionApi) { return collectionApi.getFilteredByGlob(‘src/posts/*.md’).sort((a, b) => { return b.date - a.date; // 降序,最新的在前 }); });然后在模板中遍历collections.posts即可。
6.3 构建速度突然变慢
问题现象:随着文章数量增加,npm run build的时间显著变长。
排查与优化:
- 检查图片处理:如果你使用了
eleventy-img这类图片处理插件,并且文章中有大量高清图片,这会是构建的主要瓶颈。考虑在开发时跳过图片优化,或者使用缓存。 - 精简模板逻辑:检查你的Nunjucks模板,避免在模板中进行过于复杂的计算或数据操作。尽量将数据处理逻辑移到11ty的配置或自定义过滤器中。
- 启用增量构建:在开发时,使用
eleventy --serve --incremental命令。--incremental参数会只重新构建更改过的文件,极大提升开发服务器的热重载速度。但注意,对于某些复杂的依赖关系,增量构建可能不会完全更新,必要时仍需全量构建。 - 升级Node.js和11ty版本:新版本通常有性能改进。
6.4 自定义样式与new.css的冲突
问题现象:你想修改某个元素的样式(比如链接颜色),但自己写的CSS规则似乎不生效。
原因与解决:new.css是一个“CSS框架”,它直接为HTML标签定义了样式。CSS的层叠规则是后定义的样式会覆盖先定义的。你需要确保你的自定义CSS文件在HTML中晚于new.css被引入。
<head> <link rel=“stylesheet” href=“{{ ‘/css/new.css’ | url }}”> <!-- 你的自定义样式必须放在后面 --> <link rel=“stylesheet” href=“{{ ‘/css/custom.css’ | url }}”> </head>在custom.css中,你可以使用相同的标签选择器或更具体的选择器来覆盖new.css的样式。例如,要修改链接颜色:
/* custom.css */ a { color: #ff6b6b; /* 这会覆盖new.css中的链接颜色 */ } a:hover { color: #ee5a52; }7. 从“博客引擎”到“内容系统”的思考
使用Rook's Gambit这类静态生成方案,最大的收获不仅仅是搭建了一个博客,而是理解了一种内容管理的哲学:将内容(Markdown)与表现(模板/样式)分离,并通过版本控制(Git)来管理一切。
这种模式带来了几个深远的好处:
- 可移植性:你的所有文章都是纯文本文件,未来无论想迁移到Hugo、Gatsby还是其他任何系统,转换成本都极低。
- 可追溯性:每一篇文章的每一次修改,都通过Git提交历史记录了下来。你可以清晰地看到内容的演进过程。
- 自动化集成:结合GitHub Actions/GitLab CI等工具,可以实现“写作 -> 推送 -> 构建 -> 部署”的全自动化流水线。你甚至可以用脚本自动提取文章摘要、生成社交分享图等。
对于“AI开发者代理”这个背景,这种架构更是完美契合。AI可以像开发者一样,通过编写和提交Markdown文件来“发布”文章,整个流程完全代码化、自动化,无需人工干预内容发布平台。这或许就是未来内容创作与运维的一种新形态。
我个人在将这个博客框架用于自己的技术笔记后,最大的体会是“心无旁骛”。我再也不用担心数据库备份、服务器安全、WordPress插件更新这些问题。所有的“运维”工作,就是偶尔运行一下git push。剩下的时间,可以全部投入到思考和写作本身。如果你也受够了动态博客的繁琐,或者想拥有一个完全属于自己的、高速且稳定的内容基地,那么基于Eleventy和类似Rook's Gambit这样的起点,亲手搭建一个,会是一个非常值得投入的选择。
