Eleventy 越来越受欢迎,因为它允许我们创建简洁、简单的网站,而且——它非常开发者友好。我们也可以用它来构建大型的复杂项目。在本教程中,我们将通过将一个强大的、对人类友好的环境变量解决方案整合在一起,来展示这种扩展的能力。
什么是环境变量?
环境变量是方便的变量/配置值,它们在代码所在的运行环境中定义。
例如,假设你有一个 WordPress 网站:你可能希望在你的生产网站上连接到一个数据库,而在你的预发布和本地网站上连接到另一个数据库。我们可以在 wp-config.php
中硬编码这些值,但一个保持连接细节私密并且让你的代码更容易保存在源代码控制(如 Git)中的好方法是在代码之外定义这些值。
这是一个包含硬编码值的标准版 WordPress wp-config.php
代码片段
<?php
define( 'DB_NAME', 'my_cool_db' );
define( 'DB_USER', 'root' );
define( 'DB_PASSWORD', 'root' );
define( 'DB_HOST', 'localhost' );
使用相同的 wp-config.php
文件示例,我们可以引入像 phpdotenv 这样的工具,并将它更改为类似下面的内容,并将值从代码中分离出来
<?php
$dotenv = Dotenv\Dotenv::createImmutable(__DIR__);
$dotenv->load();
define( 'DB_NAME', $_ENV['DB_NAME'] );
define( 'DB_USER', $_ENV['DB_USER'] );
define( 'DB_PASSWORD', $_ENV['DB_PASSWORD'] );
define( 'DB_HOST', $_ENV['DB_HOST'] );
定义这些环境变量值的一种方法是使用 .env
文件,这是一个通常被源代码控制忽略的文本文件。

然后,我们会使用像 dotenv 或 phpdotenv 这样的工具来获取这些值——这些值默认情况下可能对你的代码不可用。像 dotenv 这样的工具非常有用,因为你可以在 .env
文件、Docker 脚本或部署脚本中定义这些变量,并且它会正常工作——这正是我最喜欢的工具类型!
我们倾向于通过 .gitignore
在源代码控制中忽略这些文件的原因是,它们通常包含秘密密钥或数据库连接信息。理想情况下,你应该将这些信息从任何远程存储库(如 GitHub)中移除,以尽可能安全地保护这些信息。
入门
在本教程中,我创建了一些入门文件,以节省我们所有人的时间。这是一个基本的、最精简的 Eleventy 网站,所有枯燥的部分都已完成。
本教程的第一步是 下载入门文件 并将它们解压缩到你想要使用它们的位置。解压缩文件后,在你的终端中打开该文件夹并运行 npm install
。完成后,运行 npm start
。当你在浏览器中打开 http://localhost:8080
时,它应该看起来像这样

此外,在我们设置的时候:创建一个名为 .env
的新空文件,并将其添加到你的基础文件文件夹的根目录。
创建一个友好的界面
环境变量通常非常大声,因为我们使用全大写字母,这可能会让人感到厌烦。我更喜欢做的是创建一个 JavaScript 接口,它使用这些值并将它们导出为对人类友好的、带命名空间的值,这样你就可以通过查看代码来知道你正在使用环境变量。
让我们以 HELLO=hi there
这样的值为例,它可能在我们的 .env
文件中定义。要访问它,我们使用 process.env.HELLO
,经过几次调用后,这会让人感到有点乏味。如果该值没有定义,该怎么办?在这种情况下,提供一个回退值非常方便。使用 JavaScript 设置,我们可以做类似这样的事情
require('dotenv').config();
module.exports = {
hello: process.env.HELLO || 'Hello not set, but hi, anyway 👋'
};
我们在这里做的是查找该环境变量,并在需要时设置一个默认值,使用OR 运算符(||
)来返回一个值(如果它没有定义)。然后,在我们的模板中,我们可以使用 {{ env.hello }}
。
现在我们知道了这种技术的原理,让我们来实现它。在我们的入门文件文件夹中,有一个名为 src/_data
的目录,其中包含一个空的 env.js
文件。打开它,并在其中添加以下代码
require('dotenv').config();
module.exports = {
otherSiteUrl:
process.env.OTHER_SITE_URL || 'https://eleventy-env-vars-private.netlify.app',
hello: process.env.HELLO || 'Hello not set, but hi, anyway 👋'
};
因为我们的数据文件名为 env.js
,所以我们可以在我们的模板中使用 env
前缀来访问它。如果我们希望我们的环境变量以 environment
为前缀,我们应该将我们的数据文件重命名为 environment.js
。你可以阅读 Eleventy 文档中的更多内容。
我们在这里有 hello
值,还有一个 otherSiteUrl
值,我们使用它来允许人们根据他们的环境变量配置查看我们网站的不同版本。这种设置使用了 Eleventy JavaScript 数据文件,它允许我们运行 JavaScript 并将输出作为静态数据返回。它们甚至支持异步代码!这些 JavaScript 数据文件 可能是我最喜欢的 Eleventy 功能。
现在我们已经设置了这个 JavaScript 接口,让我们进入我们的内容并实现一些变量。打开 src/index.md
,并在文件底部添加以下内容
Here’s an example: The environment variable, HELLO is currently: “{{ env.hello }}”. This is called with {% raw %}{{ env.hello }}{% endraw %}.
很酷吧?我们可以使用这些变量直接在我们的内容中使用 Eleventy!现在,当你定义或更改 .env
文件中 HELLO
的值并且重新启动 npm start
任务时,你将看到内容更新。
你的网站现在应该看起来像这样

