跳转到内容

使用环境变量

Astro 使你可以使用 Vite 内置的环境变量支持,并为你的项目包含了一些 默认环境变量,让你可以访问当前项目的配置值(例如 sitebase),无论你的项目是在开发还是生产环境中运行。

Astro 也提供了一种 使用和组织类型安全的环境变量 的方法。它可以在 Astro 上下文中使用(例如 Astro 组件、路由和端点、UI 框架组件、中间件),并通过 Astro 配置中的 schema 进行管理。

Astro 使用 Vite 的内置环境变量支持,这些变量在构建时静态替换,让你可以 使用任何 Vite 的方法来处理它们。

注意,虽然 所有 环境变量都可以在服务器端代码中使用,但出于安全考虑,只有以 PUBLIC_ 为前缀的环境变量可以在客户端代码中使用。

.env
SECRET_PASSWORD=password123
PUBLIC_ANYBODY=there

在这个例子中,PUBLIC_ANYBODY(通过 import.meta.env.PUBLIC_ANYBODY 访问)将在服务器端或客户端代码中可用,而 SECRET_PASSWORD(通过 import.meta.env.SECRET_PASSWORD 访问)将仅在服务器端可用。

默认情况,Astro 在 astro/client.d.ts 中为 import.meta.env 提供类型定义。

当在 .env.[mode] 文件中定义了更多的自定义环境变量,你可能想要得到以 PUBLIC_ 前缀的自定义环境变量的 TypeScript 智能提示。

为了实现这一点,你可以在 src/ 中创建一个 env.d.ts,并配置 ImportMetaEnv

src/env.d.ts
interface ImportMetaEnv {
readonly DB_PASSWORD: string;
readonly PUBLIC_POKEAPI: string;
// 更多环境变量…
}
interface ImportMeta {
readonly env: ImportMetaEnv;
}

Astro 包括了几个开箱即用的环境变量:

  • import.meta.env.MODE:站点的运行模式。在运行 astro dev 时为 development,在运行 astro build 时为 production
  • import.meta.env.PROD:当你的站点以production模式运行时为true;否则为false
  • import.meta.env.DEV:当你的站点以development模式运行时为true;否则为false。(总是和 import.meta.env.PROD 相反)。
  • import.meta.env.BASE_URL:为站点提供服务的基础 url。它由 base 配置项 决定。
  • import.meta.env.SITE:特指项目中 astro.config 中的 site
  • import.meta.env.ASSETS_PREFIX:如果设置了 build.assetsPrefix 配置项,则指定 Astro 生成的资源链接的前缀。可以用于创建不由 Astro 处理的资源链接。

你可以将它们当作其他任意的环境变量来使用。

const isProd = import.meta.env.PROD;
const isDev = import.meta.env.DEV;

环境变量会从项目目录中的 .env 文件中加载。

只需在项目目录下创建 .env 文件,并在其中添加一些变量。

.env
# 这只有在服务器上运行时才会有效!
DB_PASSWORD="foobar"
# 这在什么地方都有效!
PUBLIC_POKEAPI="https://pokeapi.co/api/v2"

你也可以添加 .production.development 或自定义模式名称到文件名中(例如 .env.testing.env.staging)。这样可以让你在不同的时间使用不同的环境变量集。

astro devastro build 命令默认分别使用 "development""production" 模式。你可以通过 --mode 标志 运行这些命令,传递不同的 mode 值并加载匹配的 .env 文件。

这允许你运行开发服务器或构建你的站点时连接到不同的 API:

终端窗口
# 允许开发服务器连接到一个“staging” API
astro dev --mode staging
# 构建一个连接到“production” API 的站点,并输出额外的调试信息
astro build --devOutput
# 构建一个连接到“testing” API 的站点
astro build --mode testing

对于更多关于 .env 文件的信息,请查看 Vite 文档

Astro 在加载其他文件之前会评估配置文件。这意味着你不能在 astro.config.mjs 中使用 import.meta.env 来访问 .env 文件中设置的环境变量。

你可以在配置文件中使用 process.env 来访问其他环境变量,例如 由 CLI 设置的环境变量

你也可以使用 Vite 的 loadEnv 辅助函数 手动加载 .env 文件。

astro.config.mjs
import { loadEnv } from "vite";
const { SECRET_PASSWORD } = loadEnv(process.env.NODE_ENV, process.cwd(), "");

你也还可以在运行项目时添加环境变量:

终端窗口
PUBLIC_POKEAPI=https://pokeapi.co/api/v2 npm run dev

在 Astro 中,环境变量是通过 import.meta.env 访问的,使用的是 在 ES2020 中添加的 import.meta 功能,而不是 process.env。

例如,使用 import.meta.env.PUBLIC_POKEAPI 来获取 PUBLIC_POKEAPI 环境变量。

