Files
vue-seo-layer/server/middleware/seo.ts
Jakub Zych 160b53b2f5 feat: CMS head and one JSON-LD graph on every server-rendered page (tracer)
- Nitro middleware resolves page requests once and hands the answer to the
  render (event.context.seo); the route middleware reuses it
- useCmsSeo: html lang, hreflang links, og:locale and exactly one JSON-LD
  script with one @graph (CMS nodes plus useSchemaNode nodes, merged by @id)
- local module (configKey seo): cms (alias of public.seo.enabled),
  breadcrumbs, links.newTabHint, rootFiles, resolveFiles
- GET /api/__seo__/resolve for client navigation through the Nuxt server
- smoke harness: count=, exact header=, noheader=, reqheader=, repeated
  options, resolves/apicalls/noreport lines, --no-site; v0.1.1 suite runs
  unchanged against a backend without /site
2026-11-04 09:15:26 +01:00

22 lines
928 B
TypeScript

// Resolves every page request through the CMS before Nuxt renders it, so the
// render (and the head) uses one answer and no second call. Skipped: Nuxt's
// and the layers' internal paths (/_nuxt, /__nuxt_error, /_seo …), /api and
// asset files (isPagePath). The answer is left in event.context.seo for the
// app (useSeoResolve reads event.context.seoResolved).
import { isPagePath } from '../../app/utils/pagePath.ts'
import { seoServerConfig } from '../lib/config.ts'
import { resolveCached } from '../lib/resolve.ts'
export default defineEventHandler(async (event) => {
if (event.method !== 'GET' && event.method !== 'HEAD') return
const cfg = seoServerConfig(useRuntimeConfig(event))
if (!cfg.enabled) return
const url = event.path
if (!isPagePath(url, cfg.resolveFiles)) return
const answer = await resolveCached(event, url)
event.context.seo = answer
event.context.seoResolved = { url, answer }
})