Skip to content

Commit 6f0d46b

Browse files
gatsbybotpieh
andauthored
feat(gatsby): allow deduplicating head elements on id (#36138) (#36159)
* feat: deduplicate head elements on id attrbibute in browser * feat: deduplicate head elements on id attrbibute in html gen * page with head deduplication * add test * update comments to match current code * Update e2e-tests/development-runtime/cypress/integration/head-function-export/deduplication.js Co-authored-by: Jude Agboola <[email protected]> * Update e2e-tests/development-runtime/cypress/integration/head-function-export/deduplication.js * add test case to e2e-production * add test case to head integration tests Co-authored-by: Jude Agboola <[email protected]> (cherry picked from commit b08ef18) Co-authored-by: Michal Piechowiak <[email protected]>
1 parent 62d2a49 commit 6f0d46b

File tree

12 files changed

+193
-3
lines changed

12 files changed

+193
-3
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import headFunctionExportSharedData from "../../../shared-data/head-function-export.js"
2+
3+
it(`Deduplicates multiple tags with same id`, () => {
4+
cy.visit(headFunctionExportSharedData.page.deduplication).waitForRouteChange()
5+
6+
// deduplication link has id and should be deduplicated
7+
cy.get(`link[rel=deduplication]`).should("have.length", 1)
8+
// last deduplication link should win
9+
cy.get(`link[rel=deduplication]`).should("have.attr", "href", "/bar")
10+
// we should preserve id
11+
cy.get(`link[rel=deduplication]`).should(
12+
"have.attr",
13+
"id",
14+
"deduplication-test"
15+
)
16+
17+
// alternate links are not using id, so should have multiple instances
18+
cy.get(`link[rel=alternate]`).should("have.length", 2)
19+
})

e2e-tests/development-runtime/shared-data/head-function-export.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ const page = {
1111
ssr: `${path}/ssr/`,
1212
invalidElements: `${path}/invalid-elements/`,
1313
fsRouteApi: `${path}/fs-route-api/`,
14+
deduplication: `${path}/deduplication/`,
1415
}
1516

1617
const data = {
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import * as React from "react"
2+
3+
export default function HeadFunctionDeduplication() {
4+
return (
5+
<>
6+
<h1>
7+
I deduplicated Head elements by their <code>id</code>
8+
</h1>
9+
</>
10+
)
11+
}
12+
13+
function SEO({ children }) {
14+
return (
15+
<>
16+
<link rel="deduplication" id="deduplication-test" href="/foo" />
17+
<link
18+
rel="alternate"
19+
type="application/atom+xml"
20+
title="RSS Feed"
21+
href="/blog/news/atom"
22+
/>
23+
{children}
24+
</>
25+
)
26+
}
27+
28+
export function Head() {
29+
return (
30+
<SEO>
31+
<link rel="deduplication" id="deduplication-test" href="/bar" />
32+
<link rel="alternate" hrefLang="de-DE" href="/de/" />
33+
</SEO>
34+
)
35+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import headFunctionExportSharedData from "../../../shared-data/head-function-export.js"
2+
3+
it(`Deduplicates multiple tags with same id`, () => {
4+
cy.visit(headFunctionExportSharedData.page.deduplication).waitForRouteChange()
5+
6+
// deduplication link has id and should be deduplicated
7+
cy.get(`link[rel=deduplication]`).should("have.length", 1)
8+
// last deduplication link should win
9+
cy.get(`link[rel=deduplication]`).should("have.attr", "href", "/bar")
10+
// we should preserve id
11+
cy.get(`link[rel=deduplication]`).should(
12+
"have.attr",
13+
"id",
14+
"deduplication-test"
15+
)
16+
17+
// alternate links are not using id, so should have multiple instances
18+
cy.get(`link[rel=alternate]`).should("have.length", 2)
19+
})

e2e-tests/production-runtime/shared-data/head-function-export.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ const page = {
1111
ssr: `${path}/ssr/`,
1212
invalidElements: `${path}/invalid-elements/`,
1313
fsRouteApi: `${path}/fs-route-api/`,
14+
deduplication: `${path}/deduplication/`,
1415
}
1516

1617
const data = {
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import * as React from "react"
2+
3+
export default function HeadFunctionDeduplication() {
4+
return (
5+
<>
6+
<h1>
7+
I deduplicated Head elements by their <code>id</code>
8+
</h1>
9+
</>
10+
)
11+
}
12+
13+
function SEO({ children }) {
14+
return (
15+
<>
16+
<link rel="deduplication" id="deduplication-test" href="/foo" />
17+
<link
18+
rel="alternate"
19+
type="application/atom+xml"
20+
title="RSS Feed"
21+
href="/blog/news/atom"
22+
/>
23+
{children}
24+
</>
25+
)
26+
}
27+
28+
export function Head() {
29+
return (
30+
<SEO>
31+
<link rel="deduplication" id="deduplication-test" href="/bar" />
32+
<link rel="alternate" hrefLang="de-DE" href="/de/" />
33+
</SEO>
34+
)
35+
}

integration-tests/head-function-export/__tests__/ssr-html-output.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,4 +76,23 @@ describe(`Head function export SSR'ed HTML output`, () => {
7676
expect(style.text).toContain(data.queried.style)
7777
expect(link.attributes.href).toEqual(data.queried.link)
7878
})
79+
80+
it(`deduplicates multiple tags with same id`, () => {
81+
const html = readFileSync(`${publicDir}${page.deduplication}/index.html`)
82+
const dom = parse(html)
83+
84+
// deduplication link has id and should be deduplicated
85+
expect(dom.querySelectorAll(`link[rel=deduplication]`)?.length).toEqual(1)
86+
// last deduplication link should win
87+
expect(
88+
dom.querySelector(`link[rel=deduplication]`)?.attributes?.href
89+
).toEqual("/bar")
90+
// we should preserve id
91+
expect(
92+
dom.querySelector(`link[rel=deduplication]`)?.attributes?.id
93+
).toEqual("deduplication-test")
94+
95+
// alternate links are not using id, so should have multiple instances
96+
expect(dom.querySelectorAll(`link[rel=alternate]`)?.length).toEqual(2)
97+
})
7998
})

integration-tests/head-function-export/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
"babel-preset-gatsby-package": "^2.4.0",
2020
"fs-extra": "^10.0.0",
2121
"jest": "^27.2.1",
22+
"node-html-parser": "^5.3.3",
2223
"npm-run-all": "4.1.5"
2324
},
2425
"dependencies": {

integration-tests/head-function-export/shared-data/head-function-export.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ const page = {
77
staticQuery: `${path}/static-query-component/`,
88
warnings: `${path}/warnings/`,
99
allProps: `${path}/all-props/`,
10+
deduplication: `${path}/deduplication/`,
1011
}
1112

1213
const data = {
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import * as React from "react"
2+
3+
export default function HeadFunctionDeduplication() {
4+
return (
5+
<>
6+
<h1>
7+
I deduplicated Head elements by their <code>id</code>
8+
</h1>
9+
</>
10+
)
11+
}
12+
13+
function SEO({ children }) {
14+
return (
15+
<>
16+
<link rel="deduplication" id="deduplication-test" href="/foo" />
17+
<link
18+
rel="alternate"
19+
type="application/atom+xml"
20+
title="RSS Feed"
21+
href="/blog/news/atom"
22+
/>
23+
{children}
24+
</>
25+
)
26+
}
27+
28+
export function Head() {
29+
return (
30+
<SEO>
31+
<link rel="deduplication" id="deduplication-test" href="/bar" />
32+
<link rel="alternate" hrefLang="de-DE" href="/de/" />
33+
</SEO>
34+
)
35+
}

0 commit comments

Comments
 (0)