-
-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #69 from meza/fix/script-hydration
fix: fix script hydration warning
- Loading branch information
Showing
17 changed files
with
217 additions
and
79 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,15 @@ | ||
import { StaticContent } from '~/components/StaticContent'; | ||
|
||
export const CookieYes = (props: { isProduction: boolean, token: string; nonce?: string; }) => { | ||
if (props.isProduction) { | ||
return <script nonce={props.nonce} id={'cookieyes'} type={'text/javascript'} src={`https://cdn-cookieyes.com/client_data/${props.token}/script.js`}/>; | ||
return ( | ||
<StaticContent | ||
element={'script'} | ||
nonce={props.nonce} | ||
id={'cookieyes'} | ||
type={'text/javascript'} | ||
src={`https://cdn-cookieyes.com/client_data/${props.token}/script.js`}/> | ||
); | ||
} | ||
return null; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import { expect, it } from 'vitest'; | ||
import { ExposeAppConfig } from './ExposeAppConfig'; | ||
|
||
describe('ExposeAppConfig', () => { | ||
const appConfig: AppConfig = { | ||
hotjarId: 'a-hotjar-id', | ||
googleAnalyticsId: 'ga-id', | ||
mixpanelToken: 'a-mixpanel-token', | ||
visitorId: 'a-visitor-id', | ||
isProduction: true, | ||
mixpanelApi: 'a-mixpanel-api', | ||
splitToken: 'a-split-token', | ||
cookieYesToken: 'a-cookieyes-token', | ||
version: '0.0.0-dev', | ||
sentryDsn: 'a-sentry-dsn' | ||
}; | ||
|
||
it('can expose the app config correctly', () => { | ||
// eslint-disable-next-line new-cap | ||
const markup = ExposeAppConfig({ appConfig: appConfig }); | ||
expect(markup).toMatchSnapshot(); | ||
}); | ||
}); | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import { StaticContent } from '~/components/StaticContent'; | ||
|
||
export const ExposeAppConfig = (props: { appConfig: AppConfig, nonce?: string }) => { | ||
return ( | ||
<StaticContent | ||
element={'script'} | ||
id={'app-config'} | ||
nonce={props.nonce} | ||
dangerouslySetInnerHTML={{ | ||
__html: `window.appConfig = ${JSON.stringify(props.appConfig)}` //typed in the ../types/global.d.ts | ||
}}/> | ||
); | ||
}; |
13 changes: 13 additions & 0 deletions
13
src/components/ExposeAppConfig/__snapshots__/ExposeAppConfig.test.tsx.snap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
// Vitest Snapshot v1 | ||
|
||
exports[`ExposeAppConfig > can expose the app config correctly 1`] = ` | ||
<StaticContent | ||
dangerouslySetInnerHTML={ | ||
{ | ||
"__html": "window.appConfig = {\\"hotjarId\\":\\"a-hotjar-id\\",\\"googleAnalyticsId\\":\\"ga-id\\",\\"mixpanelToken\\":\\"a-mixpanel-token\\",\\"visitorId\\":\\"a-visitor-id\\",\\"isProduction\\":true,\\"mixpanelApi\\":\\"a-mixpanel-api\\",\\"splitToken\\":\\"a-split-token\\",\\"cookieYesToken\\":\\"a-cookieyes-token\\",\\"version\\":\\"0.0.0-dev\\",\\"sentryDsn\\":\\"a-sentry-dsn\\"}", | ||
} | ||
} | ||
element="script" | ||
id="app-config" | ||
/> | ||
`; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from './ExposeAppConfig'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,29 +1,31 @@ | ||
import { StaticContent } from '~/components/StaticContent'; | ||
|
||
interface GoogleAnalyticsProps { | ||
googleAnalyticsId: string; | ||
visitorId: string; | ||
nonce?: string; | ||
} | ||
|
||
export const GoogleAnalytics = (props: GoogleAnalyticsProps) => { | ||
const inputProps: {nonce?: string} = {}; | ||
if (props.nonce) { | ||
inputProps.nonce = props.nonce; | ||
} | ||
return ( | ||
<> | ||
<script async nonce={props.nonce} src={`https://www.googletagmanager.com/gtag/js?id=${props.googleAnalyticsId}`}></script> | ||
<script | ||
{...inputProps} | ||
<StaticContent | ||
element={'script'} | ||
id={'gtm'} | ||
async | ||
nonce={props.nonce} | ||
src={`https://www.googletagmanager.com/gtag/js?id=${props.googleAnalyticsId}`} | ||
/> | ||
<StaticContent | ||
element={'script'} | ||
id={'google-analytics'} | ||
nonce={props.nonce} | ||
dangerouslySetInnerHTML={{ | ||
__html: `window.dataLayer = window.dataLayer || []; | ||
function gtag(){dataLayer.push(arguments);} | ||
gtag('js', new Date()); | ||
gtag('config', '${props.googleAnalyticsId}', { | ||
'user_id': '${props.visitorId}' | ||
});` | ||
}} | ||
></script> | ||
function gtag(){dataLayer.push(arguments);} | ||
gtag('js', new Date()); | ||
gtag('config', '${props.googleAnalyticsId}', { user_id: '${props.visitorId}' });` | ||
}}/> | ||
</> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import { render } from '@testing-library/react'; | ||
import { expect, it } from 'vitest'; | ||
import { StaticContent } from './StaticContent'; | ||
|
||
describe('StaticContent', () => { | ||
it('should wrap with div by default', () => { | ||
// eslint-disable-next-line new-cap | ||
const { container } = render(<StaticContent title={'some div'}>{'div content'}</StaticContent>); | ||
expect(container).toMatchSnapshot(); | ||
}); | ||
|
||
it('should wrap with given element', () => { | ||
// eslint-disable-next-line new-cap | ||
const { container } = render(<StaticContent async element={'script'}>{'script content'}</StaticContent>); | ||
expect(container).toMatchSnapshot(); | ||
}); | ||
}); | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
import { createElement, useRef, useState, useEffect } from 'react'; | ||
import type { ReactNode } from 'react'; | ||
|
||
const useStaticContent = () => { | ||
const ref = useRef<HTMLElement>(null); | ||
const [render, setRender] = useState(typeof document === 'undefined'); | ||
|
||
useEffect(() => { | ||
// check if the innerHTML is empty as client side navigation | ||
// need to render the component without server-side backup | ||
const isEmpty = ref.current?.innerHTML === ''; | ||
if (isEmpty) { | ||
setRender(true); | ||
} | ||
}, []); | ||
|
||
return [render, ref]; | ||
}; | ||
|
||
export const StaticContent = <Elem extends keyof JSX.IntrinsicElements = 'div'>( | ||
{ children, element, ...props }: { | ||
element?: Elem; | ||
children?: ReactNode; | ||
} & JSX.IntrinsicElements[Elem] | ||
) => { | ||
const elem = element || 'div'; | ||
const [render, ref] = useStaticContent(); | ||
|
||
// if we're in the server or a spa navigation, just render it | ||
if (render) { | ||
return createElement(elem, { | ||
...props, | ||
children: children | ||
}); | ||
} | ||
|
||
// avoid re-render on the client | ||
return createElement(elem, { | ||
...props, | ||
ref: ref, | ||
suppressHydrationWarning: true, | ||
dangerouslySetInnerHTML: { __html: '' } | ||
}); | ||
}; |
Oops, something went wrong.