@shopify/react-html
Version:
A component to render your React app with no static HTML
79 lines (72 loc) • 2.56 kB
JavaScript
;
Object.defineProperty(exports, '__esModule', { value: true });
var React = require('react');
var reactHydrate = require('@shopify/react-hydrate');
var hooks = require('../hooks.js');
var utilities = require('../utilities.js');
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
function HtmlUpdater() {
const queuedUpdate = React__default["default"].useRef(null);
hooks.useClientDomEffect(manager => {
return manager.subscribe(state => {
if (queuedUpdate.current) {
cancelAnimationFrame(queuedUpdate.current);
}
queuedUpdate.current = requestAnimationFrame(() => {
updateOnClient(state);
});
});
});
return /*#__PURE__*/React__default["default"].createElement(reactHydrate.HydrationTracker, null);
}
function updateOnClient(state) {
const {
title,
metas,
links,
inlineStyles
} = state;
let titleElement = document.querySelector('title');
if (title == null) {
if (titleElement) {
titleElement.remove();
}
} else {
if (titleElement == null) {
titleElement = document.createElement('title');
document.head.appendChild(titleElement);
}
titleElement.setAttribute(utilities.MANAGED_ATTRIBUTE, 'true');
titleElement.textContent = title;
}
const fragment = document.createDocumentFragment();
updateElement('meta', utilities.removeDuplicate(metas), fragment);
updateElement('link', links, fragment);
updateElement('style', inlineStyles, fragment);
document.head.appendChild(fragment);
}
function updateElement(selector, items, fragment) {
const oldElements = Array.from(document.head.querySelectorAll(`${selector}[${utilities.MANAGED_ATTRIBUTE}]`));
for (const item of items) {
const element = document.createElement(selector);
element.setAttribute(utilities.MANAGED_ATTRIBUTE, 'true');
for (const [attribute, value] of Object.entries(item)) {
if (attribute === 'children') {
element.textContent = value;
} else {
element.setAttribute(attribute, value);
}
}
const matchingOldElementIndex = oldElements.findIndex(oldElement => oldElement.isEqualNode(element));
if (matchingOldElementIndex >= 0) {
oldElements.splice(matchingOldElementIndex, 1);
} else {
fragment.appendChild(element);
}
}
for (const oldElement of oldElements) {
oldElement.remove();
}
}
exports.HtmlUpdater = HtmlUpdater;