12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485 |
- import { watchEffect } from 'vue';
- 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;
- }
- const newEls = [];
- const commonLength = Math.min(managedHeadTags.length, newTags.length);
- for (let i = 0; i < commonLength; i++) {
- let el = managedHeadTags[i];
- const [tag, attrs, innerHTML = ''] = newTags[i];
- if (el.tagName.toLocaleLowerCase() === tag) {
- for (const key in attrs) {
- if (el.getAttribute(key) !== attrs[key]) {
- el.setAttribute(key, attrs[key]);
- }
- }
- for (let i = 0; i < el.attributes.length; i++) {
- const name = el.attributes[i].name;
- if (!(name in attrs)) {
- el.removeAttribute(name);
- }
- }
- if (el.innerHTML !== innerHTML) {
- el.innerHTML = innerHTML;
- }
- }
- else {
- document.head.removeChild(el);
- el = createHeadElement(newTags[i]);
- document.head.append(el);
- }
- newEls.push(el);
- }
- managedHeadTags
- .slice(commonLength)
- .forEach((el) => document.head.removeChild(el));
- newTags.slice(commonLength).forEach((headConfig) => {
- const el = createHeadElement(headConfig);
- document.head.appendChild(el);
- newEls.push(el);
- });
- managedHeadTags = newEls;
- };
- watchEffect(() => {
- const pageData = route.data;
- const siteData = siteDataByRouteRef.value;
- const pageTitle = pageData && pageData.title;
- const pageDescription = pageData && pageData.description;
- const frontmatterHead = pageData && pageData.frontmatter.head;
- // update title and description
- document.title = (pageTitle ? pageTitle + ` | ` : ``) + siteData.title;
- document
- .querySelector(`meta[name=description]`)
- .setAttribute('content', pageDescription || siteData.description);
- updateHeadTags([
- // site head can only change during dev
- ...(import.meta.env.DEV ? siteData.head : []),
- ...(frontmatterHead ? 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));
- }
|