你可能想知道 {% raw %}
到底是什么。它是一个 Nunjucks 标签,它允许你定义它应该忽略的区域。如果没有它,Nunjucks 将尝试评估示例 {{ env.hello }}
部分。
修改图片基础路径
我们第一个示例很酷,但让我们真正开始探索这种方法如何有用。通常,你希望你的生产图片由某种 CDN 访问,但你可能也希望你的图片在本地开发网站时能够运行。这意味着,为了提高性能和支持各种图片格式,我们通常使用 CDN 为我们提供图片,这些 CDN 通常会直接从你的网站提供图片,例如从你的 /images
文件夹。这正是我在 Piccalilli 上使用 ImgIX 所做的,但这些 CDN 无法访问网站的本地版本。因此,能够在 CDN 和本地图片之间切换非常方便。
这个问题的解决方案对于环境变量来说几乎是微不足道的——特别是对于 Eleventy 和 dotenv 来说,因为如果在使用时没有定义环境变量,就不会抛出任何错误。
打开 src/_data/env.js
,并在对象中添加以下属性
imageBase: process.env.IMAGE_BASE || '/images/',
imageProps: process.env.IMAGE_PROPS,
我们使用 /images/
作为 imageBase
的默认值,因此如果未定义 IMAGE_BASE
,则可以找到我们的本地图片。我们没有对 imageProps
做同样的事情,因为除非我们需要它们,否则它们可以为空。
打开 _includes/base.njk
,在 <h1>{{ title }}</h1>
部分之后,添加以下内容
<img src="{{ env.imageBase }}mountains.jpg{{ env.imageProps }}" alt="Some lush mountains at sunset" />
默认情况下,这将加载 /images/mountains.jpg
。酷!现在,打开 .env
文件,并在其中添加以下内容
IMAGE_BASE=https://assets.codepen.io/174183/
IMAGE_PROPS=?width=1275&height=805&format=auto&quality=70
如果你停止 Eleventy(在终端中按 Ctrl
+C
),然后再次运行 npm start
,然后在浏览器中查看源代码,渲染的图片应该看起来像这样
<img src="https://assets.codepen.io/174183/mountains.jpg?width=1275&height=805&format=auto&quality=70" alt="Some lush mountains at sunset" />
这意味着我们可以在需要时利用 CodePen 资源优化。
使用 Eleventy 提供私密内容和高级内容
我们还可以使用环境变量根据模式(如私密模式)有条件地渲染内容。对我个人来说,这是一种重要的功能,因为我有一个 Eleventy 课程,还有一个 CSS 书籍,它们都使用 Eleventy 构建,只有付费的用户才能看到高级内容。在幕后,有很多技术魔法在起作用,例如 Service Workers 和 API,但核心都是内容可以根据我们 JavaScript 接口中的 env.mode
有条件地渲染。
现在让我们将它添加到我们的示例中。打开 src/_data/env.js
,并在对象中添加以下内容
mode: process.env.MODE || 'public'
这种设置意味着默认情况下,mode
为 **public**。现在,打开 src/index.md
并将以下内容添加到文件底部
{% if env.mode === 'private' %}
## This is secret content that only shows if we’re in private mode.
This is called with {% raw %}`{{ env.mode }}`{% endraw %}. This is great for doing special private builds of the site for people that pay for content, for example.
{% endif %}
如果你刷新本地版本,你将看不到我们刚刚添加的内容。这对于我们来说是 **完美** 的——尤其是因为我们想要保护它。所以现在,让我们使用环境变量来显示它。打开 .env
并添加以下内容
MODE=private
现在,重启 Eleventy 并重新加载网站。你应该会看到类似以下的内容