// 当 import.meta.env.SSR === true
const data = await db(import.meta.env.DB_PASSWORD);
// 当 import.meta.env.SSR === false
const data = fetch(`${import.meta.env.PUBLIC_POKEAPI}/pokemon/squirtle`);

使用 SSR 时,可以根据所使用的 SSR 适配器,在运行时访问环境变量。对于大部分适配器,可以通过 process.env 访问环境变量,但有一些适配器在工作时有所不同。Deno 适配器则需要使用 Deno.env.get()。在使用 Cloudflare 适配器时,可以参阅如何 访问 Cloudflare 运行时 以处理环境变量。Astro 会检查服务器环境中的变量,如果这些变量不存在,则会在 .env 文件中查找它们。

类型安全的环境变量

段落标题 类型安全的环境变量

astro:env 允许你为 设置的环境变量 配置一个类型安全的 schema。这允许你指定它们是否应该在服务器端或客户端上可用,并定义它们的数据类型和其他属性。

在开发适配器?查看如何 使适配器与 astro:env 兼容

要定义一个 schema,将 env.schema 选项添加到你的 Astro 配置中:

astro.config.mjs
import { defineConfig } from 'astro/config'
export default defineConfig({
env: {
schema: {
// ...
}
}
})

然后,你可以使用 envField 辅助函数 将变量注册为字符串、数字、枚举或布尔值。为每个变量提供 context(client 或 server)和 access(secret 或 public)来定义 环境变量的类型,并在对象中传递任何额外的属性,例如 optionaldefault

astro.config.mjs
import { defineConfig, envField } from 'astro/config'
export default defineConfig({
env: {
schema: {
API_URL: envField.string({ context: "client", access: "public", optional: true }),
PORT: envField.number({ context: "server", access: "public", default: 4321 }),
API_SECRET: envField.string({ context: "server", access: "secret" }),
}
}
})

类型将在运行 astro devastro build 时为你生成,但你也可以运行 astro sync 仅生成类型。

使用你的 schema 中定义的变量

段落标题 使用你的 schema 中定义的变量

从对应的 /client/server 模块导入并使用你定义的变量:

---
import { API_URL } from "astro:env/client"
import { API_SECRET_TOKEN } from "astro:env/server"
const data = await fetch(`${API_URL}/users`, {
method: "GET",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${API_SECRET_TOKEN}`
},
})
---
<script>
import { API_URL } from "astro:env/client"
fetch(`${API_URL}/ping`)
</script>

环境变量分为三种,由你在 schema 中定义的 context(client 或 server)和 access(secret 或 public)设置决定:

  • 公共的客户端变量:这些变量最终会出现在你的最终客户端和服务器包中,并且可以通过 astro:env/client 模块从客户端和服务器中访问:

    import { API_URL } from "astro:env/client"
  • 公共的服务器变量:这些变量最终会出现在你的最终服务器包中,并且可以通过 astro:env/server 模块从服务器中访问:

    import { PORT } from "astro:env/server"
  • 私密的服务器变量:这些变量不会出现在你的最终包中,只能通过 astro:env/server 模块从服务器中访问:

    import { API_SECRET } from "astro:env/server"

    默认情况下,私密变量只在运行时验证。你可以通过 配置 validateSecrets: true 来在启动时验证私密变量。

目前支持四种数据类型:字符串、数字、枚举和布尔值:

import { envField } from "astro/config"
envField.string({
// context & access
optional: true,
default: "foo",
})
envField.number({
// context & access
optional: true,
default: 15,
})
envField.boolean({
// context & access
optional: true,
default: true,
})
envField.enum({
// context & access
values: ['foo', 'bar', 'baz'],
optional: true,
default: 'baz',
})
有关验证字段的完整列表,请参阅 envField API 参考

尽管定义了你的 schema,你可能想要检索某一个私密变量的原始值,或者检索未在你的 schema 中定义的私密变量。在这种情况下,你可以使用 astro:env/server 导出的 getSecret()

import {
FOO, // boolean
getSecret
} from 'astro:env/server'
getSecret('FOO') // string | undefined
API 参考 中了解更多。
  1. astro:env 是一个虚拟模块,这意味着它只能在 Astro 上下文中使用。例如,你可以在以下情况下使用它:

    • 中间件
    • Astro 路由和端点
    • Astro 组件
    • 框架组件
    • 模块

    你不能在以下情况下使用它,必须使用 process.env

    • astro.config.mjs
    • Script 脚本
  2. @astrojs/cloudflare 与其他适配器有些不同。环境变量是针对请求的,不像 Node.js 中是全局的。

    这意味着你总是需要在请求范围内使用私密变量:

    src/middleware.ts
    import { defineMiddleware } from "astro:middleware"
    import { FOO, getSecret } from "astro:env"
    console.log(FOO) // undefined
    console.log(getSecret("FOO")) // undefined
    export const onRequest = defineMiddleware((context, next) => {
    console.log(FOO) // boolean
    console.log(getSecret("FOO")) // string
    return next()
    })
贡献 社区 赞助