feat: shared site cache purge route clears the SEO caches
- POST /api/__site__/cache/purge, its library and the site config plugin moved from vue-journal-layer with the same contract (token rules, 404 for proxied requests unless allowProxied, deprecated siteCache names); the route also clears the resolve cache - server/plugins/seo-cache-purge.ts clears the SEO caches after any 200 purge, so an app whose journal, menu or FAQ layer copy of the route wins keeps fresh SEO answers until those copies are removed - cachePurge and siteCache runtime keys; /api/__site__/** never cached - testing/purge-check.mjs (CMS answer change, plus a redirect added for a route-cached page applying at once) and purge-token-check.mjs
This commit is contained in:
22
server/plugins/seo-cache-purge.ts
Normal file
22
server/plugins/seo-cache-purge.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
// Clears the SEO layer's caches after every successful site cache purge,
|
||||
// whichever layer's copy of POST /api/__site__/cache/purge answered it.
|
||||
//
|
||||
// vue-journal-layer, vue-menu-layer and vue-faq-layer ship their own copy of
|
||||
// the shared purge route until they extend this layer, and Nitro keeps one
|
||||
// handler per route and method, so in an app that extends several of them
|
||||
// this layer's route (which clears the caches itself) may not be the one
|
||||
// that runs. The journal's deprecated POST /api/__journal__/cache/purge
|
||||
// purges the route cache too, so it clears them as well. Clearing twice is
|
||||
// harmless.
|
||||
|
||||
import { clearSeoCaches } from '../lib/resolve.ts'
|
||||
|
||||
const PURGE_PATHS = new Set(['/api/__site__/cache/purge', '/api/__journal__/cache/purge'])
|
||||
|
||||
export default defineNitroPlugin((nitroApp) => {
|
||||
nitroApp.hooks.hook('afterResponse', (event) => {
|
||||
if (event.method !== 'POST') return
|
||||
if (!PURGE_PATHS.has((event.path.split('?')[0] ?? '').replace(/\/+$/, ''))) return
|
||||
if (event.node.res.statusCode === 200) clearSeoCaches()
|
||||
})
|
||||
})
|
||||
48
server/plugins/site-cache-purge.ts
Normal file
48
server/plugins/site-cache-purge.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
// 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)
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user