@shopify/react-html
Version:
A component to render your React app with no static HTML
138 lines (134 loc) • 4.74 kB
JavaScript
import React from 'react';
import { renderToString } from 'react-dom/server';
import { HydrationContext } from '@shopify/react-hydrate';
import { HtmlContext } from '../../context.mjs';
import { MANAGED_ATTRIBUTE, removeDuplicate } from '../../utilities.mjs';
import { Script } from './Script.mjs';
import Serialize from './Serialize.mjs';
import { Stylesheet } from './Stylesheet.mjs';
import { InlineStyle } from './InlineStyle.mjs';
function Html({
manager,
hydrationManager,
children = '',
locale = 'en',
blockingScripts = [],
scripts = [],
styles = [],
inlineStyles = [],
preloadAssets = [],
headMarkup = null,
bodyMarkup = null
}) {
const markup = typeof children === 'string' ? children : render(children, {
htmlManager: manager,
hydrationManager
});
const extracted = manager && manager.extract();
const serializationMarkup = extracted ? extracted.serializations.map(({
id,
data
}) => /*#__PURE__*/React.createElement(Serialize, {
key: id,
id: id,
data: data
})) : null;
const managedProps = {
[MANAGED_ATTRIBUTE]: true
};
const titleMarkup = extracted && extracted.title ? /*#__PURE__*/React.createElement("title", managedProps, extracted.title) : null;
const metaMarkup = extracted ? removeDuplicate(extracted.metas).map((metaProps, index) =>
/*#__PURE__*/
// This is never re-rendered, since it is the initial HTML document,
// so index keys are acceptable.
// eslint-disable-next-line react/no-array-index-key
React.createElement("meta", Object.assign({
key: index
}, managedProps, metaProps))) : null;
const linkMarkup = extracted ? extracted.links.map((linkProps, index) =>
/*#__PURE__*/
// This is never re-rendered, since it is the initial HTML document,
// so index keys are acceptable.
// eslint-disable-next-line react/no-array-index-key
React.createElement("link", Object.assign({
key: index
}, managedProps, linkProps))) : null;
const stylesheetMarkup = styles.map(style => {
return /*#__PURE__*/React.createElement(Stylesheet, {
key: style.path,
href: style.path,
integrity: style.integrity,
crossOrigin: "anonymous"
});
});
const inlineStylesMarkup = inlineStyles.map(inlineStyle => {
return /*#__PURE__*/React.createElement(InlineStyle, {
key: inlineStyle.content
}, inlineStyle.content);
});
const blockingScriptsMarkup = blockingScripts.map(script => {
return /*#__PURE__*/React.createElement(Script, {
key: script.path,
src: script.path,
integrity: script.integrity,
type: script.type,
crossOrigin: "anonymous"
});
});
const deferredScriptsMarkup = scripts.map(script => {
return /*#__PURE__*/React.createElement(Script, {
key: script.path,
src: script.path,
integrity: script.integrity,
type: script.type,
crossOrigin: "anonymous",
defer: true
});
});
const preloadAssetsMarkup = preloadAssets.map(asset => /*#__PURE__*/React.createElement("link", {
key: asset.path,
rel: "prefetch",
href: asset.path
}));
const htmlAttributes = extracted ? extracted.htmlAttributes : {};
const bodyAttributes = extracted ? extracted.bodyAttributes : {};
// eslint-disable-next-line no-process-env
if (process.env.NODE_ENV === 'development') {
if (bodyAttributes.style == null) {
bodyAttributes.style = {
visibility: 'hidden'
};
} else {
bodyAttributes.style.visibility = 'hidden';
}
}
return /*#__PURE__*/React.createElement("html", Object.assign({
lang: locale
}, htmlAttributes), /*#__PURE__*/React.createElement("head", null, titleMarkup, /*#__PURE__*/React.createElement("meta", {
charSet: "utf-8"
}), /*#__PURE__*/React.createElement("meta", {
httpEquiv: "X-UA-Compatible",
content: "IE=edge"
}), /*#__PURE__*/React.createElement("meta", {
name: "referrer",
content: "never"
}), metaMarkup, linkMarkup, stylesheetMarkup, inlineStylesMarkup, headMarkup, blockingScriptsMarkup, deferredScriptsMarkup, preloadAssetsMarkup), /*#__PURE__*/React.createElement("body", bodyAttributes, /*#__PURE__*/React.createElement("div", {
id: "app",
dangerouslySetInnerHTML: {
__html: markup
}
}), bodyMarkup, serializationMarkup));
}
function render(app, {
htmlManager,
hydrationManager
}) {
const hydrationWrapped = hydrationManager ? /*#__PURE__*/React.createElement(HydrationContext.Provider, {
value: hydrationManager
}, app) : app;
const content = htmlManager == null ? app : /*#__PURE__*/React.createElement(HtmlContext.Provider, {
value: htmlManager
}, hydrationWrapped);
return renderToString(content);
}
export { Html as default };