feat!: extend the SEO layer and drop the copied purge route

- extend vue-seo-layer (link dependency during development); every page
  takes its head from the SEO plugin through it
- remove the copied shared purge route, library, plugin and their test:
  POST /api/__site__/cache/purge comes from vue-seo-layer with the same
  contract and environment variables
- the page-less playground sets seo.htmlSitemap false; the smoke points
  NUXT_SEO_API_BASE at the fixture API (fails open)

BREAKING CHANGE: server/api/__site__/cache/purge.post.ts,
server/lib/siteCachePurge.ts and server/plugins/site-cache-purge.ts are
no longer in this layer, and the runtime keys cachePurge and siteCache
are declared by vue-seo-layer. An app without pages sets
seo.htmlSitemap false.
This commit is contained in:
Jakub Zych
2026-11-04 13:59:38 +01:00
parent ef3a090647
commit 8b5da6762c
10 changed files with 132 additions and 891 deletions

View File

@@ -1,48 +0,0 @@
// Keeps the site cache purge settings out of the public site config.
//
// nuxt-site-config (pulled in by @nuxtjs/seo) copies every NUXT_SITE_* and
// NUXT_PUBLIC_SITE_* environment variable into the site config, camel-cased,
// and Nuxt serializes the site config into every page's payload (and into
// window.__NUXT_SITE_CONFIG__ on client-only pages). The purge token's
// earlier name NUXT_SITE_CACHE_PURGE_TOKEN therefore reached every page as
// cachePurgeToken, and NUXT_SITE_CACHE_ALLOW_PROXIED as cacheAllowProxied.
// The settings now live under NUXT_CACHE_PURGE_TOKEN and
// NUXT_CACHE_PURGE_ALLOW_PROXIED, outside that prefix. The old names keep
// working for one release, so this plugin also removes the two keys from
// every entry of the site config stack on nuxt-site-config's
// `site-config:init` hook, before anything reads it. The stripping stays
// with the new names too: a site that still sets an old variable, or sets
// both, must not publish it.
//
// When a setting comes from an old name, the plugin logs one deprecation
// warning per process (globalThis[SITE_PURGE_WARNED], so a site extending
// several layers that ship this file warns once). The warning names
// variables, never a value.
//
// Without nuxt-site-config the hook is never called and the plugin does
// nothing else. Shared: several layers ship this file byte for byte;
// running it more than once is harmless.
import { SITE_PURGE_WARNED, redactSiteConfigStack, resolveSitePurgeConfig, sitePurgeDeprecationMessage } from '../lib/siteCachePurge.ts'
interface SiteConfigInitContext {
siteConfig?: { stack?: unknown }
}
type LooseHooks = { hook: (name: string, fn: (ctx: SiteConfigInitContext | undefined) => void) => unknown }
export default defineNitroPlugin((nitroApp) => {
const g = globalThis as Record<symbol, unknown>
if (!g[SITE_PURGE_WARNED]) {
const message = sitePurgeDeprecationMessage(resolveSitePurgeConfig(useRuntimeConfig()).deprecated)
if (message) {
g[SITE_PURGE_WARNED] = true
console.warn(message)
}
}
// The hook name is untyped in an app without nuxt-site-config.
;(nitroApp.hooks as unknown as LooseHooks).hook('site-config:init', (ctx) => {
redactSiteConfigStack(ctx?.siteConfig?.stack)
})
})