feat: runtime env

Support runtime environment variables using server components.

This will mean docker images can change env vars for runtime as required.
This commit is contained in:
Mythie
2023-11-12 13:10:30 +11:00
parent aec0d2ae97
commit 1cd60e1abb
29 changed files with 254 additions and 70 deletions

View File

@ -0,0 +1,26 @@
'use client';
import React, { useContext } from 'react';
import { PublicEnv } from './types';
export type RuntimeEnvClientProviderProps = {
value: PublicEnv;
children: React.ReactNode;
};
const RuntimeEnvContext = React.createContext<PublicEnv | null>(null);
export const useRuntimeEnv = () => {
const context = useContext(RuntimeEnvContext);
if (!context) {
throw new Error('useRuntimeEnv must be used within a RuntimeEnvProvider');
}
return context;
};
export const RuntimeEnvClientProvider = ({ value, children }: RuntimeEnvClientProviderProps) => {
return <RuntimeEnvContext.Provider value={value}>{children}</RuntimeEnvContext.Provider>;
};

View File

@ -0,0 +1,22 @@
import { PublicEnv } from './types';
declare global {
interface Window {
__unstable_runtimeEnv: PublicEnv;
}
}
export const getRuntimeEnv = () => {
if (typeof window === 'undefined') {
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
return Object.entries(process.env)
.filter(([key]) => key.startsWith('NEXT_PUBLIC_'))
.reduce((acc, [key, value]) => ({ ...acc, [key]: value }), {}) as PublicEnv;
}
if (typeof window !== 'undefined' && window.__unstable_runtimeEnv) {
return window.__unstable_runtimeEnv;
}
throw new Error('RuntimeEnv is not available');
};

View File

@ -0,0 +1 @@
export { RuntimeEnvProvider, type RuntimeEnvProviderProps } from './server';

View File

@ -0,0 +1,29 @@
'use server';
import React from 'react';
import { RuntimeEnvClientProvider } from './client';
import { PublicEnv } from './types';
export type RuntimeEnvProviderProps = {
children: React.ReactNode;
};
export const RuntimeEnvProvider = ({ children }: RuntimeEnvProviderProps) => {
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
const publicEnv = Object.entries(process.env)
.filter(([key]) => key.startsWith('NEXT_PUBLIC_'))
.reduce((acc, [key, value]) => ({ ...acc, [key]: value }), {}) as PublicEnv;
return (
<RuntimeEnvClientProvider value={publicEnv}>
{children}
<script
dangerouslySetInnerHTML={{
__html: `window.__unstable_runtimeEnv = ${JSON.stringify(publicEnv)}`,
}}
/>
</RuntimeEnvClientProvider>
);
};

View File

@ -0,0 +1,3 @@
import { PickStartsWith } from '../../types/pick-starts-with';
export type PublicEnv = PickStartsWith<typeof process.env, 'NEXT_PUBLIC_'>;