发布于 2025-12-08 8 阅读
0

11 分钟内开始使用 Eleventy

11 分钟内开始使用 Eleventy

在本文中,我们将探索 Eleventy,一个用 Node.js 编写的快速、简单的静态站点生成器。

我们将通过从头开始逐步构建一个简单的示例网站,以非常实用的方式实现这一目标。

在此练习中,我们将学习掌握 Eleventy 的一些基本概念,例如模板、布局、数据文件,甚至如何使用来自外部来源(如第三方 REST API)的数据。

本文中的所有代码都可以在 GitHub 上的lmammino/11ty-sample-project上找到。

引导项目

让我们直接创建一个名为的新项目11ty-sample-project

mkdir 11ty-sample-project
cd 11ty-sample-project
npm init -y
Enter fullscreen mode Exit fullscreen mode

安装 Eleventy 并建立我们的第一个站点

Eleventy 可以使用 npm 安装。你可以在系统中全局安装它,但我个人更喜欢将其作为特定项目的开发依赖项安装。这样,你可以根据需要在不同项目中使用不同版本的 Eleventy。

npm i --save-dev @11ty/eleventy
Enter fullscreen mode Exit fullscreen mode

现在让我们为 Eleventy 项目创建一个索引文件:

echo "# My sample Eleventy website" > index.md
Enter fullscreen mode Exit fullscreen mode

此时,我们已准备好运行 Eleventy:

node_modules/.bin/eleventy --watch --serve
Enter fullscreen mode Exit fullscreen mode

当然,为了简单起见,我们可以将这个脚本放在我们的package.json

// ...
"scripts": {
  "start": "eleventy --watch --serve"
},
// ...
Enter fullscreen mode Exit fullscreen mode

现在我们只需运行以下命令即可更轻松地运行 Eleventy:

npm start
Enter fullscreen mode Exit fullscreen mode

我们现在可以在localhost:8080看到我们的网站

我的示例 Eleventy 网站

创建自定义配置文件

Eleventy 遵循一些默认约定,但它也非常灵活,允许您更改这些默认设置。

如果您出于某种原因希望更改默认文件夹结构或支持的模板语言等,这将非常方便。

为了向 Eleventy 提供我们的自定义配置,我们必须.eleventy.js在项目的根文件夹中创建一个名为的文件:

module.exports = function (config) {
  return {
    dir: {
      input: './src',
      output: './build'
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

通过此特定配置,我们将重新定义项目的输入和输出文件夹。所有源文件都位于其中src,生成的文件位于 中build

现在让我们实际创建文件夹并将文件src移动到其中。我们也可以删除旧的构建文件夹():index.mdsrc_site

mkdir src
mv index.md src
rm -rf _site
Enter fullscreen mode Exit fullscreen mode

最后,请务必重启 Eleventy。我们的网站没有变化,但现在所有生成的文件都将存储在 中build

你可能已经注意到,在我们的配置文件中,函数定义接收一个名为 的参数config。这允许进行更高级的配置。我们稍后会讨论一个例子。

Nunjucks 模板及前言

到目前为止,我们一直只使用 Markdown 文件来定义静态网站的内容。现在让我们创建一个名为 的Nunjucks模板,src/page.njk其内容如下:

<!DOCTYPE html>
<head>
  <meta charset="utf-8"/>
  <meta name="viewport" content="width=device-width, initial-scale=1"/>
  <title>A new website</title>
</head>
<body>A sample page here</body>
</html>
Enter fullscreen mode Exit fullscreen mode

一旦我们保存了这个新文件,构建将生成一个新页面,我们可以在localhost:8080/page上看到它。

使用 Nunjucks 生成的示例页面

有趣的是,现在如果我们在源模板中更改任何内容,浏览器将自动刷新并显示最新更改的结果。

这是因为,一旦我们拥有完整的 HTML 结构,Eleventy 就会在页面中注入一个BrowserSync脚本,该脚本会在每次更改时自动重新加载页面。请注意,此代码仅在运行时(通过开发 Web 服务器接收页面时)注入到 HTML 页面中,它实际上并不存在于生成的 HTML 中。因此,您无需执行任何特殊操作即可生成可部署到生产服务器的构建版本。无论如何,如果您只想生成构建版本,而不启动开发 Web 服务器,则可以通过运行 来实现eleventy build

但是现在让我们进一步讨论一下模板。

在 Eleventy 中,markdown ( .md)、Nunjucks ( .njk) 以及许多其他文件类型(查看完整列表)被称为模板。这些文件可以用作生成页面的框架。Eleventy 会自动在源文件夹中搜索这些文件,并默认为每个文件生成一个页面。稍后我们将看到如何使用单个模板生成多个页面。

模板顶部可以有一个前置部分,可用于定义一些额外的元数据。

必须在文件顶部指定 frontmatter 部分,并用---以下示例分隔:

---
name: someone
age: 17
---
Rest of the file
Enter fullscreen mode Exit fullscreen mode

在前言中,元数据使用 YAML 指定,如果这对您的特定用例有意义,您甚至可以拥有嵌套属性。

在我们的项目中,我认为使用 frontmattertitle为我们的新模板添加属性是有意义的:

---
title: A NOT SO NEW website
---
<!DOCTYPE html>
<head>
  <meta charset="utf-8"/>
  <meta name="viewport" content="width=device-width, initial-scale=1"/>
  <title>{{ title }}</title>
</head>
<body>A sample page here</body>
</html>
Enter fullscreen mode Exit fullscreen mode

{{ variableName }}请注意,如何使用所选模板语言的插值语法(就 Nunjucks 而言)在我们的模板中直接使用前置部分的数据。

布局

如果我们希望所有生成的页面(或部分页面)具有相同的 HTML 结构,该怎么办?此外,如果我们喜欢使用 Markdown,理想情况下,我们希望生成的 HTML 被包装在一个包含headbody部分的正确 HTML 布局中。

使用 Eleventy,我们可以通过使用布局来实现这一点。

布局可以存储_includes在源文件夹的目录中。这是一个特殊的文件夹。实际上,Eleventy 不会为 Markdown、Nunjucks 或此文件夹中的其他模板文件生成页面。Eleventy 还会确保放置在此处的所有文件都易于被我们选择的模板语言访问。

让我们创建我们的第一个布局src/_includes/base.njk

---
title: My default title
---
<!DOCTYPE html>
<head>
  <meta charset="utf-8"/>
  <meta name="viewport" content="width=device-width, initial-scale=1"/>
  <title>{{ title }}</title>
</head>
<body>
  <main>
    {{ content | safe }}
  </main>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

请注意,特殊变量content是放置主要内容(来自模板)的位置。我们使用该过滤器safe是因为我们希望来自模板的 HTML 被逐字应用(不包含转义文本)。

如果没有safe来自模板的 HTML,<h1>Hello from Eleventy</h1>则将呈现如下内容:

<!-- ... -->
<body>
  <main>
    &lt;h1&gt;Hello from Eleventy&lt;/h1&gt;
  <main>
</body>
Enter fullscreen mode Exit fullscreen mode

这当然不是我们想要的……

现在我们可以返回并编辑index.md以使用我们的基本模板:

---
layout: base
---

# Hello from Eleventy

This is a simple Eleventy demo
Enter fullscreen mode Exit fullscreen mode

现在我们可以尝试重新加载我们的索引页并在浏览器中检查页面的源代码!

使用基本布局生成的页面

复制静态文件

如果我们想在生成的页面中添加一些样式怎么办?该如何添加 CSS?当然,我们可以轻松地在模板和布局中添加内联 CSS,但是如果我们想包含外部 CSS 文件怎么办?

让我们创建src/_includes/style.css

html, body {
  background-color: #eee;
  margin: 0;
}

main {
  box-sizing: border-box;
  max-width: 1024px;
  min-height: 100vh;
  padding: 2em;
  margin: 0 auto;
  background: white;
}
Enter fullscreen mode Exit fullscreen mode

现在我们如何确保这个 CSS 文件被复制到构建文件夹?

让我们编辑配置.eleventy.js

module.exports = function (config) {
  config.addPassthroughCopy({ './src/_includes/style.css': 'style.css' })

  // ...
}
Enter fullscreen mode Exit fullscreen mode

调用该addPassthroughCopy函数本质上是告诉 Eleventy,对于每次构建,给定的源文件都需要(按原样)复制到构建文件夹中的给定目标。

查看构建文件夹,我们会style.css在那里看到!如果没有找到,请尝试重新启动 Eleventy 构建。

我们现在可以通过在块中添加以下代码来更新默认布局以引用此样式表head

<link rel="stylesheet" href="/style.css"/>
Enter fullscreen mode Exit fullscreen mode

style.css这将在页面加载时实质上通知浏览器从我们的文件中加载 CSS 样式。

在我们的基本布局中添加了一些样式表

您可以使用相同的技术将客户端 JavaScript 文件、图像、视频或其他静态资产复制到您的构建文件夹中。

全局数据文件

在构建静态站点时,我们通常有一些“全局”数据,希望能够在模板和布局中引用这些数据。

仅举一个非常简单的例子,我喜欢将所有网站元数据(作者信息、版权信息、域名、谷歌分析 ID 等)保存在一个专用文件中。

让我们创建一个包含一些通用站点信息的文件./src/_data/site.js

'use strict'

module.exports = {
  author: 'Luciano Mammino',
  copyrightYear: (new Date()).getFullYear()
}
Enter fullscreen mode Exit fullscreen mode

该文件夹_data是另一个特殊的数据文件夹。其中的每个js文件都json将被预处理,并使用文件名(site在本例中)作为变量名。

现在我们可以更新基本布局并添加页脚:

{# ... #}

<main>
  {{ content | safe }}
<hr/>
<small>A website by {{ site.author }} - &copy; {{ site.copyrightYear }}</small>
</main>

{# ... #}
Enter fullscreen mode Exit fullscreen mode

该网站现在有一个由数据文件中的数据填充的页脚

集合 API

在构建静态网站时,经常需要将内容文件按逻辑类别分组。例如,如果是一个博客,我们会收集博客文章,甚至可以按主题对它们进行分组。

让我们尝试创建一些示例博客文章:

echo -e "---\ntitle: Post 1\nlayout: base\n---\n# post 1\n\nA sample blog post 1" > src/post1.md
echo -e "---\ntitle: Post 2\nlayout: base\n---\n# post 2\n\nA sample blog post 2" > src/post2.md
echo -e "---\ntitle: Post 3\nlayout: base\n---\n# post 3\n\nA sample blog post 3" > src/post3.md
Enter fullscreen mode Exit fullscreen mode

现在让我们在每篇博文的头条中添加标签“posts”:

---
tags: [posts]
---
Enter fullscreen mode Exit fullscreen mode

现在,如果我们想在另一个模板中显示所有帖子,我们可以通过访问特殊变量来实现collections.post。例如,我们可以将以下内容添加到src/index.md

{% for post in collections.posts %}
- [{{ post.data.title }}]({{ post.url }})
{% endfor %}
Enter fullscreen mode Exit fullscreen mode

在主页中显示帖子列表

对于模板中的每个标签,eleventy 都会保存一个以该标签命名的集合。然后,我们可以使用 访问该集合中的模板列表collections.<name of the tag>

还有一个名为 的特殊集合collections.all,其中包含所有模板。它可用于生成站点地图或 ATOM feed。

对于集合中的每个元素,我们都可以使用特殊属性访问该模板 frontmatter 中的数据.data。在我们的示例中,我们这样做是为了访问该title属性。此外,还有一些特殊属性,例如urldate,我们可以使用它们来访问 Eleventy 自身添加的其他元数据。

使用动态内容

现在,如果我们想从 REST API 等外部源获取一些数据怎么办?

使用 Eleventy 确实很容易!

对于本教程,我们可以使用一个令人惊叹的免费 API,它允许我们访问吉卜力工作室制作的所有电影的信息,我们可以在ghibliapi.herokuapp.com上找到这些信息。

例如,我们可以调用此 APIhttps://ghibliapi.herokuapp.com/films/来获取所有电影的列表。

使用 Ghibli API 获取吉卜力工作室电影列表

这对我们来说是一个很好的 API,我们可以尝试使用 Eleventy 为每部电影生成一个新页面。

由于我们想要缓存此调用的结果,为了避免在每次构建时反复调用它,我们可以使用@11ty/eleventy-cache-assets

npm i --save-dev @11ty/eleventy-cache-assets
Enter fullscreen mode Exit fullscreen mode

现在让我们创建src/_data/movies.js

'use strict'

const Cache = require('@11ty/eleventy-cache-assets')

module.exports = async function () {
  return Cache('https://ghibliapi.herokuapp.com/films/', { type: 'json' })
}
Enter fullscreen mode Exit fullscreen mode

现在我们可以movies在任何模板或布局中访问该数组。

为每部电影创建一个页面

让我们创建一个名为src/movie-page.md

---
layout: base
permalink: /movie/{{ movie.title | slug }}/
pagination:
  data: movies
  size: 1
  alias: movie
eleventyComputed:
  title: "{{ movie.title }}"
---

## {{ movie.title }}

  - Released in **{{ movie.release_date }}**
  - Directed by **{{ movie.director }}**
  - Produced by **{{ movie.producer }}**

{{ movie.description }}

[<< See all movies](/movies)
Enter fullscreen mode Exit fullscreen mode

这里有很多内容需要解开!我们先从讨论pagination前言中的属性开始。

这个特殊属性告诉 Eleventy 从这个模板开始生成多个页面。具体生成多少页?这取决于pagination.datapagination.size属性。

pagination.data属性告诉 Eleventy 我们要迭代哪个数据数组,而pagination.size它用于将数组划分为多个块。在本例中,通过指定1size,我们实际上是告诉 Eleventy 为数组中的每个元素生成一个页面movies

当使用分页 API时,我们可以通过指定 来引用当前元素(每页 1 个元素的情况),alias在我们的例子中我们将其定义为movie

此时,我们可以使用permalink属性指定每个页面的 URL。注意我们如何插入movie变量以从当前电影中提取数据。

如果我们需要定义特定元素的 frontmatter 数据,可以使用 specialeleventyComputed属性来实现。在我们的示例中,我们这样做是为了确保每个生成的页面都有自己的标题。

如果我们想看看其中一个页面的样子,我们可以访问localhost:8080/movie/ponyo/

为电影《悬崖上的金鱼姬》生成的页面

现在我们可以轻松创建索引页来链接所有电影src/movies.md

---
layout: base
title: Studio Ghibli movies
---

# Studio Ghibli movies

{% for movie in movies %}
- [{{ movie.title }}](/movie/{{ movie.title | slug }})
{% endfor %}
Enter fullscreen mode Exit fullscreen mode

索引页显示吉卜力工作室的所有电影

花点时间浏览一下,希望能了解一些新电影!😎

结束了🌯

我们的 Eleventy 教程到此结束!

在本文中,我们了解了以下主题:

  • 如何安装 Eleventy 并从头开始启动一个新项目
  • 创建一个简单的“Hello world”网站
  • 提供自定义配置
  • 模板、前言和布局
  • 使用实时重新加载
  • 复制静态文件
  • 自定义全局数据
  • 集合 API
  • 使用来自外部来源的动态数据
  • 分页 API

我们可以用 Eleventy 做更多的事情,因此请务必查看Eleventy 官方文档以了解更多信息。

如果您发现这篇文章很有趣,请关注我这里,在Twitter上,并查看我的个人网站/博客以获取更多文章。

此外,如果您喜欢 Node.js,请考虑查看我的书《Node.js 设计模式》

Node.js 设计模式书籍由 man 持有

谢谢!👋

附言:特别感谢推特上的Ben White提供的一些有用的反馈!

鏂囩珷鏉ユ簮锛�https://dev.to/loige/getting-started-with-eleventy-in-11-minutes-496j