51 lines
1.9 KiB
JavaScript
51 lines
1.9 KiB
JavaScript
import { watchEffect } from 'vue';
|
|
import { createTitle, mergeHead } from '../../shared';
|
|
export function useUpdateHead(route, siteDataByRouteRef) {
|
|
let managedHeadTags = [];
|
|
let isFirstUpdate = true;
|
|
const updateHeadTags = (newTags) => {
|
|
if (import.meta.env.PROD && isFirstUpdate) {
|
|
// in production, the initial meta tags are already pre-rendered so we
|
|
// skip the first update.
|
|
isFirstUpdate = false;
|
|
return;
|
|
}
|
|
managedHeadTags.forEach((el) => document.head.removeChild(el));
|
|
managedHeadTags = [];
|
|
newTags.forEach((headConfig) => {
|
|
const el = createHeadElement(headConfig);
|
|
document.head.appendChild(el);
|
|
managedHeadTags.push(el);
|
|
});
|
|
};
|
|
watchEffect(() => {
|
|
const pageData = route.data;
|
|
const siteData = siteDataByRouteRef.value;
|
|
const pageDescription = pageData && pageData.description;
|
|
const frontmatterHead = (pageData && pageData.frontmatter.head) || [];
|
|
// update title and description
|
|
document.title = createTitle(siteData, pageData);
|
|
document
|
|
.querySelector(`meta[name=description]`)
|
|
.setAttribute('content', pageDescription || siteData.description);
|
|
updateHeadTags(mergeHead(siteData.head, filterOutHeadDescription(frontmatterHead)));
|
|
});
|
|
}
|
|
function createHeadElement([tag, attrs, innerHTML]) {
|
|
const el = document.createElement(tag);
|
|
for (const key in attrs) {
|
|
el.setAttribute(key, attrs[key]);
|
|
}
|
|
if (innerHTML) {
|
|
el.innerHTML = innerHTML;
|
|
}
|
|
return el;
|
|
}
|
|
function isMetaDescription(headConfig) {
|
|
return (headConfig[0] === 'meta' &&
|
|
headConfig[1] &&
|
|
headConfig[1].name === 'description');
|
|
}
|
|
function filterOutHeadDescription(head) {
|
|
return head.filter((h) => !isMetaDescription(h));
|
|
}
|