• 亮色
  • 深色
  • 自动
  • RSS 订阅

    Remix 怎么使用环境变量

    2024-06-22

    通过 Vite 的方式

    Warnning

    需要注意的是,这种方式如果使用不当,可能会不小心把敏感信息暴露到客户端!

    新版本的 Remix 基于 Vite,而 Vite 本身提供了读取环境变量的方法,所以可以使用 Vite 的 import.meta.env.<环境变量名> 来使用环境变量中的值。前提是环境变量以 VITE_ 为前缀命名。

    参考: https://vitejs.dev/guide/env-and-mode#env-variables-and-modes

    在项目下创建一个 .env 文件,填入如下内容:

    VITE_EXAMPLE=abc
    

    此时项目里可以通过 import.meta.env.VITE_EXAMPLE 来调用这个环境变量。

    Vite 导入环境变量的类型提示

    Info

    注意确保你的 TypeScript 能够读取到 env.d.ts 文件。

    如果想要类型提示,可以在项目下创建 env.d.ts 文件,其中填入如下内容:

    /// <reference types="vite/client" />
    
    interface ImportMetaEnv {
      readonly VITE_EXAMPLE: string
    }
    

    这样再使用 import.meta.env. 时就能够自动提示有哪些可以调用的环境变量了。

    通过 Remix 建议的方式

    在 Remix 的服务端代码中可以通过 process.env.<环境变量名> 来使用环境变量。

    这种方式只能在 ActionFunctionsLoaderFunctions 里访问环境变量,不能直接在 export default 的组件里使用。这也意味着不能直接在浏览器端访问环境变量中的值(通过 Vite 的方式是可以那样做的)。

    这里先说下使用例子,后面再说怎么在浏览器端访问环境变量值(直接在浏览器端的代码里使用 Vite 的那种方式也是可以的,只是说不推荐)。

    假设当前已经有个 .env 文件,且其中有如下值:

    API_KEY=abc
    BASE_URL=http://example.com
    

    像下面这样使用这些环境变量:

    // Loaders
    export async function loader({ request }) {
      const apiKey = process.env.API_KEY
      const baseUrl = process.env.BASE_URL
    
      const response = await fetch(`${baseUrl}/data?api_key=${apiKey}`)
      const data = await response.json()
    
      return data
    }
    
    // Actions
    export async function action({ request }) {
      const apiKey = process.env.API_KEY
      const baseUrl = process.env.BASE_URL
    
      const response = await fetch(`${baseUrl}/submit?api_key=${apiKey}`, {
        method: 'POST',
        body: JSON.stringify({ data: 'example' }),
      })
    
      return response
    }
    

    在浏览器中使用

    /* eslint-disable react-dom/no-dangerously-set-innerhtml */
    // 如果使用了 ESLint,那么可能需要在文件开头使用这一行 ⬆️
    
    export async function loader() {
      return json({
        ENV: {
          baseUrl: process.env.BASE_URL,
        },
      })
    }
    
    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>
      )
    }
    

    现在可以在浏览器里通过 window.ENV.baseUrl 来调用环境变量了。

    Process Env 类型提示

    Info

    注意确保你的 TypeScript 能够读取到 env.d.ts 文件。

    当通过 process.env.<环境变量名> 去调用环境变量时,可以发现没有提供提示,可以在项目下添加一个 env.d.ts 文件,其中填入如下内容,以此增加 process.env. 中的提示内容:

    namespace NodeJS {
      interface ProcessEnv {
        // 无须指定任何特定前缀
        readonly 环境变量名称: string
      }
    }
    

    ESLint 读取不到 process

    ESLint 可能会提示:

    Unexpected use of the global variable 'process'. Use 'require("process")' instead.
    

    这是因为这条 node/prefer-global/process 规则要求的,可以禁用它。

    参考