next/head deduping process can duplicate and overwrite dynamically inserted header tags
See original GitHub issueWhat example does this report relate to?
Next/Head
What version of Next.js are you using?
^11.1.0
What version of Node.js are you using?
^15.6.1
What browser are you using?
Chrome
What operating system are you using?
Windows
How are you deploying your application?
AWS EC2
Describe the Bug
If you have integrations which dynamically add elements to the html document head, if the item added falls into the “old tags” range for the Next/Head implementation, any tags added dynamically will be duplicated because they no longer fall within the “old tags” range. Additionally, if you then have a re-render which causes the Next/Head to run again, the dynamically inserted elements from the integration will then be deleted.
The issue happens here (credit @tb-campbell) https://github.com/vercel/next.js/blob/f52211bad39c2a29a7caba40bfeb89b600524b41/packages/next/client/head-manager.ts#L73
Expected Behavior
The Next/Head component should manage the state of old and new tags internally and not count backward from an element inside the document head. Any elements that dynamically get inserted into the document head should be unaffected by the dynamic insertion by the Next/Head component, and the Next/Head component should manage the new and old Head tags without relying on the actual DOM.
To Reproduce
We are using google-tag-manager which has some 3rd party integrations which insert their scripts into the head of the document. This would also be applicable for a lot of ad frameworks and trackers as well. To recreate it without these, you could try dynamically injecting meta/link/script/etc tags into the head, until one overlaps in position with the tags set by the next head.
Below would be an example of a Head component usage for a page, where some of the fields are generated client side during runtime. If a script were to inject into the document head at any line where the tags below exist, they would first be duplicated, and on subsequent render be deleted.
<Head>
<title key="title">{titleText}</title>
<link key="canonical" rel="canonical" href={canonicalUrl} />
<meta key="description" name="description" content={descriptionText} />
<meta key="og:title" property="og:title" content={titleText} />
<meta key="og:description" property="og:description" content={descriptionText} />
<meta key="og:url" property="og:type" content="website" />
<meta key="og:type" property="og:url" content={canonicalUrl} />
<meta key="og:details" property="og:details" content={details} />
<meta
key="place:location:latitude"
property="place:location:latitude"
content={searchLocation?.position?.lat?.toString()}
/>
<meta
key="place:location:longitude"
property="place:location:longitude"
content={searchLocation?.position?.lng?.toString()}
/>
<script
key="breadcrumb-schema"
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: sanitize(JSON.stringify(breadcrumbs)) }}
/>
</Head>
Issue Analytics
- State:
- Created 2 years ago
- Reactions:10
- Comments:13 (1 by maintainers)
Top GitHub Comments
In my case, viewport meta tag is duplicated. I have custom
_document.tsx
and_app.tsx
. Viewport tag alongside with all other Head tags is placed inside_app.tsx
._document.tsx
only containsHead
component with Google font imports.Here’s a minimal example.