import type { PageHead } from '../seo'; import { JSON_LD_ATTRIBUTE, serializeStructuredData } from '../structured-data'; /** Update the existing SSR tags and remove stale/duplicate tags after SPA navigation. */ export function applyPageHead(head:PageHead,doc:Document=document):void { doc.title=head.title; function tag(selector:string,element:'meta'|'link',attributes:Record,value:string|undefined){ const matches=Array.from(doc.head.querySelectorAll(selector)); const node=matches.shift();matches.forEach(item=>item.remove()); if(!value){node?.remove();return;} const target=node||doc.createElement(element); for(const [name,content] of Object.entries(attributes))target.setAttribute(name,content); target.setAttribute(element==='meta'?'content':'href',value); if(!node)doc.head.appendChild(target); } const meta=(name:string,value:string|undefined)=>tag(`meta[name="${name}"]`,'meta',{name},value); const og=(property:string,value:string|undefined)=>tag(`meta[property="${property}"]`,'meta',{property},value); const link=(rel:string,value:string|undefined)=>tag(`link[rel="${rel}"]`,'link',{rel},value); meta('description',head.description);meta('keywords',head.keywords.join(','));meta('application-name',head.siteName); meta('robots',head.robots);meta('googlebot',head.robots); link('canonical',head.canonical);link('prev',head.previous);link('next',head.next); og('og:locale','zh_CN');og('og:type',head.type);og('og:site_name',head.siteName); og('og:title',head.title);og('og:description',head.description);og('og:url',head.canonical);og('og:image',head.image||undefined); og('og:image:width',head.image?'1200':undefined);og('og:image:height',head.image?'630':undefined);og('og:image:alt',head.image?head.siteName:undefined); meta('twitter:card','summary_large_image');meta('twitter:title',head.title);meta('twitter:description',head.description); meta('twitter:image',head.image||undefined);meta('twitter:image:alt',head.image?head.siteName:undefined); const selector=`script[${JSON_LD_ATTRIBUTE}]`; const scripts=[...new Set([...doc.head.querySelectorAll(selector),...doc.querySelectorAll(selector)])]; const script=scripts.shift();scripts.forEach(item=>item.remove()); if(!head.jsonLd){script?.remove();return;} const target=script||doc.createElement('script'); target.setAttribute('id','site-json-ld');target.setAttribute('type','application/ld+json');target.setAttribute(JSON_LD_ATTRIBUTE,''); target.textContent=serializeStructuredData(head.jsonLd); if(!script)doc.head.appendChild(target); }