¥Environment Variables
Remix 不会直接使用环境变量(本地开发除外),但我们认为有一些有用的模式,我们将在本指南中分享。
¥Remix does not do anything directly with environment variables (except during local development), but there are some patterns we find useful that we'll share in this guide.
环境变量是驻留在服务器上、可供应用使用的值。你可能熟悉无处不在的 NODE_ENV
。你的部署服务器可能会自动将其设置为 "production"
。
¥Environment Variables are values that live on the server that your application can use. You may be familiar with the ubiquitous NODE_ENV
. Your deployment server probably automatically sets that to "production"
.
process.env.NODE_ENV
的值与有效模式("production"
、"development"
或 "test"
)相对应,则运行 remix build
会使用其值进行编译。如果 process.env.NODE_ENV
的值无效,则默认使用 "production"
。
以下是一些你可能在实际环境中遇到的示例环境变量:
¥Here are some example environment variables you might find in the wild:
DATABASE_URL
:Postgres 数据库的 URL
¥DATABASE_URL
: The URL for a Postgres Database
STRIPE_PRIVATE_KEY
:结账工作流将在服务器上使用的键
¥STRIPE_PRIVATE_KEY
: The key a checkout workflow will use on the server
STRIPE_PUBLIC_KEY
:结账工作流将在浏览器上使用的键
¥STRIPE_PUBLIC_KEY
: The key a checkout workflow will use on the browser
如果你过去几年的 Web 开发经验主要集中在 JS 框架上,那么你可能会认为这些框架可以作为你的构建工具。虽然它们对于打包代码很有用,但传统上它们是 "构建参数",而不是环境变量。环境变量在服务器运行时最有用。例如,你可以更改环境变量来更改应用的行为,而无需重建或重新部署。
¥If your experience with web development is primarily with the JS frameworks in the last few years, you might think of these as something for your build to use. While they can be useful for bundling code, traditionally those are "build arguments" not environment variables. Environment variables are most useful at runtime on the server. For example, you can change an environment variable to change the behavior of your app without rebuilding or even redeploying.
¥Server Environment Variables
¥Local Development
如果你使用 remix dev
服务器在本地运行项目,它内置了对 dotenv 的支持。
¥If you're using the remix dev
server to run your project locally, it has built-in support for dotenv.
首先,在项目根目录中创建一个 .env
文件:
¥First, create an .env
file in the root of your project:
touch .env
.env
文件提交到 git;关键是它包含机密信息!
编辑你的 .env
文件。
¥Edit your .env
file.
SOME_SECRET=super-secret
然后,运行 remix dev
时,你将能够在加载器/操作中访问这些值:
¥Then, when running remix dev
you will be able to access those values in your loaders/actions:
export async function loader() {
console.log(process.env.SOME_SECRET);
}
如果你使用的是 @remix-run/cloudflare-pages
或 @remix-run/cloudflare
适配器,环境变量的工作方式会略有不同。你需要在 .dev.vars
文件中定义本地环境变量。它的语法与上面提到的 .env
示例文件相同。
¥If you're using the @remix-run/cloudflare-pages
or @remix-run/cloudflare
adapters, env variables work a little differently. You'll need to define your local environment variables in the .dev.vars
file. It has the same syntax as .env
example file mentioned above.
然后,它们将通过 Remix 的 context.cloudflare.env
在你的 loader
/action
函数中使用:
¥Then, they'll be available via Remix's context.cloudflare.env
in your loader
/action
functions:
export const loader = async ({
context,
}: LoaderFunctionArgs) => {
console.log(context.cloudflare.env.SOME_SECRET);
};
请注意,.env
和 .dev.vars
文件仅用于开发。你不应在生产环境中使用它们,因此 Remix 在运行 remix serve
时不会加载它们。你需要按照主机提供商的指南,通过以下链接向生产服务器添加 secret。
¥Note that .env
and .dev.vars
files are only for development. You should not use them in production, so Remix doesn't load them when running remix serve
. You'll need to follow your host's guides on adding secrets to your production server, via the links below.
¥Production
你的主机在部署到生产环境时会处理环境变量,例如:
¥Your host will handle environment variables when deployed to production, for example:
¥Browser Environment Variables
有些人询问 Remix 是否允许他们将环境变量放入浏览器包中。这是构建密集型框架的常用策略。然而,这种方法存在一些问题,原因如下:
¥Some folks ask if Remix can let them put environment variables into browser bundles. It's a common strategy in build-heavy frameworks. However, this approach is a problem for a few reasons:
它实际上不是一个环境变量。你必须在构建时知道要部署到哪个服务器。
¥It's not really an environment variable. You have to know which server you're deploying to at build time.
如果不重建并重新部署,则无法更改这些值。
¥You can't change the values without a rebuild and redeploy.
很容易将机密信息意外泄露到可公开访问的文件中!
¥It's easy to accidentally leak secrets into publicly accessible files!
我们建议将所有环境变量(所有服务器机密以及浏览器中 JavaScript 所需的内容)保留在服务器上,并通过 window.ENV
将它们公开给浏览器代码。由于你始终拥有服务器,因此你不需要在包中包含这些信息;你的服务器可以在加载器中提供客户端环境变量。
¥Instead, we recommend keeping all of your environment variables on the server (all the server secrets as well as the stuff your JavaScript in the browser needs) and exposing them to your browser code through window.ENV
. Since you always have a server, you don't need this information in your bundle; your server can provide the client-side environment variables in the loaders.
从根加载器返回客户端的 ENV
。 - 在加载器中,你可以访问服务器的环境变量。加载器仅在服务器上运行,并且永远不会打包到客户端 JavaScript 中。
¥Return ENV
for the client from the root loader - Inside your loader you can access your server's environment variables. Loaders only run on the server and are never bundled into your client-side 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
放在窗口上 - 这就是我们将值从服务器传递到客户端的方式。确保将其放在 <Scripts/>
之前
¥Put ENV
on window - This is how we hand off the values from the server to the client. Make sure to put this before <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>
);
}
访问值
¥Access the values
import { loadStripe } from "@stripe/stripe-js";
export async function redirectToStripeCheckout(
sessionId
) {
const stripe = await loadStripe(
window.ENV.STRIPE_PUBLIC_KEY
);
return stripe.redirectToCheckout({ sessionId });
}