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 });
}