在 Gatsby React 应用程序中插入环境变量客户端

Interpolate env vars client side in gatsby react app

我正在使用 Gatsby 作为静态站点生成器并使用 Netlify 进行部署。

Netlify 允许您在其 UI 后端设置环境变量。

我在 Netlify 后端设置了一些环境变量,以便能够 post 订阅邮件列表。

DATA_NO = 'XXXX'
LIST_ID = '123456'
API_KEY = 'XXXXXXXXXXXXXXXXXXXXXXXXXX'

在我的 src 文件中,我有一个组件响应 onSubmit 事件并构建一个 URL 到 post 新订阅者。

(axios作为发送HTTP请求等的包)

import React, { useState } from "react"
import axios from 'axios'

const Form = () => {

    const [userEmail, setState] = useState({'email_address': ''})

    const creds = 'anystring:'+ process.env.API_KEY
    let URL = 'https://'+ process.env.DATA_NO +'.api.example.com/3.0'
    URL += '/lists/'+ process.env.LIST_ID +'/members'

    const submitSubscribe = async e => {
        e.preventDefault()

        const payload = {
            'email_address': userEmail.email_address,
            'status': 'subscribed'
        }

        try {          
            const response = await axios.post( URL , payload, {
                headers: {
                    'Authorization': 'Basic ' + Buffer.from(creds ).toString('base64')
                }
            })
            console.log('r', response)
            console.log('r data', response.data)
          } catch(err) {
            console.log(err);
          }

    }

    return (
        <form name="newsletter-signup" method="post" onSubmit={submitSubscribe}>
            {/*<input type="hidden" name="form-name" value="newsletter-signup" />*/}
            <input type="email" placeholder="Email required" onChange={handleChange} value={userEmail.email_address} required />
            <button type="submit" className="button primary-button-inverted">Send'</button>
        </form>
    )
}

所以,发生的事情是在 运行 时间,我的 env vars 出现了 undefined

我一直在看 Netlify 文档,他们一直说您需要 插入 客户端的值才能使用它们。我明白这里的逻辑。这些环境变量需要在构建时打印和捆绑,而不是在 运行 时间调用。

我遇到的问题是我该如何

我已经在项目的根目录中设置了一个 .env.development 文件。我试过用 GATSBY_ 作为我的环境变量的前缀,但我仍然遇到同样的问题。

我尝试使用 require('dotenv').config(),但我不确定 准确地放置在何处(在我的 gatsby-node.jsgatsby-config.js 中)或我是否需要在页面上包含使用这些环境变量的组件?

我希望能够在一个地方设置这些变量(如果在开发中测试的话可能是两个)但是我不想为了能够在开发和生产构建中使用它们而进行太多调整.

我也知道 Netlify 或 Gatsby 可以将这些变量处理到我的源代码中的 functions/ 文件夹中,我可以以某种方式利用它,但这似乎比我需要的更多 post一个简单的表格。

请帮忙!

更新

当前代码:

在我的项目根目录中,我创建了两个 .env 文件,一个用于开发,一个用于生产。它们各自共享以下格式(请记住,我正在使用 GatsbyJS 进行开发):

GATSBY_MC_API_KEY="xxxxxxxxxxxxxxxxxxxxxxxxx-xxxx"
GATSBY_MC_DATA_NO="xxxx"
GATSBY_MC_AUDIENCE_ID="xxxxxxxxxxx"

我在 src/config/config.js 中设置了一个单独的 config.js 文件来组织和验证我的 env vars(感谢@Baboo_)。看起来像:

export const MC_API_KEY = process.env.GATSBY_MC_API_KEY;
export const MC_DATA_NO = process.env.GATSBY_MC_DATA_NO;
export const MC_AUDIENCE_ID = process.env.GATSBY_MC_AUDIENCE_ID;

const envVars = [
    {name: "MC_API_KEY", value: MC_API_KEY},
    {name: "MC_DATA_NO", value: MC_DATA_NO},
    {name: "MC_AUDIENCE_ID", value: MC_AUDIENCE_ID}
]

export const checkEnvVars = () => {
    const envVarsNotLoaded = envVars.filter((envVar) => envVar.value !== undefined);
    if (envVarsNotLoaded.length > 0) {
        throw new Error(`Could not load env vars ${envVarsNotLoaded.join(",")}`);
    }
}

checkEnvVars()

但是,当我 运行 gatsby develop 时,会抛出 "Could not load env vars" 错误。

你做得对。

你所要做的确实是在你的环境变量前加上GATSBY_,Gatsby 会自动加载它们。然后在您的代码中调用它们:

const creds = 'anystring:'+ process.env.GATSBY_API_KEY
let URL = 'https://'+ process.env.GATSBY_DATA_NO +'.api.example.com/3.0'
tURL += '/lists/'+ process.env.GATSBY_LIST_ID +'/members'

确保使用整个字符串 process.env.GATSBY_LIST_ID 而不是 process.env[GATSBY_LIST_ID] 因为对象 process.envundefined.

本地

确保创建 .env 个文件,.env.development.env.production。前者用于 运行 gatsby develop 后者用于 运行 gatsby build.

您可能已经知道不应该提交这些文件。

Netlify

在 Netlify 上的部署管道中添加相同的环境变量。这里是related doc。这样 Netlify 就可以在部署时构建您的网站。

改进

不是直接引用环境变量,而是在加载它们的地方创建一个文件,如果无法检索其中一个,则抛出错误。这样当加载失败时你会被注意到并节省调试时间。

示例:

// config.js
export const API_KEY = process.env.GATSBY_API_KEY;
export const DATA_NO = process.env.GATSBY_DATA_NO ;

const envVars = [
    {name: "API_KEY", value: API_KEY},
    {name: "DATA_NO", value: DATA_NO},
]

const checkEnvVars = () => {
    const envVarsNotLoaded = envVars.filter(isUndefined);
    if (envVarsNotLoaded.length > 0) {
        throw new Error(`Could not load env vars ${envVarsNotLoaded.join(",")}`);
    }
}

const isUndefined = (envVar) => typeof envVar.value === "undefined";

// component.js
import React, { useState } from "react"
import axios from 'axios'
// Import environment variables
import { API_KEY, DATA_NO } from "./config"

const Form = () => {
    // ...

    const [userEmail, setState] = useState({'email_address': ''})

    const creds = 'anystring:'+ API_KEY
    let URL = 'https://'+ DATA_NO +'.api.example.com/3.0'