Skip to content

Commit

Permalink
Expose environment variables to client (#11375)
Browse files Browse the repository at this point in the history
* Testing exposing clientside env vars

* Test in Express app

* import fix

* Rename env variables object to be clearer and what it does

* Remove `SIMORGH_APP_ENV` from `next.config.js`

* Use initialiser method to allow `process.env` overrides

- This is mainly to support tests that set the `process.env` values within the tests

* Update index.ts

* Test with `SIMORGH_ATI_BASE_URL`

* Type check `SIMORGH_APP_ENV`

* Update _document.page.tsx

* Update index.ts

* Update component.jsx

* Update `process.env` references to use `getEnvConfig()`

* Add missing cache config

* Set ichef default back

* Fix import

* Update index.ts

* Snapshot update

* Test removing `getEnvConfig` from `getOriginContext`

* Revert "Test removing `getEnvConfig` from `getOriginContext`"

This reverts commit 81e26db.

* Update index.ts

* Test removing path aliasing

* Add test

* Improve tests

* Update index.test.ts

* Remove `process.env` from clientside test

- These should be coming from the `window` object, so its more accurate to remove these
  • Loading branch information
amoore108 authored Mar 6, 2024
1 parent a97bb56 commit 1259bab
Show file tree
Hide file tree
Showing 41 changed files with 275 additions and 71 deletions.
3 changes: 2 additions & 1 deletion src/app/components/ATIAnalytics/amp/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/** @jsxRuntime classic */
/** @jsx jsx */
import { jsx } from '@emotion/react';
import { getEnvConfig } from '#app/lib/utilities/getEnvConfig';
import getAmpAnalyticsJson from './ampAnalyticsJson';
import { ATIAnalyticsProps, AMPAnalyticsData } from '../types';

Expand All @@ -17,7 +18,7 @@ const AmpATIAnalytics = ({ pageviewParams }: ATIAnalyticsProps) => {
<amp-analytics>
{JsonInlinedScript(
getAmpAnalyticsJson({
baseUrl: process.env.SIMORGH_ATI_BASE_URL,
baseUrl: getEnvConfig().SIMORGH_ATI_BASE_URL,
pageviewParams,
}),
)}
Expand Down
3 changes: 2 additions & 1 deletion src/app/components/ATIAnalytics/atiUrl/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { getEnvConfig } from '#app/lib/utilities/getEnvConfig';
import {
getDestination,
getAppType,
Expand Down Expand Up @@ -328,7 +329,7 @@ export const buildATIEventTrackUrl = ({
},
];

return `${process.env.SIMORGH_ATI_BASE_URL}${getAtiUrl(
return `${getEnvConfig().SIMORGH_ATI_BASE_URL}${getAtiUrl(
eventTrackingBeaconValues,
)}&type=AT`;
};
3 changes: 2 additions & 1 deletion src/app/components/ATIAnalytics/canonical/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React, { useEffect, useState } from 'react';
import { getEnvConfig } from '#app/lib/utilities/getEnvConfig';
import sendBeacon from '../../../lib/analyticsUtils/sendBeacon';
import { ATIAnalyticsProps } from '../types';

Expand All @@ -24,7 +25,7 @@ const renderNoScriptTrackingPixel = (atiPageViewUrl: string) => (

const CanonicalATIAnalytics = ({ pageviewParams }: ATIAnalyticsProps) => {
const [atiPageViewUrl] = useState(
process.env.SIMORGH_ATI_BASE_URL + pageviewParams,
getEnvConfig().SIMORGH_ATI_BASE_URL + pageviewParams,
);

useEffect(() => {
Expand Down
5 changes: 4 additions & 1 deletion src/app/components/Ad/Amp/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
AMP_ACCESS_JS,
AMP_ADS_JS,
} from '#psammead/psammead-assets/src/amp-boilerplate';
import { getEnvConfig } from '#app/lib/utilities/getEnvConfig';
import { ServiceContext } from '../../../contexts/ServiceContext';
import getAdsAriaLabel from '../utilities/getAdsAriaLabel';
import AdSlot from './AdSlot';
Expand All @@ -29,7 +30,9 @@ const AMP_ACCESS_DATA = (endpoint: string) => ({
const LABEL_LINK = 'https://www.bbc.com/usingthebbc/cookies/';

export const AMP_ACCESS_FETCH = (service: Services) => {
const togglesEndpoint = `${process.env.SIMORGH_CONFIG_URL}?application=simorgh&service=${service}`;
const togglesEndpoint = `${
getEnvConfig().SIMORGH_CONFIG_URL
}?application=simorgh&service=${service}`;

return (
<script id="amp-access" type="application/json">
Expand Down
5 changes: 4 additions & 1 deletion src/app/components/Embeds/EmbedImages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import { jsx } from '@emotion/react';
import { PropsWithChildren, useContext } from 'react';
import { RequestContext } from '#app/contexts/RequestContext';
import { getEnvConfig } from '#app/lib/utilities/getEnvConfig';
import styles from './index.styles';
import Image from '../../Image';

Expand All @@ -23,7 +24,9 @@ const EmbedImages = ({ blocks: embedImages }: PropsWithChildren<Props>) => {

const sanitizedLocator = locator?.replace(/^\//, '');

const src = `${process.env.SIMORGH_ICHEF_BASE_URL}/news/${width}/${idt2EnvUrlSubPath}/${sanitizedLocator}`;
const src = `${
getEnvConfig().SIMORGH_ICHEF_BASE_URL
}/news/${width}/${idt2EnvUrlSubPath}/${sanitizedLocator}`;
const alt =
image?.[0]?.model?.blocks?.[0]?.model?.blocks?.[0]?.model?.blocks?.[0]
?.model?.text;
Expand Down
5 changes: 3 additions & 2 deletions src/app/components/Metadata/utils/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/* eslint-disable @typescript-eslint/ban-ts-comment */
import React from 'react';
import { Services } from '#app/models/types/global';
import { getEnvConfig } from '#app/lib/utilities/getEnvConfig';
import { AppleItunesApp, AlternateLink, IconSizes, IconType } from '../types';

export const getIconAssetUrl = (service: Services, size: string) =>
Expand Down Expand Up @@ -49,8 +50,8 @@ export const getIconLinks = (service: Services, iconSizes: IconSizes) => {

export const getAppleTouchUrl = (service: Services) => {
return [
process.env.SIMORGH_PUBLIC_STATIC_ASSETS_ORIGIN,
process.env.SIMORGH_PUBLIC_STATIC_ASSETS_PATH,
getEnvConfig().SIMORGH_PUBLIC_STATIC_ASSETS_ORIGIN,
getEnvConfig().SIMORGH_PUBLIC_STATIC_ASSETS_PATH,
service,
'/images/icons/icon-192x192.png',
].join('');
Expand Down
3 changes: 2 additions & 1 deletion src/app/components/MostRead/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React, { useContext } from 'react';
import { RequestContext } from '#contexts/RequestContext';
import useToggle from '#hooks/useToggle';
import { getMostReadEndpoint } from '#app/lib/utilities/getUrlHelpers/getMostReadUrls';
import { getEnvConfig } from '#app/lib/utilities/getEnvConfig';
import { ServiceContext } from '../../contexts/ServiceContext';
import Canonical from './Canonical';
import Amp from './Amp';
Expand Down Expand Up @@ -77,7 +78,7 @@ const MostRead = ({
backgroundColor={headingBackgroundColour}
/>
<Amp
endpoint={`${process.env.SIMORGH_MOST_READ_CDN_URL}${endpoint}`}
endpoint={`${getEnvConfig().SIMORGH_MOST_READ_CDN_URL}${endpoint}`}
size={size}
/>
</MostReadSection>
Expand Down
3 changes: 2 additions & 1 deletion src/app/components/ServiceWorker/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import onClient from '#lib/utilities/onClient';
import { RequestContext } from '#contexts/RequestContext';
import { jsx } from '@emotion/react';
import isLocal from '#app/lib/utilities/isLocal';
import { getEnvConfig } from '#app/lib/utilities/getEnvConfig';
import { ServiceContext } from '../../contexts/ServiceContext';

interface AmpServiceWorkerProps {
Expand Down Expand Up @@ -38,7 +39,7 @@ const AmpServiceWorker = ({
export default () => {
const { swPath, service } = useContext(ServiceContext);
const { isAmp, canonicalLink } = useContext(RequestContext);
const swSrc = `${process.env.SIMORGH_BASE_URL}/${service}${swPath}`;
const swSrc = `${getEnvConfig().SIMORGH_BASE_URL}/${service}${swPath}`;

useEffect(() => {
const shouldInstallServiceWorker =
Expand Down
8 changes: 5 additions & 3 deletions src/app/contexts/RequestContext/getOriginContext/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { getEnvConfig } from '../../../lib/utilities/getEnvConfig';

const getOriginContext = (bbcOrigin: string | null) => {
let origin = 'https://www.bbc.co.uk';

Expand All @@ -6,16 +8,16 @@ const getOriginContext = (bbcOrigin: string | null) => {
} else if (
process &&
process.env &&
process.env.SIMORGH_APP_ENV === 'local'
getEnvConfig().SIMORGH_APP_ENV === 'local'
) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
origin = process.env.SIMORGH_BASE_URL!;
origin = getEnvConfig().SIMORGH_BASE_URL!;
} else if (
typeof window !== 'undefined' &&
window.location &&
window.location.origin
) {
origin = window.location.origin; // eslint-disable-line prefer-destructuring
origin = window.location.origin;
}

return {
Expand Down
3 changes: 2 additions & 1 deletion src/app/contexts/ToggleContext/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@ import React, {
} from 'react';
import defaultToggles from '#lib/config/toggles';
import { Environments, Toggles } from '#app/models/types/global';
import { getEnvConfig } from '#app/lib/utilities/getEnvConfig';
import toggleReducer from './reducer';

const environment = (process.env.SIMORGH_APP_ENV || 'local') as Environments;
const environment = (getEnvConfig().SIMORGH_APP_ENV || 'local') as Environments;

type ToggleContextProps = {
toggleState: Toggles;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import { getEnvConfig } from '#app/lib/utilities/getEnvConfig';
import { Services } from '#app/models/types/global';

export default (service: Services, origin: string | null) => {
const requestOrigin = origin || 'https://www.test.bbc.com';
const baseTogglesUrl = `${process.env.SIMORGH_CONFIG_URL}?application=simorgh&service=${service}&__amp_source_origin=${requestOrigin}`; // __amp_source_origin is relevant to both canonical and amp
const baseTogglesUrl = `${
getEnvConfig().SIMORGH_CONFIG_URL
}?application=simorgh&service=${service}&__amp_source_origin=${requestOrigin}`; // __amp_source_origin is relevant to both canonical and amp

return baseTogglesUrl;
};
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@
import React, { useContext, useEffect } from 'react';
import { Helmet } from 'react-helmet';
import { UserContext } from '#contexts/UserContext';
import { getEnvConfig } from '#app/lib/utilities/getEnvConfig';

const CanonicalComscoreAnalytics = () => {
const { personalisationEnabled } = useContext(UserContext);

const staticAssetsPath = `${process.env.SIMORGH_PUBLIC_STATIC_ASSETS_ORIGIN}${process.env.SIMORGH_PUBLIC_STATIC_ASSETS_PATH}`;
const staticAssetsPath = `${
getEnvConfig().SIMORGH_PUBLIC_STATIC_ASSETS_ORIGIN
}${getEnvConfig().SIMORGH_PUBLIC_STATIC_ASSETS_PATH}`;
const comscoreScript = 'static/js/comscore/main-1.0.js';

useEffect(() => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { getHeadline, getUrl } from '#lib/utilities/getStoryPromoInfo';
import { getEnvConfig } from '#app/lib/utilities/getEnvConfig';

export default ({ item, index } = {}) => {
const block = {
Expand All @@ -13,7 +14,7 @@ export default ({ item, index } = {}) => {
campaignID: 'cps_wsoj',
componentName: encodeURIComponent(headline),
advertiserID,
url: `${process.env.SIMORGH_BASE_URL}${url}`,
url: `${getEnvConfig().SIMORGH_BASE_URL}${url}`,
format: `CHD=promo::${index + 1}`,
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
import isLive from '#lib/utilities/isLive';
import onClient from '#lib/utilities/onClient';
import { GEL_GROUP_3_SCREEN_WIDTH_MAX } from '#psammead/gel-foundations/src/breakpoints';
import { getEnvConfig } from '#app/lib/utilities/getEnvConfig';
import { ServiceContext } from '../../../../contexts/ServiceContext';
import getOptimizelyUserId from './getOptimizelyUserId';

Expand All @@ -18,7 +19,7 @@ if (isLive() || isCypress) {
}

const optimizely = createInstance({
sdkKey: process.env.SIMORGH_OPTIMIZELY_SDK_KEY,
sdkKey: getEnvConfig().SIMORGH_OPTIMIZELY_SDK_KEY,
eventBatchSize: 10,
eventFlushInterval: 1000,
});
Expand Down
6 changes: 4 additions & 2 deletions src/app/legacy/containers/WebVitals/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import { string } from 'prop-types';
// Contexts
import { UserContext } from '#contexts/UserContext';

import { getEnvConfig } from '#app/lib/utilities/getEnvConfig';

const WebVitals = ({ pageType }) => {
const { personalisationEnabled } = useContext(UserContext);

Expand All @@ -15,7 +17,7 @@ const WebVitals = ({ pageType }) => {
const isWebVitalsEnabled = personalisationEnabled && enabled;

const sampleRate = Number(
toggleSampleRate || process.env.SIMORGH_WEBVITALS_DEFAULT_SAMPLING_RATE,
toggleSampleRate || getEnvConfig().SIMORGH_WEBVITALS_DEFAULT_SAMPLING_RATE,
);

const wsPageType = pageType
Expand All @@ -29,7 +31,7 @@ const WebVitals = ({ pageType }) => {

const webVitalsConfig = {
enabled: isWebVitalsEnabled,
reportingEndpoint: process.env.SIMORGH_WEBVITALS_REPORTING_ENDPOINT,
reportingEndpoint: getEnvConfig().SIMORGH_WEBVITALS_REPORTING_ENDPOINT,
sampleRate,
...(wsPageType && {
reportParams: {
Expand Down
6 changes: 5 additions & 1 deletion src/app/lib/utilities/getBrandedImage/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import { getEnvConfig } from '../getEnvConfig';

const getBrandedImage = (locator, service) =>
`${process.env.SIMORGH_ICHEF_BASE_URL}/news/1024/branded_${service}/${locator}`;
`${
getEnvConfig().SIMORGH_ICHEF_BASE_URL
}/news/1024/branded_${service}/${locator}`;

export default getBrandedImage;
54 changes: 54 additions & 0 deletions src/app/lib/utilities/getEnvConfig/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { getEnvConfig } from '.';

let windowSpy: jest.SpyInstance<Window | undefined, []>;

describe('getEnvConfig', () => {
const originalProcessEnv = process.env;

beforeEach(() => {
process.env = originalProcessEnv;
windowSpy = jest.spyOn(window, 'window', 'get');
});

afterEach(() => {
windowSpy.mockRestore();
});

it('server side - should return values from "getEnvConfig"', () => {
process.env.SIMORGH_APP_ENV = 'test';
process.env.SIMORGH_BASE_URL = 'https://test.com';

// simulate server side by removing window object
windowSpy.mockImplementation(() => undefined);

const results = getEnvConfig();

expect(results.SIMORGH_APP_ENV).toEqual('test');
expect(results.SIMORGH_BASE_URL).toEqual('https://test.com');
});

it('client side - should return values from "getEnvConfig"', () => {
// simulate client side by adding window object
windowSpy.mockImplementation(
() =>
({
location: {
origin: 'https://test.com',
},
SIMORGH_ENV_VARS: {
SIMORGH_APP_ENV: 'test',
SIMORGH_BASE_URL: 'https://test.com',
},
} as Window),
);

const results = getEnvConfig();

expect(results.SIMORGH_APP_ENV).toEqual('test');
expect(results.SIMORGH_BASE_URL).toEqual('https://test.com');
expect(window.SIMORGH_ENV_VARS).toEqual({
SIMORGH_APP_ENV: 'test',
SIMORGH_BASE_URL: 'https://test.com',
});
});
});
46 changes: 46 additions & 0 deletions src/app/lib/utilities/getEnvConfig/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { Environments } from '#app/models/types/global';
import onClient from '../onClient';

export type EnvConfig = ReturnType<typeof getProcessEnvAppVariables>;

// Any environment variables added here will be available to the client and server
export const getProcessEnvAppVariables = () => ({
SIMORGH_APP_ENV: process.env.SIMORGH_APP_ENV as Environments,
SIMORGH_ATI_BASE_URL: process.env.SIMORGH_ATI_BASE_URL,
SIMORGH_BASE_URL: process.env.SIMORGH_BASE_URL,
SIMORGH_CONFIG_CACHE_ITEMS: process.env.SIMORGH_CONFIG_CACHE_ITEMS,
SIMORGH_CONFIG_CACHE_MAX_AGE_SECONDS:
process.env.SIMORGH_CONFIG_CACHE_MAX_AGE_SECONDS,
SIMORGH_CONFIG_TIMEOUT_SECONDS: process.env.SIMORGH_CONFIG_TIMEOUT_SECONDS,
SIMORGH_CONFIG_URL: process.env.SIMORGH_CONFIG_URL,
SIMORGH_CSP_REPORTING_ENDPOINT: process.env.SIMORGH_CSP_REPORTING_ENDPOINT,
SIMORGH_ICHEF_BASE_URL: process.env.SIMORGH_ICHEF_BASE_URL,
SIMORGH_INCLUDES_BASE_URL: process.env.SIMORGH_INCLUDES_BASE_URL,
SIMORGH_INCLUDES_BASE_AMP_URL: process.env.SIMORGH_INCLUDES_BASE_AMP_URL,
SIMORGH_MOST_READ_CDN_URL: process.env.SIMORGH_MOST_READ_CDN_URL,
SIMORGH_OPTIMIZELY_SDK_KEY: process.env.SIMORGH_OPTIMIZELY_SDK_KEY,
SIMORGH_PUBLIC_STATIC_ASSETS_ORIGIN:
process.env.SIMORGH_PUBLIC_STATIC_ASSETS_ORIGIN,
SIMORGH_PUBLIC_STATIC_ASSETS_PATH:
process.env.SIMORGH_PUBLIC_STATIC_ASSETS_PATH,
SIMORGH_WEBVITALS_REPORTING_ENDPOINT:
process.env.SIMORGH_WEBVITALS_REPORTING_ENDPOINT,
SIMORGH_WEBVITALS_DEFAULT_SAMPLING_RATE:
process.env.SIMORGH_WEBVITALS_DEFAULT_SAMPLING_RATE,
});

export function getEnvConfig(): EnvConfig {
// Return window object on client and when window.SIMORGH_ENV_VARS is set
if (onClient() && window?.SIMORGH_ENV_VARS) {
return window.SIMORGH_ENV_VARS;
}

// Return server side environment variables
return getProcessEnvAppVariables();
}

declare global {
interface Window {
SIMORGH_ENV_VARS: EnvConfig;
}
}
5 changes: 3 additions & 2 deletions src/app/lib/utilities/getToggles/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
CONFIG_RESPONSE_EMPTY_ERROR,
} from '#lib/logger.const';
import getOriginContext from '#contexts/RequestContext/getOriginContext';
import { getEnvConfig } from '../getEnvConfig';

const logger = nodeLogger(__filename);
const NS_PER_SEC = 1e9;
Expand All @@ -35,9 +36,9 @@ const logResponseTime = async (url, origin, service, timeout) => {
};

const getToggles = async (service, cache) => {
const environment = process.env.SIMORGH_APP_ENV || 'local';
const environment = getEnvConfig().SIMORGH_APP_ENV || 'local';
const timeout =
parseInt(process.env.SIMORGH_CONFIG_TIMEOUT_SECONDS, 10) * 1000;
parseInt(getEnvConfig().SIMORGH_CONFIG_TIMEOUT_SECONDS, 10) * 1000;
const localToggles = defaultToggles[environment];
if (!localToggles.enableFetchingToggles.enabled) {
return localToggles;
Expand Down
Loading

0 comments on commit 1259bab

Please sign in to comment.