Skip to content

Commit

Permalink
fix: de-duplicate head tags while merging (#975) (#976)
Browse files Browse the repository at this point in the history
  • Loading branch information
brc-dd committed Jul 13, 2022
1 parent 65ec9d7 commit f7e9cfe
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 48 deletions.
50 changes: 9 additions & 41 deletions src/client/app/composables/head.ts
@@ -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>) {
Expand All @@ -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)
Expand All @@ -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))
)
})
}

Expand Down
16 changes: 11 additions & 5 deletions src/node/build/render.ts
Expand Up @@ -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'

Expand Down Expand Up @@ -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) {
Expand Down
2 changes: 1 addition & 1 deletion src/node/config.ts
Expand Up @@ -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}')
Expand Down
20 changes: 19 additions & 1 deletion src/shared/shared.ts
@@ -1,4 +1,9 @@
import { SiteData, PageData, LocaleConfig } from '../../types/shared'
import {
SiteData,
PageData,
LocaleConfig,
HeadConfig
} from '../../types/shared'

export type {
SiteData,
Expand Down Expand Up @@ -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]
}

0 comments on commit f7e9cfe

Please sign in to comment.