gatsby
Version:
Blazing fast modern site generator for React
135 lines (107 loc) • 5.6 kB
JavaScript
;
exports.__esModule = true;
exports.headHandlerForBrowser = headHandlerForBrowser;
var _react = _interopRequireWildcard(require("react"));
var _gatsby = require("gatsby");
var _reachRouter = require("@gatsbyjs/reach-router");
var _reactDomUtils = require("../react-dom-utils");
var _fireCallbackInEffect = require("./components/fire-callback-in-effect");
var _constants = require("./constants");
var _utils = require("./utils");
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
const hiddenRoot = document.createElement(`div`);
const removePrevHeadElements = () => {
const prevHeadNodes = document.querySelectorAll(`[data-gatsby-head]`);
for (const node of prevHeadNodes) {
node.parentNode.removeChild(node);
}
};
const onHeadRendered = () => {
const validHeadNodes = [];
const seenIds = new Map();
for (const node of hiddenRoot.childNodes) {
var _node$attributes, _node$attributes$id;
const nodeName = node.nodeName.toLowerCase();
const id = (_node$attributes = node.attributes) === null || _node$attributes === void 0 ? void 0 : (_node$attributes$id = _node$attributes.id) === null || _node$attributes$id === void 0 ? void 0 : _node$attributes$id.value;
if (!_constants.VALID_NODE_NAMES.includes(nodeName)) {
(0, _utils.warnForInvalidTags)(nodeName);
} else {
let clonedNode = node.cloneNode(true);
clonedNode.setAttribute(`data-gatsby-head`, true); // Create an element for scripts to make script work
if (clonedNode.nodeName.toLowerCase() === `script`) {
const script = document.createElement(`script`);
for (const attr of clonedNode.attributes) {
script.setAttribute(attr.name, attr.value);
}
script.innerHTML = clonedNode.innerHTML;
clonedNode = script;
}
if (id) {
if (!seenIds.has(id)) {
validHeadNodes.push(clonedNode);
seenIds.set(id, validHeadNodes.length - 1);
} else {
var _validHeadNodes$index;
const indexOfPreviouslyInsertedNode = seenIds.get(id);
(_validHeadNodes$index = validHeadNodes[indexOfPreviouslyInsertedNode].parentNode) === null || _validHeadNodes$index === void 0 ? void 0 : _validHeadNodes$index.removeChild(validHeadNodes[indexOfPreviouslyInsertedNode]);
validHeadNodes[indexOfPreviouslyInsertedNode] = clonedNode;
}
} else {
validHeadNodes.push(clonedNode);
}
}
}
const existingHeadElements = document.querySelectorAll(`[data-gatsby-head]`);
if (existingHeadElements.length === 0) {
document.head.append(...validHeadNodes);
return;
}
const newHeadNodes = [];
(0, _utils.diffNodes)({
oldNodes: existingHeadElements,
newNodes: validHeadNodes,
onStale: node => node.parentNode.removeChild(node),
onNew: node => newHeadNodes.push(node)
});
document.head.append(...newHeadNodes);
};
if (process.env.BUILD_STAGE === `develop`) {
// We set up observer to be able to regenerate <head> after react-refresh
// updates our hidden element.
const observer = new MutationObserver(onHeadRendered);
observer.observe(hiddenRoot, {
attributes: true,
childList: true,
characterData: true,
subtree: true
});
}
function headHandlerForBrowser({
pageComponent,
staticQueryResults,
pageComponentProps
}) {
(0, _react.useEffect)(() => {
if (pageComponent !== null && pageComponent !== void 0 && pageComponent.Head) {
(0, _utils.headExportValidator)(pageComponent.Head);
const {
render
} = (0, _reactDomUtils.reactDOMUtils)();
const Head = pageComponent.Head;
render(
/*#__PURE__*/
// just a hack to call the callback after react has done first render
// Note: In dev, we call onHeadRendered twice( in FireCallbackInEffect and after mutualution observer dectects initail render into hiddenRoot) this is for hot reloading
// In Prod we only call onHeadRendered in FireCallbackInEffect to render to head
_react.default.createElement(_fireCallbackInEffect.FireCallbackInEffect, {
callback: onHeadRendered
}, /*#__PURE__*/_react.default.createElement(_gatsby.StaticQueryContext.Provider, {
value: staticQueryResults
}, /*#__PURE__*/_react.default.createElement(_reachRouter.LocationProvider, null, /*#__PURE__*/_react.default.createElement(Head, (0, _utils.filterHeadProps)(pageComponentProps))))), hiddenRoot);
}
return () => {
removePrevHeadElements();
};
});
}