fix: de-duplicate head tags while merging (#975) (#976)

pull/977/head
Divyansh Singh 2 years ago committed by GitHub
parent 65ec9d740b
commit f7e9cfeb3a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,5 +1,5 @@
import { watchEffect, Ref } from 'vue'
import { HeadConfig, SiteData, createTitle } from '../../shared'
import { HeadConfig, SiteData, createTitle, mergeHead } from '../../shared'
import { Route } from '../router'
export function useUpdateHead(route: Route, siteDataByRouteRef: Ref<SiteData>) {
@ -14,50 +14,20 @@ export function useUpdateHead(route: Route, siteDataByRouteRef: Ref<SiteData>) {
return
}
const newEls: HTMLElement[] = []
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) => {
managedHeadTags.forEach((el) => document.head.removeChild(el))
managedHeadTags = []
newTags.forEach((headConfig) => {
const el = createHeadElement(headConfig)
document.head.appendChild(el)
newEls.push(el)
managedHeadTags.push(el)
})
managedHeadTags = newEls
}
watchEffect(() => {
const pageData = route.data
const siteData = siteDataByRouteRef.value
const pageDescription = pageData && pageData.description
const frontmatterHead = pageData && pageData.frontmatter.head
const frontmatterHead = (pageData && pageData.frontmatter.head) || []
// update title and description
document.title = createTitle(siteData, pageData)
@ -66,11 +36,9 @@ export function useUpdateHead(route: Route, siteDataByRouteRef: Ref<SiteData>) {
.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) : [])
])
updateHeadTags(
mergeHead(siteData.head, filterOutHeadDescription(frontmatterHead))
)
})
}

@ -5,7 +5,13 @@ import { pathToFileURL } from 'url'
import escape from 'escape-html'
import { normalizePath, transformWithEsbuild } from 'vite'
import { RollupOutput, OutputChunk, OutputAsset } from 'rollup'
import { HeadConfig, PageData, createTitle, notFoundPageData } from '../shared'
import {
HeadConfig,
PageData,
createTitle,
notFoundPageData,
mergeHead
} from '../shared'
import { slash } from '../utils/slash'
import { SiteConfig, resolveSiteDataByRoute } from '../config'
@ -115,10 +121,10 @@ export async function renderPage(
const title: string = createTitle(siteData, pageData)
const description: string = pageData.description || siteData.description
const head = [
...siteData.head,
...filterOutHeadDescription(pageData.frontmatter.head)
]
const head = mergeHead(
siteData.head,
filterOutHeadDescription(pageData.frontmatter.head)
)
let inlinedScript = ''
if (config.mpa && result) {

@ -285,7 +285,7 @@ function resolveSiteDataHead(userConfig?: UserConfig): HeadConfig[] {
if (userConfig?.appearance ?? true) {
head.push([
'script',
{},
{ id: 'check-dark-light' },
`
;(() => {
const saved = localStorage.getItem('${APPEARANCE_KEY}')

@ -1,4 +1,9 @@
import { SiteData, PageData, LocaleConfig } from '../../types/shared'
import {
SiteData,
PageData,
LocaleConfig,
HeadConfig
} from '../../types/shared'
export type {
SiteData,
@ -136,3 +141,16 @@ function cleanRoute(siteData: SiteData, route: string): string {
return route.slice(baseWithoutSuffix.length)
}
function hasTag(head: HeadConfig[], tag: HeadConfig) {
const [tagType, tagAttrs] = tag
const keyAttr = Object.entries(tagAttrs)[0] // First key
if (keyAttr == null) return false
return head.some(
([type, attrs]) => type === tagType && attrs[keyAttr[0]] === keyAttr[1]
)
}
export function mergeHead(prev: HeadConfig[], curr: HeadConfig[]) {
return [...prev.filter((tagAttrs) => !hasTag(curr, tagAttrs)), ...curr]
}

Loading…
Cancel
Save