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
安装 Eleventy 并建立我们的第一个站点
Eleventy 可以使用 npm 安装。你可以在系统中全局安装它,但我个人更喜欢将其作为特定项目的开发依赖项安装。这样,你可以根据需要在不同项目中使用不同版本的 Eleventy。
npm i --save-dev @11ty/eleventy
现在让我们为 Eleventy 项目创建一个索引文件:
echo "# My sample Eleventy website" > index.md
此时,我们已准备好运行 Eleventy:
node_modules/.bin/eleventy --watch --serve
当然,为了简单起见,我们可以将这个脚本放在我们的package.json:
// ...
"scripts": {
"start": "eleventy --watch --serve"
},
// ...
现在我们只需运行以下命令即可更轻松地运行 Eleventy:
npm start
我们现在可以在localhost:8080看到我们的网站。
创建自定义配置文件
Eleventy 遵循一些默认约定,但它也非常灵活,允许您更改这些默认设置。
如果您出于某种原因希望更改默认文件夹结构或支持的模板语言等,这将非常方便。
为了向 Eleventy 提供我们的自定义配置,我们必须.eleventy.js在项目的根文件夹中创建一个名为的文件:
module.exports = function (config) {
return {
dir: {
input: './src',
output: './build'
}
}
}
通过此特定配置,我们将重新定义项目的输入和输出文件夹。所有源文件都位于其中src,生成的文件位于 中build。
现在让我们实际创建文件夹并将文件src移动到其中。我们也可以删除旧的构建文件夹():index.mdsrc_site
mkdir src
mv index.md src
rm -rf _site
最后,请务必重启 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>
一旦我们保存了这个新文件,构建将生成一个新页面,我们可以在localhost:8080/page上看到它。
有趣的是,现在如果我们在源模板中更改任何内容,浏览器将自动刷新并显示最新更改的结果。
这是因为,一旦我们拥有完整的 HTML 结构,Eleventy 就会在页面中注入一个BrowserSync脚本,该脚本会在每次更改时自动重新加载页面。请注意,此代码仅在运行时(通过开发 Web 服务器接收页面时)注入到 HTML 页面中,它实际上并不存在于生成的 HTML 中。因此,您无需执行任何特殊操作即可生成可部署到生产服务器的构建版本。无论如何,如果您只想生成构建版本,而不启动开发 Web 服务器,则可以通过运行 来实现eleventy build。
但是现在让我们进一步讨论一下模板。
在 Eleventy 中,markdown ( .md)、Nunjucks ( .njk) 以及许多其他文件类型(查看完整列表)被称为模板。这些文件可以用作生成页面的框架。Eleventy 会自动在源文件夹中搜索这些文件,并默认为每个文件生成一个页面。稍后我们将看到如何使用单个模板生成多个页面。
模板顶部可以有一个前置部分,可用于定义一些额外的元数据。
必须在文件顶部指定 frontmatter 部分,并用---以下示例分隔:
---
name: someone
age: 17
---
Rest of the file
在前言中,元数据使用 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>
{{ variableName }}请注意,如何使用所选模板语言的插值语法(就 Nunjucks 而言)在我们的模板中直接使用前置部分的数据。
布局
如果我们希望所有生成的页面(或部分页面)具有相同的 HTML 结构,该怎么办?此外,如果我们喜欢使用 Markdown,理想情况下,我们希望生成的 HTML 被包装在一个包含head和body部分的正确 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>
请注意,特殊变量content是放置主要内容(来自模板)的位置。我们使用该过滤器safe是因为我们希望来自模板的 HTML 被逐字应用(不包含转义文本)。
如果没有safe来自模板的 HTML,<h1>Hello from Eleventy</h1>则将呈现如下内容:
<!-- ... -->
<body>
<main>
<h1>Hello from Eleventy</h1>
<main>
</body>
这当然不是我们想要的……
现在我们可以返回并编辑index.md以使用我们的基本模板:
---
layout: base
---
# Hello from Eleventy
This is a simple Eleventy demo
现在我们可以尝试重新加载我们的索引页并在浏览器中检查页面的源代码!
复制静态文件
如果我们想在生成的页面中添加一些样式怎么办?该如何添加 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;
}
现在我们如何确保这个 CSS 文件被复制到构建文件夹?
让我们编辑配置.eleventy.js:
module.exports = function (config) {
config.addPassthroughCopy({ './src/_includes/style.css': 'style.css' })
// ...
}
调用该addPassthroughCopy函数本质上是告诉 Eleventy,对于每次构建,给定的源文件都需要(按原样)复制到构建文件夹中的给定目标。
查看构建文件夹,我们会style.css在那里看到!如果没有找到,请尝试重新启动 Eleventy 构建。
我们现在可以通过在块中添加以下代码来更新默认布局以引用此样式表head:
<link rel="stylesheet" href="/style.css"/>
style.css这将在页面加载时实质上通知浏览器从我们的文件中加载 CSS 样式。
您可以使用相同的技术将客户端 JavaScript 文件、图像、视频或其他静态资产复制到您的构建文件夹中。
全局数据文件
在构建静态站点时,我们通常有一些“全局”数据,希望能够在模板和布局中引用这些数据。
仅举一个非常简单的例子,我喜欢将所有网站元数据(作者信息、版权信息、域名、谷歌分析 ID 等)保存在一个专用文件中。
让我们创建一个包含一些通用站点信息的文件./src/_data/site.js:
'use strict'
module.exports = {
author: 'Luciano Mammino',
copyrightYear: (new Date()).getFullYear()
}
该文件夹_data是另一个特殊的数据文件夹。其中的每个js文件都json将被预处理,并使用文件名(site在本例中)作为变量名。
现在我们可以更新基本布局并添加页脚:
{# ... #}
<main>
{{ content | safe }}
<hr/>
<small>A website by {{ site.author }} - © {{ site.copyrightYear }}</small>
</main>
{# ... #}
集合 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
现在让我们在每篇博文的头条中添加标签“posts”:
---
tags: [posts]
---
现在,如果我们想在另一个模板中显示所有帖子,我们可以通过访问特殊变量来实现collections.post。例如,我们可以将以下内容添加到src/index.md:
{% for post in collections.posts %}
- [{{ post.data.title }}]({{ post.url }})
{% endfor %}
对于模板中的每个标签,eleventy 都会保存一个以该标签命名的集合。然后,我们可以使用 访问该集合中的模板列表collections.<name of the tag>。
还有一个名为 的特殊集合collections.all,其中包含所有模板。它可用于生成站点地图或 ATOM feed。
对于集合中的每个元素,我们都可以使用特殊属性访问该模板 frontmatter 中的数据.data。在我们的示例中,我们这样做是为了访问该title属性。此外,还有一些特殊属性,例如url或date,我们可以使用它们来访问 Eleventy 自身添加的其他元数据。
使用动态内容
现在,如果我们想从 REST API 等外部源获取一些数据怎么办?
使用 Eleventy 确实很容易!
对于本教程,我们可以使用一个令人惊叹的免费 API,它允许我们访问吉卜力工作室制作的所有电影的信息,我们可以在ghibliapi.herokuapp.com上找到这些信息。
例如,我们可以调用此 APIhttps://ghibliapi.herokuapp.com/films/来获取所有电影的列表。
这对我们来说是一个很好的 API,我们可以尝试使用 Eleventy 为每部电影生成一个新页面。
由于我们想要缓存此调用的结果,为了避免在每次构建时反复调用它,我们可以使用@11ty/eleventy-cache-assets
npm i --save-dev @11ty/eleventy-cache-assets
现在让我们创建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' })
}
现在我们可以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)
这里有很多内容需要解开!我们先从讨论pagination前言中的属性开始。
这个特殊属性告诉 Eleventy 从这个模板开始生成多个页面。具体生成多少页?这取决于pagination.data和pagination.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 %}
花点时间浏览一下,希望能了解一些新电影!😎
结束了🌯
我们的 Eleventy 教程到此结束!
在本文中,我们了解了以下主题:
- 如何安装 Eleventy 并从头开始启动一个新项目
- 创建一个简单的“Hello world”网站
- 提供自定义配置
- 模板、前言和布局
- 使用实时重新加载
- 复制静态文件
- 自定义全局数据
- 集合 API
- 使用来自外部来源的动态数据
- 分页 API
我们可以用 Eleventy 做更多的事情,因此请务必查看Eleventy 官方文档以了解更多信息。
如果您发现这篇文章很有趣,请关注我这里,在Twitter上,并查看我的个人网站/博客以获取更多文章。
此外,如果您喜欢 Node.js,请考虑查看我的书《Node.js 设计模式》。
谢谢!👋
附言:特别感谢推特上的Ben White提供的一些有用的反馈!
鏂囩珷鏉ユ簮锛�https://dev.to/loige/getting-started-with-eleventy-in-11-minutes-496j









