I apologize if this question has been answered before, but I'm banging my head against the wall here with something that should be simple ....
My project is running in server
mode. We need to be able to pass environment variables in at runtime and have them available on both server- and client-side
I'm using the publicRuntimeConfig
approach as described in the docs and I haven't done anything out of the ordinary (code to follow)
The problem is when running in dev mode (yarn dev
) everything works as expected, but when I build the project and dockerize it (or move it to kubernetes for deployment), it doesn't work correctly.
Here's the code:
next.config.js
const nextConfig = {
publicRuntimeConfig: {
PARAM_A: process.env.PARAM_A || "defaultA",
PARAM_B: process.env.PARAM_B || "defaultB"
}
};
module.exports = nextConfig;
_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;
index.tsx
, otherpage.tsx
and help.tsx
are identical apart from their wording, so I'll only put down index.tsx
to save space:
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;
When I run yarn dev
, the output in the browser dev tools for this line
console.log("[INDEX PAGE] - nextConfig", nextConfig);
is as expected (note PARAM_A
and PARAM_B
):
[INDEX PAGE] - nextConfig
{serverRuntimeConfig: {…}, publicRuntimeConfig: {…}}
serverRuntimeConfig: {}
publicRuntimeConfig:
PARAM_A: "mycustomAvalue"
PARAM_B: "mycustomBvalue"
__proto__: Object
__proto__: Object
When I dockerize the project and provide the env variables, the output is as follows for all pages and nothing gets passed from server-side to client-side for publicRuntimeConfig
:
[INDEX PAGE] - nextConfig
{serverRuntimeConfig: {…}, publicRuntimeConfig: {…}}
serverRuntimeConfig: {}
publicRuntimeConfig: {}
__proto__: Object
The first page gets the values (because the getInitialProps is executed in _app.tsx) but whenever I navigate to any other page (Using next/link) I lose the variables. I need these values available across my app in all the pages. Please tell me I'm missing something obvious.
The publicRuntimeConfig
is going to be bundled when you build your app.
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
# ...
Then pass the env variables as build args:
docker build --build-arg PARAM_A=something --build-arg PARAM_B=something ...
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With