diff --git a/dotcom-rendering/src/client/discussion.ts b/dotcom-rendering/src/client/discussion.ts index fdcc7e1ae86..26521cbdce0 100644 --- a/dotcom-rendering/src/client/discussion.ts +++ b/dotcom-rendering/src/client/discussion.ts @@ -20,7 +20,7 @@ const forceHydration = async (): Promise => { // Read the props and config from where they have been serialised in the dom using an Island const props = getProps(guElement); - const config = getConfig(guElement); + const config = getConfig(); // Now that we have the props as an object, tell Discussion we want it to expand itself props.expanded = true; diff --git a/dotcom-rendering/src/client/islands/getConfig.ts b/dotcom-rendering/src/client/islands/getConfig.ts index a6fdef28848..839d602c9eb 100644 --- a/dotcom-rendering/src/client/islands/getConfig.ts +++ b/dotcom-rendering/src/client/islands/getConfig.ts @@ -1,21 +1,23 @@ import type { Config } from '../../types/configContext'; +let config: Config | undefined; /** - * getConfig takes the given html element and returns its config attribute + * Reads the config from a JSON script tag, + * or reuse the memoised value if it exists. * - * We expect the element to always be a `gu-*` custom element - * - * @param marker : The html element that we want to read the config attribute from; - * @returns + * @returns {Config} an immutable, global config */ -export const getConfig = (marker: HTMLElement): Config => { - const serialised = marker.getAttribute('config'); +export const getConfig = (): Readonly => { + if (config) return config; + + const serialised = document.querySelector('script#config')?.innerHTML; try { if (!serialised) { - throw Error('Unable to fetch config attribute from marker element'); + throw Error('Unable to fetch config attribute from #config'); } else { - return JSON.parse(serialised) as Config; + config = JSON.parse(serialised) as Config; + return config; } } catch (error: unknown) { console.error( diff --git a/dotcom-rendering/src/client/islands/initHydration.ts b/dotcom-rendering/src/client/islands/initHydration.ts index 768a1c1ed5d..bfe49460b3b 100644 --- a/dotcom-rendering/src/client/islands/initHydration.ts +++ b/dotcom-rendering/src/client/islands/initHydration.ts @@ -39,7 +39,7 @@ export const initHydration = async ( ): Promise => { const name = getName(element); const props = getProps(element); - const config = getConfig(element); + const config = getConfig(); const priority = getPriority(element); if (!name) return; diff --git a/dotcom-rendering/src/components/ArticleMeta.test.tsx b/dotcom-rendering/src/components/ArticleMeta.test.tsx index f1f93978c03..754a861ad59 100644 --- a/dotcom-rendering/src/components/ArticleMeta.test.tsx +++ b/dotcom-rendering/src/components/ArticleMeta.test.tsx @@ -21,6 +21,7 @@ describe('ArticleMeta', () => { darkModeAvailable: false, updateLogoAdPartnerSwitch: false, assetOrigin: '/', + editionId: 'UK', }} > { darkModeAvailable: false, updateLogoAdPartnerSwitch: false, assetOrigin: '/', + editionId: 'UK', }} > { darkModeAvailable: false, updateLogoAdPartnerSwitch: false, assetOrigin: '/', + editionId: 'UK', }} > { darkModeAvailable: false, updateLogoAdPartnerSwitch: false, assetOrigin: '/', + editionId: 'UK', }} > { darkModeAvailable: false, updateLogoAdPartnerSwitch: false, assetOrigin: '/', + editionId: 'UK', }} > { darkModeAvailable: false, updateLogoAdPartnerSwitch: false, assetOrigin: '/', + editionId: 'UK', }} > { darkModeAvailable: false, updateLogoAdPartnerSwitch: false, assetOrigin: '/', + editionId: 'UK', }} > { darkModeAvailable: false, updateLogoAdPartnerSwitch: false, assetOrigin: '/', + editionId: 'UK', }, { renderingTarget: 'Apps', darkModeAvailable: true, updateLogoAdPartnerSwitch: false, assetOrigin: '/', + editionId: 'UK', }, { renderingTarget: 'Apps', darkModeAvailable: false, updateLogoAdPartnerSwitch: false, assetOrigin: '/', + editionId: 'INT', }, ] as const satisfies ReadonlyArray)( 'useConfig hook provides correct config: "%o"', diff --git a/dotcom-rendering/src/components/Contributor.test.tsx b/dotcom-rendering/src/components/Contributor.test.tsx index 6d3a10912de..f2d0cd7637f 100644 --- a/dotcom-rendering/src/components/Contributor.test.tsx +++ b/dotcom-rendering/src/components/Contributor.test.tsx @@ -21,6 +21,7 @@ describe('Contributor', () => { darkModeAvailable: false, updateLogoAdPartnerSwitch: false, assetOrigin: '/', + editionId: 'UK', }} > { darkModeAvailable: false, updateLogoAdPartnerSwitch: false, assetOrigin: '/', + editionId: 'UK', }} > { darkModeAvailable: false, updateLogoAdPartnerSwitch: false, assetOrigin: '/', + editionId: 'UK', }} > { darkModeAvailable: false, updateLogoAdPartnerSwitch: false, assetOrigin: '/', + editionId: 'UK', }} > { darkModeAvailable: false, updateLogoAdPartnerSwitch: false, assetOrigin: '/', + editionId: 'UK', }} > { darkModeAvailable: false, updateLogoAdPartnerSwitch: false, assetOrigin: '/', + editionId: 'UK', }} > { darkModeAvailable: false, updateLogoAdPartnerSwitch: false, assetOrigin: '/', + editionId: 'UK', }} > { darkModeAvailable: false, updateLogoAdPartnerSwitch: false, assetOrigin: '/', + editionId: 'UK', }} > { darkModeAvailable: false, updateLogoAdPartnerSwitch: false, assetOrigin: '/', + editionId: 'UK', }} > { darkModeAvailable: false, updateLogoAdPartnerSwitch: false, assetOrigin: '/', + editionId: 'UK', }} > @@ -39,6 +40,7 @@ describe('GuideAtom', () => { darkModeAvailable: false, updateLogoAdPartnerSwitch: false, assetOrigin: '/', + editionId: 'UK', }} > @@ -66,6 +68,7 @@ describe('GuideAtom', () => { darkModeAvailable: false, updateLogoAdPartnerSwitch: false, assetOrigin: '/', + editionId: 'UK', }} > diff --git a/dotcom-rendering/src/components/Island.test.tsx b/dotcom-rendering/src/components/Island.test.tsx index e9c1ff5642e..f4ab68adcb0 100644 --- a/dotcom-rendering/src/components/Island.test.tsx +++ b/dotcom-rendering/src/components/Island.test.tsx @@ -3,6 +3,7 @@ */ import { ArticleDesign, ArticleDisplay, Pillar } from '@guardian/libs'; +import type { PropsWithChildren } from 'react'; import { renderToString } from 'react-dom/server'; import { AdPortals } from './AdPortals.importable'; import { AlreadyVisited } from './AlreadyVisited.importable'; @@ -77,6 +78,21 @@ const Mock = () => <>🏝️; // Jest tests describe('Island: server-side rendering', () => { + /** Helper to provide config for islands */ + const WithConfig = ({ children }: PropsWithChildren) => ( + + {children} + + ); + test('AdPortals', () => { expect(() => renderToString()).not.toThrow(); }); @@ -92,16 +108,9 @@ describe('Island: server-side rendering', () => { test('BrazeMessaging', () => { expect(() => renderToString( - + - , + , ), ).not.toThrow(); }); @@ -123,20 +132,13 @@ describe('Island: server-side rendering', () => { test('DiscussionMeta', () => { expect(() => renderToString( - + - , + , ), ).not.toThrow(); }); @@ -144,14 +146,7 @@ describe('Island: server-side rendering', () => { test('Discussion', () => { expect(() => renderToString( - + { isAdFreeUser={false} shouldHideAds={false} /> - , + , ), ).not.toThrow(); }); @@ -175,16 +170,9 @@ describe('Island: server-side rendering', () => { test('EnhancePinnedPost', () => { expect(() => renderToString( - + - , + , ), ).not.toThrow(); }); @@ -204,14 +192,7 @@ describe('Island: server-side rendering', () => { test('OnwardsUpper', () => { expect(() => renderToString( - + { discussionApiUrl="" absoluteServerTimes={true} /> - , + , ), ).not.toThrow(); }); @@ -299,16 +280,9 @@ describe('Island: server-side rendering', () => { test('Metrics', () => { expect(() => renderToString( - + - , + , ), ).not.toThrow(); }); @@ -324,14 +298,7 @@ describe('Island: server-side rendering', () => { test('MostViewedRightWithAd', () => { expect(() => renderToString( - + { shouldHideReaderRevenue={false} /> , - , + , ), ).not.toThrow(); }); @@ -359,14 +326,7 @@ describe('Island: server-side rendering', () => { test('ReaderRevenueLinks', () => { expect(() => renderToString( - + { contribute: '', }} /> - , + , ), ).not.toThrow(); }); @@ -397,14 +357,7 @@ describe('Island: server-side rendering', () => { test('SetABTests', () => { expect(() => renderToString( - + { serverSideTests={{}} /> , - , + , ), ).not.toThrow(); }); @@ -436,14 +389,7 @@ describe('Island: server-side rendering', () => { test('SignInGateSelector', () => { expect(() => renderToString( - + { pageId={''} switches={{}} /> - , + , ), ).not.toThrow(); }); @@ -460,14 +406,7 @@ describe('Island: server-side rendering', () => { test('SlotBodyEnd', () => { expect(() => renderToString( - + { isLabs={false} articleEndSlot={true} /> - , + , ), ).not.toThrow(); }); @@ -491,14 +430,7 @@ describe('Island: server-side rendering', () => { test('StickyBottomBanner', () => { expect(() => renderToString( - + { remoteBannerSwitch={true} isSensitive={false} /> - , + , ), ).not.toThrow(); }); @@ -521,14 +453,7 @@ describe('Island: server-side rendering', () => { test('SupportTheG', () => { expect(() => renderToString( - + { contribute: '', }} /> - , + , ), ).not.toThrow(); }); @@ -549,14 +474,7 @@ describe('Island: server-side rendering', () => { test('ShareButton', () => { expect(() => renderToString( - + { }} context="ArticleMeta" /> - , + , ), ).not.toThrow(); }); diff --git a/dotcom-rendering/src/components/Island.tsx b/dotcom-rendering/src/components/Island.tsx index cb32f8aa7f0..94a2a6b9975 100644 --- a/dotcom-rendering/src/components/Island.tsx +++ b/dotcom-rendering/src/components/Island.tsx @@ -1,5 +1,4 @@ import type { ScheduleOptions, SchedulePriority } from '../lib/scheduler'; -import { useConfig } from './ConfigContext'; type DeferredProps = { visible: { @@ -49,14 +48,6 @@ type IslandProps = { * @param {JSX.Element} props.children - The component being inserted. Must be a single JSX Element */ export const Island = ({ priority, defer, children }: IslandProps) => { - /** - * Where is this coming from? - * Config value is set at high in the component tree within a React context in a `` - * - * This is here so that we can provide the config information to the hydrated, client-side rendered components - */ - const config = useConfig(); - const rootMargin = defer?.until === 'visible' ? defer.rootMargin : undefined; @@ -70,7 +61,6 @@ export const Island = ({ priority, defer, children }: IslandProps) => { deferUntil={defer?.until} props={JSON.stringify(children.props)} rootMargin={rootMargin} - config={JSON.stringify(config)} > {children} @@ -88,9 +78,4 @@ export type GuIsland = { rootMargin?: string; props: string; children: React.ReactNode; - /** - * This should be a stringified JSON of `ConfigContext` - * @see /dotcom-rendering/src/types/configContext.ts - */ - config: string; }; diff --git a/dotcom-rendering/src/components/LatestLinks.importable.tsx b/dotcom-rendering/src/components/LatestLinks.importable.tsx index 219087d679b..c9d258002d7 100644 --- a/dotcom-rendering/src/components/LatestLinks.importable.tsx +++ b/dotcom-rendering/src/components/LatestLinks.importable.tsx @@ -12,6 +12,7 @@ import { useApi } from '../lib/useApi'; import { palette as themePalette } from '../palette'; import type { DCRContainerPalette } from '../types/front'; import { WithLink } from './CardHeadline'; +import { useConfig } from './ConfigContext'; import { ContainerOverrides } from './ContainerOverrides'; import { DateTime } from './DateTime'; @@ -125,6 +126,8 @@ export const LatestLinks = ({ min-height: ${minHeight}; `; + const { editionId } = useConfig(); + return (
    { darkModeAvailable: false, updateLogoAdPartnerSwitch: false, assetOrigin: '/', + editionId: 'UK', }} > { darkModeAvailable: false, updateLogoAdPartnerSwitch: false, assetOrigin: '/', + editionId: 'UK', }} > { darkModeAvailable: false, updateLogoAdPartnerSwitch: false, assetOrigin: '/', + editionId: 'UK', }} > { darkModeAvailable: false, updateLogoAdPartnerSwitch: false, assetOrigin: '/', + editionId: 'UK', }} > { darkModeAvailable: false, updateLogoAdPartnerSwitch: false, assetOrigin: '/', + editionId: 'UK', }} > { darkModeAvailable: false, updateLogoAdPartnerSwitch: false, assetOrigin: '/', + editionId: 'UK', }} > @@ -75,6 +76,7 @@ describe('MostViewedList', () => { darkModeAvailable: false, updateLogoAdPartnerSwitch: false, assetOrigin: '/', + editionId: 'UK', }} > @@ -104,6 +106,7 @@ describe('MostViewedList', () => { darkModeAvailable: false, updateLogoAdPartnerSwitch: false, assetOrigin: '/', + editionId: 'UK', }} > diff --git a/dotcom-rendering/src/components/Nav/Nav.test.tsx b/dotcom-rendering/src/components/Nav/Nav.test.tsx index ce9dba80b74..e9cb99a6ab8 100644 --- a/dotcom-rendering/src/components/Nav/Nav.test.tsx +++ b/dotcom-rendering/src/components/Nav/Nav.test.tsx @@ -12,6 +12,7 @@ describe('Nav', () => { darkModeAvailable: false, updateLogoAdPartnerSwitch: false, assetOrigin: '/', + editionId: 'UK', }} >