Created
May 8, 2020 11:09
-
-
Save maarekj/96015e983588590707390402d0db3111 to your computer and use it in GitHub Desktop.
react-helmet binding for bucklescript
This file contains hidden or 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
[@react.component] | |
let make = () => { | |
<div> | |
<Helmet title="My Title" description="My Description" /> | |
<div> {React.string("My component")} </div> | |
</div> | |
}; |
This file contains hidden or 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
type htmlAttributes; | |
type bodyAttributes; | |
type titleAttributes; | |
type base; | |
type style; | |
type script; | |
type noscript; | |
module Meta = { | |
[@bs.deriving abstract] | |
type t = { | |
[@bs.optional] | |
name: string, | |
[@bs.optional] | |
property: string, | |
[@bs.optional] | |
content: string, | |
}; | |
let name = (name, content) => { | |
t(~name, ~content, ()); | |
}; | |
let property = (property, content) => { | |
t(~property, ~content, ()); | |
}; | |
let description = content => { | |
[name("description", content), property("og:description", content)]; | |
}; | |
}; | |
module Link = { | |
[@bs.deriving abstract] | |
type t = { | |
href: string, | |
[@bs.optional] | |
hreflang: string, | |
[@bs.optional] | |
rel: string, | |
}; | |
type hreflangType = | |
| Lang(string) | |
| LangRegion(string, string) | |
| XDefault; | |
type hreflang = { | |
href: string, | |
type_: hreflangType, | |
}; | |
let hreflang = hreflang => { | |
t( | |
~href=hreflang.href, | |
~rel="alternate", | |
~hreflang= | |
switch (hreflang.type_) { | |
| Lang(lang) => lang | |
| LangRegion(lang, region) => lang ++ "-" ++ region | |
| XDefault => "x-default" | |
}, | |
(), | |
); | |
}; | |
}; | |
module HelmetJs = { | |
[@bs.module "react-helmet"] [@react.component] | |
external make: | |
( | |
~defer: bool=?, | |
~encodeSpecialCharacters: bool=?, | |
~onChangeClientState: unit => unit=?, | |
~htmlAttributes: htmlAttributes=?, | |
~bodyAttributes: bodyAttributes=?, | |
~titleAttributes: titleAttributes=?, | |
~defaultTitle: string=?, | |
~titleTemplate: string=?, | |
// some <head> tags can be passed as props | |
~base: base=?, | |
~title: string=?, | |
~meta: array(Meta.t)=?, | |
~link: array(Link.t)=?, | |
~style: array(style)=?, | |
~script: array(script)=?, | |
~noscript: array(noscript)=?, | |
~children: option(React.element)=? | |
) => | |
React.element = | |
"Helmet"; | |
}; | |
[@react.component] | |
let make = | |
( | |
~title: option(string)=?, | |
~hreflangs: list(Link.hreflang)=[], | |
~description: option(string)=?, | |
~children: option(React.element)=?, | |
) => { | |
let meta = | |
switch (description) { | |
| None => None | |
| Some(desc) => Some(Meta.description(desc)->Belt.List.toArray) | |
}; | |
let link = | |
switch (hreflangs) { | |
| [] => None | |
| hreflangs => hreflangs->Belt.List.map(Link.hreflang)->Belt.List.toArray->Some | |
}; | |
<HelmetJs ?title ?meta ?link ?children />; | |
}; | |
type helmetProp = { | |
. | |
[@bs.meth] "toComponent": unit => React.element, | |
[@bs.meth] "toString": unit => string, | |
}; | |
type helmet = { | |
. | |
"base": helmetProp, | |
"bodyAttributes": helmetProp, | |
"htmlAttributes": helmetProp, | |
"link": helmetProp, | |
"meta": helmetProp, | |
"noscript": helmetProp, | |
"script": helmetProp, | |
"style": helmetProp, | |
"title": helmetProp, | |
}; | |
[@bs.val] [@bs.module "react-helmet"] [@bs.scope "Helmet"] external renderStatic: unit => helmet = "renderStatic"; |
This file contains hidden or 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
open Belt; | |
let html = | |
(~helmet: option(Helmet.helmet)=?, ~css="", ~mainJs: string, ~appId: string, ~content="", ()) => { | |
let helmetTitle = helmet->Option.mapWithDefault("", h => h##title##toString()); | |
let helmetMeta = helmet->Option.mapWithDefault("", h => h##meta##toString()); | |
let helmetLink = helmet->Option.mapWithDefault("", h => h##link##toString()); | |
{j|<html class="no-js" lang="en"> | |
<head> | |
<meta charSet="utf-8" /> | |
<meta httpEquiv="x-ua-compatible" content="ie=edge" /> | |
<meta name="viewport" content="width=device-width, initial-scale=1" /> | |
$(helmetTitle) | |
$(helmetMeta) | |
$(helmetLink) | |
<style> | |
$(css) | |
</style> | |
</head> | |
<body> | |
<div id="$(appId)"> | |
$(content) | |
</div> | |
<script src="$(mainJs)"></script> | |
</body> | |
</html>|j}; | |
}; |
This file contains hidden or 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
let content = ReactDOMServerRe.renderToString(<ComponentUsingHelmet />); | |
let helmet = Helmet.renderStatic(); | |
let html = Html.html( | |
~helmet, | |
~css=".my-css { color: red; }", | |
~mainJs="https://myjs.com/index.js", | |
~appId="my-app-content", | |
~content, | |
() | |
); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment