Files
vue-seo-layer/app/plugins/seo-route-robots.ts
Jakub Zych 9cc2cda924 feat: noindex for declared and signed-in routes
- app plugin seo-route-robots: a page whose meta sets requiresAuth: true
  gets robots noindex, nofollow, a page with seo.robots gets its value,
  a path under seo.noindexRoutes gets noindex, nofollow; meta tag above
  the CMS head entry and X-Robots-Tag during SSR, never on staging
- requiresAuth and seo added to Nuxt's page meta extraction keys
- playground /konto, /szkic and /prywatne with their smoke lines
2026-11-04 11:49:14 +01:00

51 lines
2.1 KiB
TypeScript

// Noindex for the routes an app declares (D-23, D-21), without page code:
//
// - a page whose meta sets requiresAuth: true (a signed-in or auth page)
// gets robots "noindex, nofollow";
// - a page whose meta sets seo: { robots: '...' } gets that value;
// - a path under seo.noindexRoutes gets "noindex, nofollow" (its route
// rule already sends the header; this adds the meta tag).
//
// The value goes into a robots meta tag that wins over the CMS's (a lower
// tagPriority than the head plugin's 'critical') and, during SSR, into the
// X-Robots-Tag header once the navigation is done, after the route
// middleware. Every other page keeps the CMS robots; on staging the CMS's
// noindex, nofollow stays. Works with the layer off too: it reads no CMS.
import { isNoindex } from '../../lib/guard.ts'
import { pageMetaRobots } from '../../lib/routes.ts'
/** Wins over the CMS head entry (tagPriority 'critical', -8). */
const ROUTE_ROBOTS_PRIORITY = -10
export default defineNuxtPlugin((nuxtApp) => {
const config = useRuntimeConfig()
const declared = (config.public.seo as { noindexRoutes?: unknown } | undefined)?.noindexRoutes
const noindexRoutes = Array.isArray(declared) ? declared.filter((p): p is string => typeof p === 'string') : []
const router = useRouter()
const answer = useSeoAnswer()
const robotsFor = (route: { path: string; meta: Record<string, unknown> }): string | null => {
if (answer.value?.staging === true) return null
const own = pageMetaRobots(route.meta)
if (own) return own
return isNoindex(route.path, noindexRoutes) ? 'noindex, nofollow' : null
}
useHead(
computed(() => {
const robots = robotsFor(router.currentRoute.value)
return robots ? { meta: [{ name: 'robots', content: robots }] } : {}
}),
{ tagPriority: ROUTE_ROBOTS_PRIORITY },
)
if (import.meta.server) {
router.afterEach((to, _from, failure) => {
if (failure) return
const robots = robotsFor(to)
if (robots) nuxtApp.runWithContext(() => (useResponseHeader('X-Robots-Tag').value = robots))
})
}
})