配置与环境
本指南涵盖 AdonisJS 应用中的配置。你将学习到:
config目录中的配置文件- 环境变量与
.env文件 - 以类型安全的方式验证环境变量
.env文件内的变量插值- 用于开发、测试和生产环境的环境特定
.env文件 - 在 Edge 模板中访问配置
- 用于框架配置的
adonisrc.ts文件
概述
AdonisJS 中的配置被组织成三个不同的系统,各自服务于特定目的。
-
配置文件 包含你的应用设置。这些文件位于
config目录中,定义数据库连接、邮件设置、会话配置等内容。 -
环境变量 存储在
.env文件中,保存着在不同环境之间变化的运行时密钥与值。API 密钥、数据库密码以及环境特定的 URL 都属于此类。AdonisJS 支持用于不同环境的多个.env文件,并提供类型安全验证,以便在启动时捕获缺失的变量。 -
adonisrc.ts 文件 配置框架本身。它告知 AdonisJS 你的工作区是如何组织的、要加载哪些提供者以及有哪些命令可用。
配置文件
配置文件位于项目根目录下的 config 目录中。每个文件导出一个针对应用特定部分的配置对象(数据库连接、邮件设置、身份验证、会话处理等)。
一个典型的 AdonisJS 项目开箱即包含多个配置文件。config/database.ts 文件配置数据库连接,config/mail.ts 处理邮件发送,config/auth.ts 定义身份验证设置。
下面是一个数据库配置文件示例。
import app from '@adonisjs/core/services/app'
import { defineConfig } from '@adonisjs/lucid'
const dbConfig = defineConfig({
connection: 'sqlite',
prettyPrintDebugQueries: true,
connections: {
sqlite: {
client: 'better-sqlite3',
connection: {
filename: app.tmpPath('db.sqlite3'),
},
useNullAsDefault: true,
migrations: {
naturalSort: true,
paths: ['database/migrations'],
},
debug: app.inDev,
},
},
})
export default dbConfig
邮件配置遵循类似的模式。
import env from '#start/env'
import { defineConfig, transports } from '@adonisjs/mail'
const mailConfig = defineConfig({
default: env.get('MAIL_MAILER'),
from: {
address: env.get('MAIL_FROM_ADDRESS'),
name: env.get('MAIL_FROM_NAME'),
},
mailers: {
resend: transports.resend({
key: env.get('RESEND_API_KEY'),
baseUrl: 'https://api.resend.com',
}),
},
})
export default mailConfig
declare module '@adonisjs/mail/types' {
export interface MailersList extends InferMailers<typeof mailConfig> {}
}
注意这个配置文件如何通过 env.get() 引用环境变量。这是在配置中使用环境特定值的正确方式。配置文件定义结构与默认值,而 .env 文件提供实际的值。
配置文件何时被加载
配置文件在应用启动周期中、在你的路由和控制器就绪之前被加载。这意味着你应该保持配置文件简单,避免导入模型、服务或控制器等应用级别的代码。
配置文件只应导入框架工具、定义配置对象并引用环境变量。导入应用代码会造成循环依赖,并导致你的应用在启动时失败。
在 Edge 模板中访问配置
Edge 模板可以通过 config 全局对象访问你的应用配置。这让你能够直接在视图中引用配置值,而无需从控制器显式传递它们。
<!DOCTYPE html>
<html>
<head>
<title>{{ config('app.appName') }}</title>
</head>
<body>
<footer>
<p>Running in {{ config('app.nodeEnv') }} mode</p>
</footer>
</body>
</html>
config() 辅助函数接受指向任意配置值的点号路径。该路径对应配置文件名及其内部的属性。例如,config('database.connection') 读取 config/database.ts 中的 connection 属性。
你也可以提供第二个参数作为默认值。
<p>{{ config('app.timezone', 'UTC') }}</p>
环境变量
环境变量存储在不同环境之间变化的密钥与配置。在开发过程中,你在 .env 文件中定义这些变量。在生产环境中,你必须通过托管提供商的 UI 或配置界面来定义它们。
一个典型的 .env 文件如下所示。
HOST=0.0.0.0
PORT=3333
APP_KEY=your-secret-app-key-here
MAIL_MAILER=resend
MAIL_FROM_ADDRESS=hello@example.com
MAIL_FROM_NAME=My App
RESEND_API_KEY=re_your_api_key_here
在 AdonisJS 入门套件中,.env 文件已经列在 .gitignore 中,因此你不会意外地将密钥提交到仓库。
APP_KEY
APP_KEY 是一个特殊的环境变量,AdonisJS 使用它来加密 cookie、签名会话以及其他加密操作。每个 AdonisJS 应用都需要一个 APP_KEY 才能安全运行。
运行 generate:key 命令来创建你的 APP_KEY。
node ace generate:key
这会创建一个密码学安全的随机密钥,并自动添加到你的 .env 文件中。
APP_KEY 必须保持机密。任何获得此密钥的人都能解密你应用的加密数据并伪造会话令牌。当你部署到生产环境时,每个环境(开发、预发布、生产)都应使用不同的 APP_KEY。切勿跨环境复用密钥。
如果你的 APP_KEY 被泄露,请立即生成一个新的。这将使所有现有的用户会话和加密数据失效。
在配置文件中使用环境变量
配置文件通过 env 服务访问环境变量,该服务为你的 .env 文件值提供类型安全的访问。你导入 env 服务并使用变量名调用 env.get()。
import env from '#start/env'
const apiKey = env.get('RESEND_API_KEY')
这种模式使你的配置保持有条理且经过验证。env 服务确保必需的变量存在,并在缺失时抛出清晰的错误。
你绝不应在控制器、服务或其他应用代码中直接访问环境变量。始终通过配置文件访问它们。这创建了一处配置的唯一真实来源。
变量插值
.env 文件支持变量插值,允许你在一个值中引用其他环境变量。使用 $VAR 或 ${VAR} 语法进行变量插值。
HOST=localhost
PORT=3333
APP_URL=http://$HOST:$PORT
在此示例中,APP_URL 解析为 http://localhost:3333。当你需要根据其他变量组合值而不重复书写时,这非常有用。
你也可以使用花括号以提高清晰度,或在变量名与其他字符相邻时使用。
S3_BUCKET=my-app-uploads
S3_REGION=us-east-1
S3_URL=https://${S3_BUCKET}.s3.${S3_REGION}.amazonaws.com
要在值中包含字面的美元符号,请使用反斜杠对其进行转义。
PRICE=\$99.99
环境特定的 .env 文件
AdonisJS 支持用于不同环境和用例的多个 .env 文件。框架按照特定顺序加载这些文件,后加载的文件会覆盖先加载的文件。
| 文件 | 用途 | Git 状态 |
|---|---|---|
.env | 所有环境的基础环境变量 | 忽略 |
.env.local | 本地覆盖,在所有环境中加载(测试环境除外) | 忽略 |
.env.development | 开发特定变量 | 忽略 |
.env.staging | 预发布特定变量 | 忽略 |
.env.production | 生产特定变量 | 忽略 |
.env.test | 测试特定变量,在 NODE_ENV=test 时加载 | 忽略 |
.env.example | 展示所需变量及占位值的模板 | 提交 |
加载顺序取决于你的 NODE_ENV 值。对于 NODE_ENV=development,AdonisJS 按以下顺序加载文件:
.env(基础变量).env.development(环境特定).env.local(本地覆盖)
对于 NODE_ENV=test,顺序为:
.env(基础变量).env.test(测试特定)
注意 .env.local 在测试期间不会被加载。这可以防止本地开发设置干扰测试运行。
.env.example 文件作为你团队的文档。它列出所有必需的环境变量及占位值,帮助新开发者设置本地环境。与其他 .env 文件不同,你应该将 .env.example 提交到版本控制中。
HOST=0.0.0.0
PORT=3333
APP_KEY=<generate-with-node-ace-generate:key>
DATABASE_URL=postgresql://user:password@localhost:5432/myapp
RESEND_API_KEY=<your-resend-api-key>
验证环境变量
AdonisJS 通过 start/env.ts 文件在启动时验证环境变量。这种验证确保你的应用不会在配置缺失或无效的情况下启动,将错误尽早暴露出来,而不是在运行时(更难调试)才出现。
start/env.ts 文件使用基于 schema 的验证来定义你的应用期望哪些环境变量、它们的类型以及任何约束。
import { Env } from '@adonisjs/core/env'
export default await Env.create(new URL('../', import.meta.url), {
/**
* Variables for configuring the HTTP server
*/
HOST: Env.schema.string({ format: 'host' }),
PORT: Env.schema.number(),
/**
* App-specific variables
*/
APP_KEY: Env.schema.string(),
NODE_ENV: Env.schema.enum(['development', 'production', 'test'] as const),
/**
* Database configuration
*/
DATABASE_URL: Env.schema.string(),
/**
* Optional variables with defaults
*/
LOG_LEVEL: Env.schema.enum(['debug', 'info', 'warn', 'error'] as const).optional(),
CACHE_DRIVER: Env.schema.string.optional(),
})
当你的应用启动时,AdonisJS 会读取 .env 文件并根据此 schema 验证每个变量。如果某个必需变量缺失或值无效,应用会抛出描述性错误并拒绝启动。
该 schema 提供了多种验证方法。
Env.schema.string
验证值是非空字符串。你可以通过指定以下格式之一来验证字符串格式。
// Validates the value is a valid hostname or IP
Env.schema.string({ format: 'host' })
// Validates the value is a valid URL
Env.schema.string({ format: 'url' })
// Validates the value is a valid URL without tld
Env.schema.string({ format: 'url', tld: false })
// Validates the value is a valid URL without protocol
Env.schema.string({ format: 'url', protocol: false })
// Validates the value is a valid email address
Env.schema.string({ format: 'email' })
Env.schema.number
验证并将值转换为数字
Env.schema.boolean
验证并将值转换为布尔值
Env.schema.enum
验证值是否为允许的选项之一
Optional chaining(可选链)
任何 schema 方法都可以通过链式调用 .optional() 变为可选。未设置的变量会返回 undefined。
import { Env } from '@adonisjs/core/env'
export default await Env.create(new URL('../', import.meta.url), {
SENTRY_DSN: Env.schema.string.optional(),
CACHE_DRIVER: Env.schema.string.optional()
})
验证之后,env 服务提供完整的 TypeScript 类型推断。当你调用 env.get('NODE_ENV') 时,TypeScript 会根据你的 schema 定义知道返回类型为 'development' | 'production' | 'test'。
adonisrc.ts 文件
adonisrc.ts 文件配置的是框架本身,而不是你的应用。虽然配置文件定义应用的行为、.env 存储密钥,但 adonisrc.ts 告诉 AdonisJS 你的工作区是如何组织的,以及要加载哪些框架特性。
你很少需要直接修改这个文件。大多数需要更改 adonisrc.ts 的操作都由 Ace 命令自动处理。当你运行 node ace make:provider 或 node ace make:command 时,这些命令会为你把新的提供者或命令注册到 adonisrc.ts 文件中。
下面是一个基础的 adonisrc.ts 文件包含的内容。
import { defineConfig } from '@adonisjs/core/app'
export default defineConfig({
commands: [
() => import('@adonisjs/core/commands'),
() => import('@adonisjs/lucid/commands'),
],
providers: [
() => import('@adonisjs/core/providers/app_provider'),
() => import('@adonisjs/core/providers/hash_provider'),
() => import('@adonisjs/core/providers/vinejs_provider'),
() => import('@adonisjs/session/session_provider'),
() => import('@adonisjs/lucid/database_provider'),
() => import('@adonisjs/auth/auth_provider'),
],
preloads: [
() => import('#start/routes'),
() => import('#start/kernel')
],
hooks: {
buildStarting: [
() => import('@adonisjs/vite/build_hook')
],
},
})
providers 数组列出了 AdonisJS 在应用启动时应加载的所有服务提供者。提供者负责搭建数据库连接、身份验证和会话处理等框架特性。
commands 数组注册来自包的 Ace 命令。你的应用 commands 目录中的命令会被自动发现,因此你只在这里列出包的命令。
hooks 对象定义了在特定生命周期事件期间运行的函数。buildStarting 钩子会在你为生产环境构建应用时运行。
你可以在 AdonisRC 文件参考指南 中了解更多可用属性。