深入了解 11 个静态站点生成器
已发表: 2022-03-10但首先——让我们快速回顾一下“静态站点”的含义以及生成器提供的内容。 静态网站由静态内容组成——例如,HTML、CSS、资产和所有内容在推送到网站主机之前已经编译在一起。 这与动态站点不同,后者通过在运行时查询数据库(如 WordPress)或从客户端的 API 提取内容(如没有服务器端呈现的 JavaScript 框架)来编译这些内容。
静态站点生成器是一个环境和构建处理器,用于将您的内容编译成静态 HTML。 它们通常会提供帮助程序以提供编写内容的灵活性(例如支持 Markdown)并包含模板方法。 因此,生成器将支持通过某种模板语言将这些内容分解为组件,而不是一个一个地编写 HTML 页面并复制和粘贴重复的部分。 然后生成器的构建过程会将所有内容组合在一起并输出最终的 HTML,该 HTML 可以上传到网络主机作为您的网站。 根据您使用的网络主机,此构建过程甚至可以由主机完成。
有许多可用的静态站点生成器。 您可能听说过甚至使用过 Jekyll、Hugo、Gatsby、Next 和 Nuxt 等。 Jamstack.org 提供了一个完整的列表。
是什么让 Eleventy 与其他静态站点生成器不同?
Eleventy 在构建期间和浏览器中都非常快。 这在很大程度上要归功于不需要加载客户端 JavaScript 包来提供内容(与 Gatsby 之类的东西相比)。 服务器端渲染在这里甚至不是问题,因为文件系统页面创建默认为静态 HTML。
真正让 Eleventy 与众不同的是能够从多达十种不同的模板语言中进行选择和混合:
混合语言可以发生在同一个文件中,也可以在布局之间发生。 例如,我经常使用 Markdown 编写我的主要内容,这些内容会输入 Nunjucks 布局。 在某些项目中,我发现能够在 Markdown 文件中使用 Nunjucks 循环访问一些数据很有用。 这种组合语言的能力非常强大,允许您设计一个最适合您和您的项目的编写和构建工作流程。
Eleventy 包含一个--serve
标志,该标志使用 BrowserSync 来启用在本地为站点提供服务,并在文件更改时进行热重载。 这是一个极大的便利,如果您不是在寻找静态站点生成器,而是从 Gulp 等构建工具升级,请记住这一点。
作为零配置的一部分,您的所有站点文件都可以位于项目的根目录中。 要更改输入和输出目录,您可以创建一个 Eleventy 配置,它应该是一个名为.eleventy.js
的根文件。 这是一个快速片段,显示如何进行此修改:
module.exports = function (eleventyConfig) { return { dir: { // default: [site root] input: "src", // default: _site output: "public", }, }; };
如前所述,默认行为是创建文件系统页面,这通常有很大的好处,特别是对于快速入门。 这很容易通过分配自定义permalink
来覆盖,并且可以为每个文件、整个目录或动态一组数据完成。 固定链接还提供了另一种超能力,我们稍后将对其进行探索!
独特的是,在构建过程中,您可以通过使用 JavaScript 并利用过滤器和短代码(我们稍后将讨论)来准备内容、数据和对该内容和数据的转换。 同样,这一切都发生在没有添加 JavaScript 包客户端的情况下,同时仍然可以使用 JavaScript 作为模板语言。
重要提示:您可以在没有 JavaScript 知识或 JavaScript 知识很少的情况下成功使用 Eleventy。
与 Gatsby 等其他 SSG 或 WordPress 等环境不同,大多数 Eleventy 网站不需要任何插件。 有一些插件可用,但它们对于基本功能不是必需的。
使用 Eleventy 构建时,您可以根据需要添加功能。 事实上,您可以只使用 HTML 而不使用任何其他模板语言。 Eleventy 的复杂程度取决于您的项目要求!
了解基本的 11 个概念
让我们回顾一下有助于您成功创建 Eleventy 项目的一些术语和概念。
布局和模板
您可能认为这些术语可以互换,但在 Eleventy 的上下文中,它们确实具有上下文含义:
- 模板是所有内容文件的通用术语。
- 布局是包装其他内容的特殊模板。
例如,模板引用您的所有 Markdown 文件,而布局可能是一个 Nunjucks 文件,其中包含 HTML5 样板和模板内容的插槽。 我们将在“入门”部分学习如何完成这项工作。
过滤器和简码
这些是修改内容输出和创建可重用模板部件的其他方法。 它们可用于 Nunjucks、Liquid、Handlebars 和 JavaScript 模板。 过滤器和简码在.eleventy.js
中定义。
除了您选择的模板语言中可用的变量和运算符之外,Eleventy 还统一了之前列出的语言中的过滤器概念。 过滤器以某种特定于内容类型的方式转换内容。 例如,您可以创建一个过滤器,用于将字符串大写。 或者你可能有一个过滤器打算在数组上使用来改变返回的内容,比如选择一个随机项目。 Eleventy 提供了一些过滤器,其中一些我们将在入门教程中使用。
简码允许创建可重用的模板部分并且能够接受参数。 它们可以是独立的或成对的,这意味着它们用开始和结束标签包装内容。
我最喜欢的简码之一是呈现当前年份——这意味着您的页脚中不再有过时的版权年份! 以下是创建year
短代码的方法:
eleventyConfig.addShortcode("year", () => `${new Date().getFullYear()}`);
要在 Nunjucks 或 Liquid 模板中使用它,如下所示: {% year %}
。
您可以查看 Eleventy 文档以获取配对短代码的示例。
收藏品
集合是相关内容的组,通常通过定义tags
在 frontmatter 中创建。 标记语法选项包括单个字符串、单行数组 — ["tagA", "tagB"]
— 用于多个标记或 YAML 样式列表以分配多个标记。 例如,我可以通过将以下 frontmatter 添加到我希望包含在该集合中的所有内容来创建一个“页面”集合:
--- tags: pages ---
一旦你定义了一个集合,你可以通过你在全局collections
对象中选择的模板语言来访问它。 访问我们的“页面”集合看起来像collections.pages
。 这将返回该集合数据的数组,因此您可以执行数组操作,例如对其进行循环,例如生成链接列表或文章预告卡。 您甚至可以抑制正常的文件输出并仅使用集合来管理数据显示,这对于管理单页站点内容很有用。
自定义数据
到目前为止,我们已经讨论了将内容创建为文件,但 Eleventy 还使维护不同的数据源变得非常容易。 这称为“自定义数据”,在_data
目录中以 JavaScript 模块导出或 JSON 文件的形式存在。
自定义数据可用于:
- 定义一个基本的 JSON 数组。
- 返回 fetch 操作的结果。
- 从无头 CMS 中检索和重新格式化内容。
_data
使 _data 中的所有数据在与文件名匹配的变量下可用。 例如,如果我创建posts.json
,那么我可以在我的模板中以posts
的形式访问它。 使用 Nunjucks,这是一个循环遍历posts
数据的示例:
{% for post in posts %} {{ post.title }} {% endfor %}
分页和从数据创建页面
在 Eleventy 术语中,分页是指遍历数据集并为该数据“块”的输出定义模板。 这是通过定义 frontmatter 中的分页的专用文件完成的。 该文件还包括为数据设置您的预期输出,这意味着它也成为自己的模板。 我们可以定义一个布局来发送内容,也可以添加标签来创建一个集合,以便于参考和灵活的输出。
注意:如果您使用自定义数据从 CMS 中检索内容,那么分页是您正在寻找的 Eleventy 方法,可以动态地将数据转换为页面。
这是一个引用我们的posts
自定义数据的示例,我们假设我们是通过从无头 CMS 中获取来检索的。 重要的是, size
设置为 1,这意味着每个“分页块”应该产生一页输出。 然后,我们使用alias
在分页循环中创建对当前项目的引用,然后在permalink
定义和模板正文中使用该引用。
定义分页的文件可以放在输入目录中的任何位置。 我的组织偏好是创建一个generate
目录,然后将其命名为与将要创建的集合相同的名称。 考虑以下是src/generate/posts.njk
:
--- pagination: data: posts size: 1 alias: post addAllPagesToCollections: true permalink: "/{{ post.title | slug }}/" tags: posts layout: post templateEngineOverride: njk, md --- {{ post.body | safe }}
在这种情况下, permalink
将页面分配为直接从站点根目录输出。 您可以更改它以添加前缀,例如/posts/{{ post.title | slug }}
/posts/{{ post.title | slug }}
,例如。
此外,如果您希望所有生成的页面在由标签创建的集合中可用,则必须将addAllPagesToCollections
设置为true
以包含比第一项更多的内容。
最后,如果你的内容是以 Markdown 的形式出现而不是预编译的 HTML,你需要使用templateEngineOverride
。 在示例代码段中,我将其设置为njk, md
,这意味着模板内容需要作为 Nunjucks 进行处理才能转换变量,然后使用 Markdown 编译变量中返回的内容。
如果您想知道safe
的含义,我们将在接下来学习!
如何开始使用十一
好的,所以你已经准备好开始你的第一个 Eleventy 项目了! 这个简短的教程将帮助您建立一个起始结构以继续构建。 我们将使用我们已经了解的概念并添加一些新想法。
这里的第一个重要说明是 Eleventy 是一个作用域包,所以这里是安装命令:
npm install @11ty/eleventy
接下来,我喜欢做的一个方便的事情是将以下脚本添加到我的package.json
中:
"scripts": { "start": "eleventy --serve", "build": "eleventy" }
如前所述, --serve
标志将通过 BrowserSync 启用本地服务器。
我的偏好是更新我们已经看过的输入/输出目录,所以现在是时候在src
或您选择的输入目录中创建一些内容了。
为了让我们的项目从一开始就更加灵活和可扩展,我建议创建至少一个包含 HTML5 样板的布局。 布局需要在直接调用的_includes
中定义,这是少数预期目录之一。
您在初学者中经常会发现的一个约定是将此布局称为base
。 我倾向于将其设为 Nunjucks 文件。
这是一个示例base.njk
:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>{{ title }}</title> </head> <body> <header> <h1>{{ title }}</h1> </header> <main> {{ content | safe }} </main> </body> </html>
双花括号是用于变量的 Nunjucks 语法。 在这里,我们已经为即将通过前端提供的传入title
变量做好了准备。 content
变量由 Eleventy 提供,并标记所有传入的非前端内容应该去的位置。 重要的是,它与提供的safe
过滤器结合使用,可防止编译的 HTML 被转义和呈现。
现在是时候创建我们的站点索引了,我们将其添加为index.md
:
--- title: Hello Smashing Readers! layout: base.njk --- Thanks for reading — hope you're excited to try Eleventy!
请注意,在前面的内容中,我们添加了标题,还定义了布局。
此时,我们可以使用我们添加的脚本运行我们的项目: npm start
。 这将触发 BrowserSync 设置localhost:8080
(如果可用),但您需要在浏览器中手动打开它。 如果您希望它自动打开浏览器,请查看此快速提示。
最后一个关键步骤是添加样式表。 目前,CSS 不被识别为自动包含的文件类型,因此我们在创建样式表后将有一个额外的配置步骤。
您可以在输入目录中的任意位置添加 CSS 文件,例如css/style.css
。 然后,打开.eleventy.js
(如果您没有进行输入/输出自定义,则在项目根目录中创建它)并添加以下内容:
module.exports = function (eleventyConfig) { eleventyConfig.addPassthroughCopy("./src/css/"); eleventyConfig.addWatchTarget("./src/css/"); // - input/output customization if using - };
首先,我们将css
目录添加为“直通副本”,这意味着 Eleventy 应该将其包含在推送到输出目录中。 然后我们还将它添加为“监视目标”,这样当我们在运行start
命令时更改样式时,Eleventy 将触发重建以更新我们的本地站点。
最后,我们需要记住在base
布局中添加样式表的链接:
<link rel="stylesheet" href="{{ '/css/style.css' | url }}" />
当我们定义样式表的位置时,我们将它传递给 Eleventy 的url
过滤器,该过滤器将在构建时根据需要调整相对文件路径。
接下来,让我们创建一个“页面”帖子类型来进一步探索使用集合和布局。 为此,请添加pages
目录并创建一个或两个 Markdown 文件,包括title
前置键但不包括布局。
这次我们将使用一种稍微不同的方法来定义布局——数据目录文件。 此文件通常格式化为 JSON,使我们能够添加应应用于目录中所有文件的数据,从而避免跨文件复制它。 该文件需要与将使用的目录命名相同,因此创建文件pages.json
并添加以下内容:
{ "layout": "page.njk", "tags": "pages" }
我们还继续定义标签以创建“页面”集合。 但是我们定义的布局实际上还不存在,所以创建_includes/page.njk
并添加以下内容:
--- layout: base.njk --- <article> {{ content | safe }} </article>
在这里,我们使用了布局链的 Eleventy 概念,以便能够重用我们的base
模板,同时也为我们的page
布局添加一个独特的元素,即<article>
。 这意味着我们页面的所有内容都将使用page
布局和base
布局。
布局链接通过允许重复使用样板和基础站点布局结构来减少重复。
现在我们已经为pages
内容类型创建了内容,并通过标签将其定义为“pages”集合,让我们看看如何访问该集合。 在这里,我们将使用 Nunjucks 循环遍历集合并输出每个页面的链接列表。 这个循环将被添加到我们的index.md
文件中。
{% for post in collections.post -%} - [{{ post.data.title }}]({{ post.url }}) {% endfor %}
我们做了一些独特的事情,那就是循环内部实际上切换回 Markdown 来呈现链接。 这不是处理这种情况的必需方法,但它可以非常方便! 有时,根据复杂性,这可能不起作用。 真正的原因是 Markdown 渲染器默认使用Liquid模板语言,所以如果您使用 Nunjucks 功能超出基本循环,您必须让 Eleventy 知道如何处理文件。
在前面关于分页的部分中,我们实际上已经研究了解决方案。 那就是利用templateEngineOverride
来指示文件应该作为 Nunjucks 和 Markdown 处理。 以下完整的解决方案应该放在模板的前面: templateEngineOverride: njk, md
。
至此,您已经创建了一个基本的多页站点! 如果您需要使用外部数据,请跳回分页部分。
启动 Eleventy 项目的其他方法
尽管其他一些静态站点生成器和环境(如 WordPress)具有“主题”的概念,但 Eleventy 使用术语“启动器”。 可供选择的集合越来越多,许多可以在 Eleventy 文档的列表中找到。
我的偏好是在我的 Eleventy 项目中使用 Sass,如果您想了解如何将其添加到构建过程中,我可以使用 Sass 启动器。 如果其他人习惯于为资产和处理构建管道,他们可能会选择添加 Gulp。
我还创建了一个包含本文中讨论的功能并与教程结果有相似之处的最小启动器。 它还有一个获取外部数据的小示例,并展示了如何添加部分以显示基于集合的站点导航。
扩展基础
一旦您尝试使用一些基本内容和一些自定义数据创建您的第一个站点,了解使用该内容的其他方法会很有帮助。 以下是一些其他需要注意的概念的简要概述。
使用永久链接更改文件输出类型
我之前提到过永久链接有一种超能力。 那就是您可以使用它们来输出非 HTML 文件类型。
两个有用的示例是创建一个 RSS 提要和一个站点地图,这两者通常都是 XML 文件。 真正强大的是,您可以继续使用您选择的模板语言来帮助生成这些文件,例如,您可以使用 Nunjucks 循环页面数据以保持您的 RSS 提要新鲜。
自定义集合
有时使用标签创建集合可能还不够。 或者,您可能想要创建现有集合的过滤变体。 我们可以使用一系列提供的函数来更改或创建集合。 这些将存在于.eleventy.js
配置文件中。
在此示例中,我们使用addCollection
函数过滤现有集合中的项目。 新集合将基于前面事项中customKey
的存在。 该键是从附加到所有生成的 Eleventy 内容的data
对象中返回的。
eleventyConfig.addCollection("specialCollection", function (collection) { return collection.getAll().filter((post) => post.data.customKey); });
您可以在 Eleventy 文档中查看创建、修改和使用集合的其他方法。
使用数据级联
Eleventy 对如何为称为数据级联的模板编译数据有一个更完整的概念,我们在本指南中才刚刚开始探索。 如果您从文档开始查看它的工作原理,您将充分利用 Eleventy。 Ben Myers 也有一个很好的理解数据级联的指南。
推荐的 11 个插件
在介绍中,我简要提到有可用的插件,但并不总是需要它们。 但是,我倾向于在大多数项目中使用一些,其中包括:
- @11ty/eleventy-plugin-rss 如果你想要一个 RSS 提要,这个官方插件提供了一些过滤器来帮助你生成提要。 链接的 repo 包含一个示例提要,您也可以在某些启动器中找到该提要。
- @11ty/eleventy-plugin-syntaxhighlight 这个插件不是将 Prism 作为代码高亮的脚本加载,而是允许将该处理作为 Eleventy 构建过程的一部分应用。 这意味着代码块被转换为包含提前应用 Prism 主题的类,因此您只需要添加您选择的 Prism CSS 主题。
- @11tyrocks/eleventy-plugin-social-images 我在 Eleventy 探索早期发现的一个功能是生成社交媒体共享图像的能力。 这导致我创建了一个插件,它在幕后使用 Puppeteer 来拍摄快照。 该插件带有预构建的模板以及用于定义您自己的模板文件的配置选项。
我还建议您熟悉其他官方 Eleventy 插件,因为它们解决了其他常见需求,包括导航和图像处理。
确定 Eleventy 是否适合您的项目
Eleventy 与大多数静态网站一样,最适合通常不需要动态或按需提供的内容。 这并不是说所有网站都必须是静态的,或者没有办法使内容动态化。 您仍然可以加载 JavaScript 以启用动态内容,例如从 API 获取或创建交互式小部件。 如果您的主机支持构建 webhook 并且您有想要按计划刷新的部分,您还可以使用 IFTTT 或 Zapier 等服务来帮助重建您的站点。
多亏了自定义数据和分页,我们看到很容易包含来自无头 CMS 或任何其他 API 的外部数据。 因此,尽管它将以静态方式提供服务,但您在提取内容的位置和管理方式方面仍然具有很大的灵活性。
关于 Eleventy,我最喜欢的一点是,除了我们为_includes
和_data
讨论过的少数预期目录(您也可以更新它们的命名约定)之外,它不会对我应该如何构建我的网站提出太多意见。 如果您希望迁移站点并且还能够潜在地移动某些现有文件结构,这也很有帮助。 但是,如果您更喜欢固执己见的架构,您可能会寻求不同的选择。
我也很享受如何通过利用多种模板语言以及过滤器、短代码和布局来塑造 Eleventy 以适应给定项目的心智模型。 初学者也有助于提升,以便您可以专注于真正重要的事情:您的内容。 而纯静态输出的高性能也是一大利好。
如果您在构建过程中确实需要更多内容,您可以添加其他熟悉的工具,例如 Webpack、Gulp 或 Parcel。 您也许可以找到已经包含这些内容的启动器。 请记住,您还可以利用 Eleventy 构建过程固有的 Node 脚本。
Eleventy 非常有能力处理大量的页面生成。 它已被用于一些大型和复杂的网站,例如 Google 的 web.dev 和 Netlify 的营销网站。 我还将 Eleventy 用于一些非常规用途,例如电子邮件和 Web 组件生成器,以及本概述中描述的其他一些用途。
其他资源
我希望本指南既能激发您的兴趣,又能让您为开始使用 Eleventy 做好准备! 它包含了很多点,当我用它创建我的第一个项目时,我发现这些点有点难以发现。 自从我在 2020 年 4 月第一次找到 Eleventy 以来,我已经构建了 20 多个 Eleventy 项目,包括初学者、插件、辅助项目和课程资料。 其中许多可以在我的网站 11ty.Rocks 上找到,该网站也有教程和技巧。 Eleventy 是我非常喜欢讨论的话题,所以请随时在 Twitter 上联系!
以下是帮助您学习和充分利用 Eleventy 的更多资源:
- Andy Bell 提供了一个非常全面的付费课程——“从零开始学习十一”。
- Tatiana Mac 的教程系列,从“11 岁初学者指南”开始,提供了详尽的解释,假设以前没有使用静态站点生成器的经验。
- Bryan Robinson 提供了一个 YouTube 课程,用于将免费的 HTML 主题转换为 Eleventy 网站。
最后,我要指出的是,Eleventy 社区虽小但很活跃! 如果您在查找某些信息时遇到困难,可以将您的问题推特到官方@eleven_ty 帐户。 Eleventy 的创建者 Zach Leatherman 可以快速回答或 RT 问题,帮助您重回正轨!