你也可以在模板中运行这种条件渲染。例如,你可以将所有页面内容设为私有,并渲染一个付费墙。例如,如果你 进入我的课程 却没有许可证,你会看到一个购买课程的行动呼吁

趣味模式
到目前为止,这些内容对你来说应该非常有用,所以让我们扩展一下我们学到的知识,并用它来玩一些有趣的!
我想最后做个“趣味模式”,它会将设计完全改变成更...有趣 的东西。打开 src/_includes/base.njk
,在闭合的 </head>
标签之前,添加以下内容
{% if env.funMode %}
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Lobster&display=swap" />
<style>
body {
font-family: 'Comic Sans MS', cursive;
background: #fc427b;
color: #391129;
}
h1,
.fun {
font-family: 'Lobster';
}
.fun {
font-size: 2rem;
max-width: 40rem;
margin: 0 auto 3rem auto;
background: #feb7cd;
border: 2px dotted #fea47f;
padding: 2rem;
text-align: center;
}
</style>
{% endif %}
这段代码片段将查看我们的 funMode
环境变量是否为 true
,如果是,它将添加一些“趣味”CSS。
仍然在 base.njk
中,在打开的 <article>
标签之前,添加以下代码
{% if env.funMode %}
<div class="fun">
<p>🎉 <strong>Fun mode enabled!</strong> 🎉</p>
</div>
{% endif %}
这段代码使用相同的逻辑,如果 funMode
为 true
,则会渲染一个有趣的横幅。现在让我们为它创建环境变量接口。打开 src/_data/env.js
,并将以下内容添加到导出的对象中
funMode: process.env.FUN_MODE
如果 funMode
未定义,它将充当 false
,因为 undefined
是一个 虚假值。
接下来,打开你的 .env
文件,并将以下内容添加到其中
FUN_MODE=true
现在,重启 Eleventy 任务并重新加载浏览器。它应该看起来像这样

相当大声吧?!尽管这个设计看起来很糟糕(阅读:很酷),但我希望它能演示使用这种环境设置可以改变多少东西。
总结
我们创建了同一个网站的三个版本,运行相同的代码以查看所有差异
所有这些网站都由相同的代码驱动,每个网站之间唯一的区别是某些环境变量,在这个例子中,我在我的 Netlify 仪表盘中定义了这些变量。
我希望这种技术能为你打开各种可能性,使用最好的静态网站生成器 Eleventy!
我觉得“默认情况下,这将加载 /images/mountains.jpg。”之前的代码块是错误的。它不应该应该是
<img src="{{ env.imageBase }}mountains.jpg{{ env.imageProps }}" alt="Some lush mountains at sunset" />
吗?@YellowLed – 是的。感谢你的更正!我正要尝试自己进行类似的更改,但随后看到了你的评论。
感谢你。我已经更新了它 :)
嗨 Andy,写得很不错。我正在尝试弄清楚图像基本路径。在开发过程中,我希望它看起来像 /images/——但在 _site(输出)中,我希望它有一个子目录,例如“/ssg-pages/images/”。
因为我只需将整个 _site 文件夹拖到 S3 存储桶中——但它必须位于名为“ssg-pages”的子目录中。因此,“/images/”的默认图像路径将不起作用。
我不能在 S3 中设置环境变量。
所以,我基本上需要一种方法来在“构建”(在 _site 内部)时输出“/ssg-pages/”。
你有什么建议吗?
我在此处询问了相同的问题
https://stackoverflow.com/questions/68355172/eleventy-configuration-for-subdirectory-for-images-and-static-assets
提前感谢。