forked from staylor/react-helmet-async
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add the ability to use
<Helmet>
without context
This is useful for React Server Components, which do not yet support context
- Loading branch information
Showing
6 changed files
with
234 additions
and
37 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
// Jest Snapshot v1, https://goo.gl/fbAQLP | ||
|
||
exports[`Helmet Data browser renders declarative without context 1`] = `"<base target=\\"_blank\\" href=\\"http://localhost/\\" data-rh=\\"true\\">"`; | ||
exports[`Helmet Data browser renders without context 1`] = `"<base target=\\"_blank\\" href=\\"http://localhost/\\" data-rh=\\"true\\">"`; | ||
exports[`Helmet Data browser sets base tag based on deepest nested component 1`] = `"<base href=\\"http://mysite.com/public\\" data-rh=\\"true\\">"`; | ||
exports[`Helmet Data server renders declarative without context 1`] = `"<base data-rh=\\"true\\" target=\\"_blank\\" href=\\"http://localhost/\\"/>"`; | ||
exports[`Helmet Data server renders without context 1`] = `"<base data-rh=\\"true\\" target=\\"_blank\\" href=\\"http://localhost/\\"/>"`; | ||
exports[`Helmet Data server sets base tag based on deepest nested component 1`] = `"<base data-rh=\\"true\\" href=\\"http://mysite.com/public\\"/>"`; |
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,145 @@ | ||
import React, { StrictMode } from 'react'; | ||
import ReactDOM from 'react-dom'; | ||
import { Helmet } from '../../src'; | ||
import Provider from '../../src/Provider'; | ||
import HelmetData from '../../src/HelmetData'; | ||
import { HELMET_ATTRIBUTE } from '../../src/constants'; | ||
|
||
Helmet.defaultProps.defer = false; | ||
|
||
const render = node => { | ||
const mount = document.getElementById('mount'); | ||
|
||
ReactDOM.render(<StrictMode>{node}</StrictMode>, mount); | ||
}; | ||
|
||
describe('Helmet Data', () => { | ||
describe('server', () => { | ||
beforeAll(() => { | ||
Provider.canUseDOM = false; | ||
}); | ||
|
||
afterAll(() => { | ||
Provider.canUseDOM = true; | ||
}); | ||
|
||
it('renders without context', () => { | ||
const helmetData = new HelmetData({}); | ||
|
||
render( | ||
<Helmet helmetData={helmetData} base={{ target: '_blank', href: 'http://localhost/' }} /> | ||
); | ||
|
||
const head = helmetData.context.helmet; | ||
|
||
expect(head.base).toBeDefined(); | ||
expect(head.base.toString).toBeDefined(); | ||
expect(head.base.toString()).toMatchSnapshot(); | ||
}); | ||
|
||
it('renders declarative without context', () => { | ||
const helmetData = new HelmetData({}); | ||
|
||
render( | ||
<Helmet helmetData={helmetData}> | ||
<base target="_blank" href="http://localhost/" /> | ||
</Helmet> | ||
); | ||
|
||
const head = helmetData.context.helmet; | ||
|
||
expect(head.base).toBeDefined(); | ||
expect(head.base.toString).toBeDefined(); | ||
expect(head.base.toString()).toMatchSnapshot(); | ||
}); | ||
|
||
it('sets base tag based on deepest nested component', () => { | ||
const helmetData = new HelmetData({}); | ||
|
||
render( | ||
<div> | ||
<Helmet helmetData={helmetData}> | ||
<base href="http://mysite.com" /> | ||
</Helmet> | ||
<Helmet helmetData={helmetData}> | ||
<base href="http://mysite.com/public" /> | ||
</Helmet> | ||
</div> | ||
); | ||
|
||
const head = helmetData.context.helmet; | ||
|
||
expect(head.base).toBeDefined(); | ||
expect(head.base.toString).toBeDefined(); | ||
expect(head.base.toString()).toMatchSnapshot(); | ||
}); | ||
}); | ||
|
||
describe('browser', () => { | ||
it('renders without context', () => { | ||
const helmetData = new HelmetData({}); | ||
|
||
render( | ||
<Helmet helmetData={helmetData} base={{ target: '_blank', href: 'http://localhost/' }} /> | ||
); | ||
|
||
const existingTags = document.head.querySelectorAll(`base[${HELMET_ATTRIBUTE}]`); | ||
const firstTag = [].slice.call(existingTags)[0]; | ||
|
||
expect(existingTags).toBeDefined(); | ||
expect(existingTags).toHaveLength(1); | ||
|
||
expect(firstTag).toBeInstanceOf(Element); | ||
expect(firstTag.getAttribute).toBeDefined(); | ||
expect(firstTag.getAttribute('href')).toEqual('http://localhost/'); | ||
expect(firstTag.outerHTML).toMatchSnapshot(); | ||
}); | ||
|
||
it('renders declarative without context', () => { | ||
const helmetData = new HelmetData({}); | ||
|
||
render( | ||
<Helmet helmetData={helmetData}> | ||
<base target="_blank" href="http://localhost/" /> | ||
</Helmet> | ||
); | ||
|
||
const existingTags = document.head.querySelectorAll(`base[${HELMET_ATTRIBUTE}]`); | ||
const firstTag = [].slice.call(existingTags)[0]; | ||
|
||
expect(existingTags).toBeDefined(); | ||
expect(existingTags).toHaveLength(1); | ||
|
||
expect(firstTag).toBeInstanceOf(Element); | ||
expect(firstTag.getAttribute).toBeDefined(); | ||
expect(firstTag.getAttribute('href')).toEqual('http://localhost/'); | ||
expect(firstTag.outerHTML).toMatchSnapshot(); | ||
}); | ||
|
||
it('sets base tag based on deepest nested component', () => { | ||
const helmetData = new HelmetData({}); | ||
|
||
render( | ||
<div> | ||
<Helmet helmetData={helmetData}> | ||
<base href="http://mysite.com" /> | ||
</Helmet> | ||
<Helmet helmetData={helmetData}> | ||
<base href="http://mysite.com/public" /> | ||
</Helmet> | ||
</div> | ||
); | ||
|
||
const existingTags = document.head.querySelectorAll(`base[${HELMET_ATTRIBUTE}]`); | ||
const firstTag = [].slice.call(existingTags)[0]; | ||
|
||
expect(existingTags).toBeDefined(); | ||
expect(existingTags).toHaveLength(1); | ||
|
||
expect(firstTag).toBeInstanceOf(Element); | ||
expect(firstTag.getAttribute).toBeDefined(); | ||
expect(firstTag.getAttribute('href')).toEqual('http://mysite.com/public'); | ||
expect(firstTag.outerHTML).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,41 @@ | ||
import mapStateOnServer from './server'; | ||
|
||
export default class HelmetData { | ||
instances = []; | ||
|
||
value = { | ||
setHelmet: serverState => { | ||
this.context.helmet = serverState; | ||
}, | ||
helmetInstances: { | ||
get: () => this.instances, | ||
add: instance => { | ||
this.instances.push(instance); | ||
}, | ||
remove: instance => { | ||
const index = this.instances.indexOf(instance); | ||
this.instances.splice(index, 1); | ||
}, | ||
}, | ||
}; | ||
|
||
constructor(context) { | ||
this.context = context; | ||
|
||
if (!HelmetData.canUseDOM) { | ||
context.helmet = mapStateOnServer({ | ||
baseTag: [], | ||
bodyAttributes: {}, | ||
encodeSpecialCharacters: true, | ||
htmlAttributes: {}, | ||
linkTags: [], | ||
metaTags: [], | ||
noscriptTags: [], | ||
scriptTags: [], | ||
styleTags: [], | ||
title: '', | ||
titleAttributes: {}, | ||
}); | ||
} | ||
} | ||
} |
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