Remix 本身不会直接处理环境变量(除了在本地开发期间),但有一些我们认为有用的模式,我们将在本指南中分享。
环境变量是在服务器上存在的、您的应用程序可以使用的值。您可能熟悉无处不在的 NODE_ENV
。您的部署服务器可能会自动将其设置为“production”。
remix build
会使用 process.env.NODE_ENV
的值进行编译,前提是它与有效模式相对应:“production”、“development”或“test”。如果 process.env.NODE_ENV
的值无效,则默认使用“production”。
以下是一些您可能在实际应用中遇到的环境变量示例
DATABASE_URL
:Postgres 数据库的 URLSTRIPE_PRIVATE_KEY
:结账工作流在服务器上使用的密钥STRIPE_PUBLIC_KEY
:结账工作流在浏览器上使用的密钥如果您在过去几年的 Web 开发经验主要来自 JS 框架,您可能会认为这些是构建使用的东西。虽然它们可以用于捆绑代码,但传统上这些是“构建参数”,而不是环境变量。环境变量在**服务器运行时**最有用。例如,您可以更改环境变量以更改应用程序的行为,而无需重新构建甚至重新部署。
如果您使用 remix dev
服务器在本地运行项目,它内置支持 dotenv。
首先,在项目的根目录中创建一个 .env
文件
touch .env
.env
文件提交到 git,关键是它包含机密信息!
编辑您的 .env
文件。
SOME_SECRET=super-secret
然后,在运行 remix dev
时,您将能够在您的加载器/操作中访问这些值
export async function loader() {
console.log(process.env.SOME_SECRET);
}
如果您使用的是 @remix-run/cloudflare-pages
或 @remix-run/cloudflare
适配器,则环境变量的工作方式略有不同。您需要在 .dev.vars
文件中定义您的本地环境变量。它与上面提到的 .env
示例文件具有相同的语法。
然后,它们将通过 Remix 的 context.cloudflare.env
在您的 loader
/action
函数中可用
export const loader = async ({
context,
}: LoaderFunctionArgs) => {
console.log(context.cloudflare.env.SOME_SECRET);
};
请注意,.env
和 .dev.vars
文件仅用于开发。您不应该在生产环境中使用它们,因此 Remix 在运行 remix serve
时不会加载它们。您需要按照主机提供的指南,通过以下链接将机密信息添加到生产服务器。
部署到生产环境时的环境变量将由您的主机处理,例如
有些人会问 Remix 是否可以让他们将环境变量放入浏览器捆绑包中。这在构建密集型框架中是一种常见的策略。但是,这种方法存在一些问题
我们建议将所有环境变量都保存在服务器上(所有服务器密钥以及浏览器中的 JavaScript 代码需要的部分),并通过window.ENV
将其暴露给浏览器代码。由于您始终拥有服务器,因此您不需要在捆绑包中包含此信息,您的服务器可以在加载器中提供客户端环境变量。
从根加载器返回ENV
以供客户端使用 - 在加载器中,您可以访问服务器的环境变量。加载器仅在服务器上运行,并且永远不会捆绑到客户端 JavaScript 中。
export async function loader() {
return json({
ENV: {
STRIPE_PUBLIC_KEY: process.env.STRIPE_PUBLIC_KEY,
FAUNA_DB_URL: process.env.FAUNA_DB_URL,
},
});
}
export function Root() {
return (
<html lang="en">
<head>
<Meta />
<Links />
</head>
<body>
<Outlet />
<Scripts />
</body>
</html>
);
}
将ENV
放到 window 上 - 这是我们将值从服务器传递到客户端的方式。请确保将其放在<Scripts/>
之前。
export async function loader() {
return json({
ENV: {
STRIPE_PUBLIC_KEY: process.env.STRIPE_PUBLIC_KEY,
},
});
}
export function Root() {
const data = useLoaderData<typeof loader>();
return (
<html lang="en">
<head>
<Meta />
<Links />
</head>
<body>
<Outlet />
<script
dangerouslySetInnerHTML={{
__html: `window.ENV = ${JSON.stringify(
data.ENV
)}`,
}}
/>
<Scripts />
</body>
</html>
);
}
访问这些值
import { loadStripe } from "@stripe/stripe-js";
export async function redirectToStripeCheckout(
sessionId
) {
const stripe = await loadStripe(
window.ENV.STRIPE_PUBLIC_KEY
);
return stripe.redirectToCheckout({ sessionId });
}