I have the need to add <script type="application/ld+json"> tags into my head, so I implemented a <Script> tag with a doc comment saying that this should not be used to inject code.
I also needed a way, in my gatsby based project, to add arbitrary tags to the head from a headless cms. Neither react-helmet or react-head support this use case.
The solution I came up with was based on ideas from https://github.com/remarkablemark/html-react-parser however using html-react-parser added 7.6k to the bundle. However the idea was sound, so I added the <Static> tag to this library based on their ideas. It is a cut down version of html-react-parser's domToReact that is very minimal. It also doesn't provide runtime parsing of the html string - this is to be done before hand. Hence the tag name Static. It only adds ~ 400 bytes to the gzippped bundle.
How do you use it ?
First of all you need to pre-parse the head html string from your headless cms.
for example (using the parseHtmlHeadToStatic function below)
let headJson = parseHtmlHeadToStatic(`<link rel="canonical" href="https://www.drivenow.com.au">`)
Then you use it as follows :
<Static json={headJson}/>
One example of code to parse the html into the correct json structure is as follows. This code can be added to react-head if someone knows how to do that in a tree-shaking safe way. Otherwise it can be added as a separate npm project.
import { StaticNode } from "react-head"
import htmlDomParser from "html-dom-parser"
export function parseHtmlHeadToStatic( head: string ) : StaticNode[] {
if (!head) return null
let nodes = htmlDomParser(head)
nodes = filterTopLevelTextNodes(nodes)
removeCyclicAndExtraProps(nodes)
nodes = JSON.parse(JSON.stringify(nodes)) // convert to JSON
return nodes as StaticNode[]
}
export function filterTopLevelTextNodes(nodes) {
return nodes.filter(node=>{
return node.type != 'text'
})
}
export function removeCyclicAndExtraProps(nodes) {
nodes.forEach(node=>{
delete node.parent
delete node.next
delete node.prev
delete node.endIndex
delete node.startIndex
if (node.children) {
if (node.children.length == 0) {
delete node.children
}
else {
removeCyclicAndExtraProps(node.children)
}
}
})
}
I have the need to add
<script type="application/ld+json">
tags into my head, so I implemented a<Script>
tag with a doc comment saying that this should not be used to inject code.I also needed a way, in my gatsby based project, to add arbitrary tags to the head from a headless cms. Neither
react-helmet
orreact-head
support this use case.The solution I came up with was based on ideas from https://github.com/remarkablemark/html-react-parser however using
html-react-parser
added 7.6k to the bundle. However the idea was sound, so I added the<Static>
tag to this library based on their ideas. It is a cut down version ofhtml-react-parser
'sdomToReact
that is very minimal. It also doesn't provide runtime parsing of the html string - this is to be done before hand. Hence the tag name Static. It only adds ~ 400 bytes to the gzippped bundle.How do you use it ?
First of all you need to pre-parse the head html string from your headless cms.
example
<link rel="canonical" href="https://www.drivenow.com.au">
needs to become
for example (using the parseHtmlHeadToStatic function below)
Then you use it as follows :
One example of code to parse the html into the correct json structure is as follows. This code can be added to react-head if someone knows how to do that in a tree-shaking safe way. Otherwise it can be added as a separate npm project.