diff --git a/packages/client/src/setupUpdateHead.ts b/packages/client/src/setupUpdateHead.ts index f64d35d8293..1c6ec61e567 100644 --- a/packages/client/src/setupUpdateHead.ts +++ b/packages/client/src/setupUpdateHead.ts @@ -1,4 +1,8 @@ -import { isPlainObject, isString } from '@vuepress/shared' +import { + isPlainObject, + isString, + resolveHeadIdentifier, +} from '@vuepress/shared' import type { HeadConfig, VuepressSSRContext } from '@vuepress/shared' import { onMounted, provide, ref, useSSRContext, watch } from 'vue' import { @@ -25,35 +29,45 @@ export const setupUpdateHead = (): void => { return } - const headTags = ref([]) + const headTags = ref<{ el: HTMLElement; id: string }[]>([]) // load current head tags from DOM const loadHead = (): void => { head.value.forEach((item) => { const tag = queryHeadTag(item) if (tag) { - headTags.value.push(tag) + headTags.value.push({ el: tag, id: resolveHeadIdentifier(item) }) } }) } // update html lang attribute and head tags to DOM const updateHead: UpdateHead = () => { - document.documentElement.lang = lang.value + const oldHeadTags = headTags.value + const newHeadTags = head.value + .map((item) => ({ + id: resolveHeadIdentifier(item), + el: createHeadTag(item), + })) + .filter(({ el }) => el !== null) - headTags.value.forEach((item) => { - if (item.parentNode === document.head) { - document.head.removeChild(item) - } + // update lang + if (document.documentElement.lang !== lang.value) + document.documentElement.lang = lang.value + + oldHeadTags.forEach(({ el, id: oldID }) => { + const existingHeaIndex = newHeadTags.findIndex(({ id }) => id === oldID) + + // remove the tag in new tags to preserve it + if (existingHeaIndex !== -1) newHeadTags.splice(existingHeaIndex, 1) + // remove old head tags + else document.head.removeChild(el) }) - headTags.value.splice(0, headTags.value.length) - head.value.forEach((item) => { - const tag = createHeadTag(item) - if (tag !== null) { - document.head.appendChild(tag) - headTags.value.push(tag) - } + // append new head tags + newHeadTags.forEach((head) => { + document.head.appendChild(head.el) + headTags.value.push(head) }) } provide(updateHeadSymbol, updateHead)