NextJS 和环境变量 - 向客户端获取值

Tec*_*mic 5 environment-variables typescript docker next.js

如果之前已经回答过这个问题,我深表歉意,但我在这里用一些应该很简单的东西撞墙......

我的项目正在server模式下运行。我们需要能够在通过环境变量在运行时间,并让他们可用两种服务器端和客户端

我正在使用文档中publicRuntimeConfig描述的方法,但我没有做任何不寻常的事情(要遵循的代码)

问题是在开发模式 ( yarn dev)下运行时一切正常,但是当我构建项目并将其 dockerize (或将其移动到 kubernetes 进行部署)时,它无法正常工作。

这是代码: next.config.js

const nextConfig = {
  publicRuntimeConfig: {
    PARAM_A: process.env.PARAM_A || "defaultA",
    PARAM_B: process.env.PARAM_B || "defaultB"
  }
};

module.exports = nextConfig;
Run Code Online (Sandbox Code Playgroud)

_app.tsx

import React from "react";
import App, { AppContext } from "next/app";
import Head from "next/head";
import { Menu } from "../src/components/menu";


class CustomApp extends App {
  static async getInitialProps({ Component, ctx }: AppContext) {
    let pageProps = {};

    if (Component.getInitialProps) {
      pageProps = await Component.getInitialProps(ctx);
      console.log("[_app.tsx] pageProps", pageProps);
    }

    return { pageProps };
  }

  render() {
    const { Component, pageProps } = this.props;

    return (
      <>
        <Head>
          <title>Testing Area</title>
        </Head>
        <Menu />
        <Component {...pageProps} />
      </>
    );
  }
}

export default CustomApp;
Run Code Online (Sandbox Code Playgroud)

index.tsxotherpage.tsxhelp.tsx从他们的措辞除了相同的,所以我只放了下来index.tsx,节省空间:

import React, { Component } from "react";
import getConfig from "next/config";
import { NextPageContext } from "next";

class Index extends Component {
  static async getInitialProps(ctx: NextPageContext) {
    const nextConfig = getConfig();
    const clientConfig = (nextConfig && nextConfig.publicRuntimeConfig) || {};
    const settings =  Object.keys(process.env).length > 1 ? process.env : clientConfig;
    console.log("[INDEX PAGE] - nextConfig", nextConfig);
    console.log("[INDEX PAGE] - clientConfig", nextConfig.publicRuntimeConfig);
    console.log("[INDEX PAGE] - settings", settings);
    console.log("[INDEX PAGE] - process.env", process.env);

    return { settings };
  }

  render() {
    return <div>INDEX Page</div>;
  }
}

export default Index;
Run Code Online (Sandbox Code Playgroud)

当我运行时yarn dev,此行的浏览器开发工具中的输出符合 console.log("[INDEX PAGE] - nextConfig", nextConfig); 预期(注意PARAM_APARAM_B):

[INDEX PAGE] - nextConfig 
{serverRuntimeConfig: {…}, publicRuntimeConfig: {…}}
serverRuntimeConfig: {}
publicRuntimeConfig:
PARAM_A: "mycustomAvalue"
PARAM_B: "mycustomBvalue"
__proto__: Object
__proto__: Object
Run Code Online (Sandbox Code Playgroud)

当我对项目进行 dockerize 并提供 env 变量时,所有页面的输出如下所示,并且没有任何内容从服务器端传递到客户端publicRuntimeConfig

[INDEX PAGE] - nextConfig 
{serverRuntimeConfig: {…}, publicRuntimeConfig: {…}}
serverRuntimeConfig: {}
publicRuntimeConfig: {}
__proto__: Object
Run Code Online (Sandbox Code Playgroud)

第一个页面获取值(因为 getInitialProps 在 _app.tsx 中执行)但是每当我导航到任何其他页面(使用 next/link)时,我都会丢失变量。我需要这些值在我的应用程序的所有页面中都可用。请告诉我我遗漏了一些明显的东西。

Ste*_*ado 6

当您构建应用程序时,它将publicRuntimeConfig被捆绑。

Your app build happens when you build your Docker image. However, your environment variables are not available at this time.

When you start your container, you supply your environment variables so your server-side code can use them, but your client-side code cannot.


One solution would be to build your app on container start, as the build would then have access to the env variables that you supply. I would not really recommend this approach though.

Another solution would be to use Docker build args to set your environment variables at build time:

Dockerfile

ARG PARAM_A
ARG PARAM_B

ENV PARAM_A=$PARAM_A
ENV PARAM_B=$PARAM_B

# ...
Run Code Online (Sandbox Code Playgroud)

Then pass the env variables as build args:

docker build --build-arg PARAM_A=something --build-arg PARAM_B=something ...
Run Code Online (Sandbox Code Playgroud)

This allows you to pass different build args for each environment.

However, this does mean that you have a separate image for each of your environments.

I hope this helps.