React Router v7 已发布。 查看文档
环境变量
本页内容

环境变量

Remix 不会直接处理环境变量(除了在本地开发期间),但是我们发现一些有用的模式,我们将在本指南中分享。

环境变量是存在于服务器上的值,你的应用程序可以使用它们。你可能熟悉无处不在的 NODE_ENV。你的部署服务器可能会自动将其设置为“production”。

运行 remix build 会使用 process.env.NODE_ENV 的值进行编译,如果它对应于有效模式:“production”、“development”或“test”。如果 process.env.NODE_ENV 的值无效,则默认使用“production”。

以下是一些你可能会在实际中找到的示例环境变量

  • DATABASE_URL:Postgres 数据库的 URL
  • STRIPE_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 是否允许他们将环境变量放入浏览器包中。这在构建密集型框架中是一种常见的策略。然而,这种方法存在一些问题

  1. 它并不是真正的环境变量。您必须在构建时知道您要部署到哪个服务器。
  2. 如果不进行重新构建和重新部署,您就无法更改这些值。
  3. 很容易不小心将密钥泄露到公共可访问的文件中!

我们建议将所有环境变量保留在服务器上(包括所有服务器密钥以及浏览器中 JavaScript 需要的内容),并通过 window.ENV 将它们暴露给您的浏览器代码。由于您始终拥有服务器,因此您不需要在包中包含此信息,您的服务器可以在加载器中提供客户端环境变量。

  1. 从根加载器返回客户端的 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>
      );
    }
    
  2. 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>
      );
    }
    
  3. 访问这些值

    import { loadStripe } from "@stripe/stripe-js";
    
    export async function redirectToStripeCheckout(
      sessionId
    ) {
      const stripe = await loadStripe(
        window.ENV.STRIPE_PUBLIC_KEY
      );
      return stripe.redirectToCheckout({ sessionId });
    }
    
文档和示例采用以下许可: MIT