Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(gatsby): Gatsby Head API #35980

Merged
merged 69 commits into from
Jul 14, 2022
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
69 commits
Select commit Hold shift + click to select a range
194a690
initial work
marvinjude Jun 8, 2022
5beb48b
add latest
marvinjude Jun 8, 2022
bb56387
implement in page renderer
marvinjude Jun 16, 2022
40549d7
progress
marvinjude Jun 16, 2022
2597e9f
make static query work when used in export
marvinjude Jun 17, 2022
361ad85
cleanup
marvinjude Jun 21, 2022
69b39cc
don't warn for 'head' export
marvinjude Jun 21, 2022
36d296e
cleanup & append head nodes to head at once
marvinjude Jun 21, 2022
5357b5c
add warnings
marvinjude Jun 21, 2022
6b7bb4f
update warning
marvinjude Jun 22, 2022
e03a316
remove use less function
marvinjude Jun 22, 2022
923a08e
add TS Types
marvinjude Jun 23, 2022
eb33292
Merge branch 'master' into poc/metadata-management
marvinjude Jun 23, 2022
f48beff
test(gatsby): Metadata management e2e tests (#35979)
tyhopp Jun 23, 2022
f5d5288
fix test
marvinjude Jun 24, 2022
0751f0d
fix hydration issue
marvinjude Jun 24, 2022
3d7e8af
use react to render into head instead of parsing and appending result…
marvinjude Jun 26, 2022
cbc4324
fix test
marvinjude Jun 26, 2022
70dd9a9
don't invalid head element for HTML
marvinjude Jun 26, 2022
a8c2a9b
remove warning test in prod
marvinjude Jun 27, 2022
e3f2571
do react 18 checks for create root/ render
marvinjude Jun 27, 2022
940f02e
remove all props page test
marvinjude Jun 27, 2022
c7e80d3
wrap head element with server location and props provider
marvinjude Jun 27, 2022
c69941a
Merge branch 'master' into feat/metadata-management
marvinjude Jun 28, 2022
167fb4e
Fix borked yarn.lock
tyhopp Jun 28, 2022
c2acf0a
Update dev-loader test snapshot
tyhopp Jun 28, 2022
5efa140
Update packages/gatsby/cache-dir/dev-loader.js
marvinjude Jun 28, 2022
544e1d5
Update packages/gatsby/cache-dir/loader.js
marvinjude Jun 28, 2022
8dd4fa8
Update packages/gatsby/cache-dir/page-renderer.js
marvinjude Jun 28, 2022
42d72d6
Update packages/gatsby/cache-dir/static-entry.js
marvinjude Jun 28, 2022
4bab3eb
create shared function for render and hydrate
marvinjude Jun 28, 2022
56da964
Fix lint error
tyhopp Jun 29, 2022
f5969a6
Remove unused functions
tyhopp Jun 29, 2022
7169fa0
Ensure params are passed with props in page renderer
tyhopp Jun 29, 2022
6370a5f
Fix eslint test assertion
tyhopp Jun 29, 2022
2fe95f2
remove unnecessary spread operator
marvinjude Jun 29, 2022
f218a32
remove no-op setAttribute addition
marvinjude Jun 29, 2022
a2506d6
feat(head-function-export): Correct props (#36008)
LekoArts Jun 30, 2022
ee3c07a
test(head-function-export): Ensure head elements in SSR'ed HTML (#36006)
tyhopp Jun 30, 2022
664133d
test(head-function-export): More e2e tests (#36014)
tyhopp Jun 30, 2022
8fac6b6
create SSR and browser handler for head export
marvinjude Jul 4, 2022
4a50f2f
fix import and condition
marvinjude Jul 4, 2022
e1ca969
add head handler for DEV SSR
marvinjude Jul 4, 2022
1f80113
test(head-function-export): Test in DEV_SSR mode (#36007)
tyhopp Jul 4, 2022
b9c565e
feat(head-function-export): Hot update for Head export (#36060)
marvinjude Jul 12, 2022
a223b6d
Merge branch 'master' into feat/metadata-management
marvinjude Jul 12, 2022
9635085
fix(head-function-export): Make tsx pages work (#36114)
tyhopp Jul 13, 2022
4bfb485
Merge branch 'master' into feat/metadata-management
marvinjude Jul 13, 2022
fc53d38
Fix unit tests
tyhopp Jul 13, 2022
c01ffc2
cleaup tags on navigation
marvinjude Jul 13, 2022
a1bd8ec
remove test images
marvinjude Jul 13, 2022
ebd9ca4
Update e2e-tests/development-runtime/cypress/integration/head-functio…
marvinjude Jul 13, 2022
def1743
Update packages/gatsby/cache-dir/fast-refresh-overlay/components/runt…
marvinjude Jul 13, 2022
0836cdf
fixes from dot com testing
marvinjude Jul 13, 2022
e55541a
review update
marvinjude Jul 13, 2022
2117f0a
review update
marvinjude Jul 13, 2022
0732354
remove extra formatting
marvinjude Jul 13, 2022
ba1e5e8
review update
marvinjude Jul 13, 2022
0cb42a2
review update
marvinjude Jul 13, 2022
fa454d0
review updates
marvinjude Jul 13, 2022
9a6790d
remove all export query param
marvinjude Jul 13, 2022
8ccb9c5
fix duplicate tags added because we call onHeadRendered twice
marvinjude Jul 13, 2022
8486a93
.waitForRouteChange() everywhere
marvinjude Jul 13, 2022
4451b04
add additional e2e tests
marvinjude Jul 13, 2022
2a668ec
Fix dsg, ssr tests
tyhopp Jul 14, 2022
b649b2d
add Head type shorthand
LekoArts Jul 14, 2022
6f79729
Fix React 18 hydration error due to stringified all props
tyhopp Jul 14, 2022
4722284
update type name
LekoArts Jul 14, 2022
9df3cc2
warn once for same message
marvinjude Jul 14, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { page } from "../../../shared-data/head-function-export.js"

it.only(`head function export should get all page properties`, () => {
cy.visit(page.allProps)
cy.getTestElement(`location.origin`)
.invoke(`attr`, `content`)
.should(`equal`, `http://localhost:8000`)
cy.getTestElement(`pageContext`)
.invoke(`attr`, `content`)
.should(`not.be.undefined`)
cy.getTestElement(`pageResources.page.componentChunkName`)
.invoke(`attr`, `content`)
.should(`equal`, `component---src-pages-head-function-export-all-props-js`)
cy.getTestElement(`params`)
.invoke(`attr`, `content`)
.should(`not.be.undefined`)
cy.getTestElement(`path`)
.invoke(`attr`, `content`)
.should(`equal`, `/head-function-export/all-props/`)
cy.getTestElement(`uri`)
.invoke(`attr`, `content`)
.should(`equal`, `/head-function-export/all-props`)
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { page, data } from "../../../shared-data/head-function-export.js"

describe(`head function export html insertion`, () => {
it(`should work with static data`, () => {
cy.visit(page.basic)
marvinjude marked this conversation as resolved.
Show resolved Hide resolved
cy.getTestElement(`base`)
.invoke(`attr`, `href`)
.should(`equal`, data.static.base)
cy.getTestElement(`title`).should(`have.text`, data.static.title)
cy.getTestElement(`meta`)
.invoke(`attr`, `content`)
.should(`equal`, data.static.meta)
cy.getTestElement(`noscript`).should(`have.text`, data.static.noscript)
cy.getTestElement(`style`).should(`contain`, data.static.style)
cy.getTestElement(`link`)
.invoke(`attr`, `href`)
.should(`equal`, data.static.link)
})

it(`should work with data from a page query`, () => {
cy.visit(page.pageQuery)
cy.getTestElement(`base`)
.invoke(`attr`, `href`)
.should(`equal`, data.queried.base)
cy.getTestElement(`title`).should(`have.text`, data.queried.title)
cy.getTestElement(`meta`)
.invoke(`attr`, `content`)
.should(`equal`, data.queried.meta)
cy.getTestElement(`noscript`).should(`have.text`, data.queried.noscript)
cy.getTestElement(`style`).should(`contain`, data.queried.style)
cy.getTestElement(`link`)
.invoke(`attr`, `href`)
.should(`equal`, data.queried.link)
})

it(`should work when a head function with static data is re-exported from the page`, () => {
cy.visit(page.reExport)
cy.getTestElement(`base`)
.invoke(`attr`, `href`)
.should(`equal`, data.static.base)
cy.getTestElement(`title`).should(`have.text`, data.static.title)
cy.getTestElement(`meta`)
.invoke(`attr`, `content`)
.should(`equal`, data.static.meta)
cy.getTestElement(`noscript`).should(`have.text`, data.static.noscript)
cy.getTestElement(`style`).should(`contain`, data.static.style)
cy.getTestElement(`link`)
.invoke(`attr`, `href`)
.should(`equal`, data.static.link)
})

it(`should work when an imported head component with queried data is used`, () => {
cy.visit(page.staticQuery)
cy.getTestElement(`base`)
.invoke(`attr`, `href`)
.should(`equal`, data.queried.base)
cy.getTestElement(`title`).should(`have.text`, data.queried.title)
cy.getTestElement(`meta`)
.invoke(`attr`, `content`)
.should(`equal`, data.queried.meta)
cy.getTestElement(`noscript`).should(`have.text`, data.queried.noscript)
cy.getTestElement(`style`).should(`contain`, data.queried.style)
cy.getTestElement(`link`)
.invoke(`attr`, `href`)
.should(`equal`, data.queried.link)
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { page, data } from "../../../shared-data/head-function-export.js"

// No need to test SSR navigation (anchor tags) because it's effectively covered in the html insertion tests

it(`head function export behavior during CSR navigation (Gatsby Link)`, () => {
// Initial load
cy.visit(page.basic)

// Validate data from initial load
cy.getTestElement(`base`)
.invoke(`attr`, `href`)
.should(`equal`, data.static.base)
cy.getTestElement(`title`).should(`have.text`, data.static.title)
cy.getTestElement(`meta`)
.invoke(`attr`, `content`)
.should(`equal`, data.static.meta)
cy.getTestElement(`noscript`).should(`have.text`, data.static.noscript)
cy.getTestElement(`style`).should(`contain`, data.static.style)
cy.getTestElement(`link`)
.invoke(`attr`, `href`)
.should(`equal`, data.static.link)

// Navigate to a different page via Gatsby Link
cy.getTestElement(`gatsby-link`).click()

// Validate data on navigated-to page
cy.getTestElement(`base`)
.invoke(`attr`, `href`)
.should(`equal`, data.queried.base)
cy.getTestElement(`title`).should(`have.text`, data.queried.title)
cy.getTestElement(`meta`)
.invoke(`attr`, `content`)
.should(`equal`, data.queried.meta)
cy.getTestElement(`noscript`).should(`have.text`, data.queried.noscript)
cy.getTestElement(`style`).should(`contain`, data.queried.style)
cy.getTestElement(`link`)
.invoke(`attr`, `href`)
.should(`equal`, data.queried.link)

// Navigate back to original page via Gatsby Link
cy.getTestElement(`gatsby-link`).click()

// Validate data is same as initial load
cy.getTestElement(`base`)
.invoke(`attr`, `href`)
.should(`equal`, data.static.base)
cy.getTestElement(`title`).should(`have.text`, data.static.title)
cy.getTestElement(`meta`)
.invoke(`attr`, `content`)
.should(`equal`, data.static.meta)
cy.getTestElement(`noscript`).should(`have.text`, data.static.noscript)
cy.getTestElement(`style`).should(`contain`, data.static.style)
cy.getTestElement(`link`)
.invoke(`attr`, `href`)
.should(`equal`, data.static.link)
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { VALID_NODE_NAMES } from "gatsby/cache-dir/head/constants"
import { page } from "../../../shared-data/head-function-export.js"

describe(`head function export should warn`, () => {
beforeEach(() => {
cy.visit(page.warnings, {
onBeforeLoad(win) {
cy.stub(win.console, `warn`).as(`consoleWarn`)
},
})
})

it(`for elements that belong in the body`, () => {
cy.get(`@consoleWarn`).should(
`be.calledWith`,
`<h1> is not a valid head element. Please use one of the following: ${VALID_NODE_NAMES.join(
`, `
)}`
)
})

it(`for scripts that could use the script component`, () => {
cy.get(`@consoleWarn`).should(
`be.calledWith`,
`Do not add scripts here. Please use the <Script> component in your page template instead. For more info see: https://www.gatsbyjs.com/docs/reference/built-in-components/gatsby-script/`
)
})
})
6 changes: 6 additions & 0 deletions e2e-tests/development-runtime/gatsby-config.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
const {
data: headFunctionExportData,
} = require(`./shared-data/head-function-export.js`)

/**
* @type {import('gatsby').GatsbyConfig}
*/
Expand All @@ -8,6 +12,8 @@ module.exports = {
social: {
twitter: `kylemathews`,
},
// Separate to avoid needing to change other tests that rely on site metadata
headFunctionExport: headFunctionExportData.queried,
},
graphqlTypegen: true,
flags: {
Expand Down
31 changes: 31 additions & 0 deletions e2e-tests/development-runtime/shared-data/head-function-export.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
const path = `/head-function-export`

const page = {
basic: `${path}/basic/`,
pageQuery: `${path}/page-query/`,
reExport: `${path}/re-exported-function/`,
staticQuery: `${path}/static-query-component/`,
warnings: `${path}/warnings/`,
allProps: `${path}/all-props/`,
}

const data = {
static: {
base: `http://localhost:8000`,
title: `Ella Fitzgerald's Page`,
meta: `Ella Fitzgerald`,
noscript: `You take romance - I will take Jell-O!`,
style: `rebeccapurple`,
link: `/used-by-head-function-export-basic.css`,
},
queried: {
base: `http://localhost:8000`,
title: `Nat King Cole's Page`,
meta: `Nat King Cole`,
noscript: `There is just one thing I cannot figure out. My income tax!`,
style: `blue`,
link: `/used-by-head-function-export-query.css`,
},
}

module.exports = { page, data }
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import * as React from "react"
import { useStaticQuery, graphql } from "gatsby"
import { data } from "../../shared-data/head-function-export.js"

function HeadComponent({ children }) {
const data = useStaticQuery(graphql`
query SiteMetaDataStaticQuery {
site {
siteMetadata {
headFunctionExport {
base
title
meta
noscript
style
link
}
}
}
}
`)

const { base, title, meta, noscript, style, link } =
data?.site?.siteMetadata?.headFunctionExport || {}

return (
<>
<base data-testid="base" href={base} />
<title data-testid="title">{title}</title>
<meta data-testid="meta" name="author" content={meta} />
<noscript data-testid="noscript">{noscript}</noscript>
<style data-testid="style">
{`
h1 {
color: ${style};
}
`}
</style>
<link data-testid="link" href={link} rel="stylesheet" />
{children}
</>
)
}

function head() {
const { base, title, meta, noscript, style, link } = data.static

return (
<>
<base data-testid="base" href={base} />
<title data-testid="title">{title}</title>
<meta data-testid="meta" name="author" content={meta} />
<noscript data-testid="noscript">{noscript}</noscript>
<style data-testid="style">
{`
h1 {
color: ${style};
}
`}
</style>
<link data-testid="link" href={link} rel="stylesheet" />
</>
)
}

export { head }
export default HeadComponent
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import * as React from "react"

export default function HeadFunctionExportAllProps(props) {
return (
<>
<h1>
I test usage for the head function export to make sure all props are
received
</h1>
<pre>{JSON.stringify(props, null, 2)}</pre>
</>
)
}

export function head(props) {
const { location, pageContext, pageResources, params, path, uri } =
props || {}

return (
<>
<meta
data-testid="location.origin"
name="location.origin"
content={location?.origin}
/>
<meta
data-testid="pageContext"
name="pageContext"
content={pageContext}
/>
<meta
data-testid="pageResources.page.componentChunkName"
name="pageResources.page.componentChunkName"
content={pageResources?.page?.componentChunkName}
/>
<meta data-testid="params" name="params" content={params} />
<meta data-testid="path" name="path" content={path} />
<meta data-testid="uri" name="uri" content={uri} />
</>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import * as React from "react"
import { Link } from "gatsby"
import { data } from "../../../shared-data/head-function-export"

export default function HeadFunctionExportBasic() {
return (
<>
<h1>I test basic usage for the head function export</h1>
<p>Some other words</p>
<Link data-testid="gatsby-link" to="/head-function-export/page-query">
Navigate to page-query via Gatsby Link
</Link>
</>
)
}

export function head() {
const { base, title, meta, noscript, style, link } = data.static

return (
<>
<base data-testid="base" href={base} />
<title data-testid="title">{title}</title>
<meta data-testid="meta" name="author" content={meta} />
<noscript data-testid="noscript">{noscript}</noscript>
<style data-testid="style">
{`
h1 {
color: ${style};
}
`}
</style>
<link data-testid="link" href={link} rel="stylesheet" />
</>
)
}