- useSeoLabels(): the L8 dictionary (en, pl) of the page's content locale (resolve locale, then html_lang, then en), overridable and extendable in app.config.ts under seo.labels; no i18n dependency - seo-tokens.css (spacing, colour, small type, breadcrumb separator) and seo-base.css (.seo-visually-hidden, the focus ring of layer links), loaded before the app's CSS and styling only .seo-* classes
106 lines
4.9 KiB
TypeScript
106 lines
4.9 KiB
TypeScript
// vue-seo-layer: the frontend half of the SummerCMS SEO plugin
|
|
// (golem15.seo). For every page it asks GET /_seo/api/v1/resolve?url=…,
|
|
// enforces the redirect and 410 decisions, and sets the head (title,
|
|
// description, canonical, robots, Open Graph, X/Twitter, verification,
|
|
// hreflang, <html lang> and one JSON-LD @graph) from the answer with priority
|
|
// over the page's own tags. It also reports 404s to the plugin's log and
|
|
// serves the site's root files (verification files and, with a backend that
|
|
// answers /_seo/api/v1/site, robots.txt, the sitemaps, llms.txt and the
|
|
// IndexNow key). An app consumes it with `extends: ['vue-seo-layer']`.
|
|
//
|
|
// Every path below is absolute and built from this file's directory: a
|
|
// relative or ~ path in a layer config resolves against the consuming
|
|
// project, not the layer. The layer's only module is its own local one
|
|
// (lib/seo-module.ts); it pulls in no package.
|
|
|
|
import { fileURLToPath } from 'node:url'
|
|
|
|
const currentDir = fileURLToPath(new URL('.', import.meta.url))
|
|
|
|
export default defineNuxtConfig({
|
|
compatibilityDate: '2025-07-15',
|
|
devtools: { enabled: false },
|
|
|
|
modules: [`${currentDir}lib/seo-module.ts`],
|
|
|
|
// Tokens first, then the base styles that use them (only .seo-* classes).
|
|
// The app's own css array loads after these, so its overrides win.
|
|
css: [`${currentDir}app/assets/css/seo-tokens.css`, `${currentDir}app/assets/css/seo-base.css`],
|
|
|
|
runtimeConfig: {
|
|
seo: {
|
|
// Server-only base for SSR calls (NUXT_SEO_API_BASE). It never comes
|
|
// from request input.
|
|
apiBase: 'http://127.0.0.1:8096/_seo/api/v1',
|
|
// Server-only origin of the Go binary for the root files
|
|
// (NUXT_SEO_BACKEND_BASE). Empty: apiBase without /_seo/api/v1, so
|
|
// http://127.0.0.1:8096 by default.
|
|
backendBase: '',
|
|
// Server-only bearer token of POST /notfound (NUXT_SEO_NOTFOUND_TOKEN),
|
|
// the backend's golem15.seo.notfound_token. Empty: 404s are not
|
|
// reported. Not under NUXT_SITE_: nuxt-site-config copies every
|
|
// NUXT_SITE_* variable into the site config, which is published in
|
|
// every page's payload.
|
|
notfoundToken: '',
|
|
// Server-only bearer token of the route report
|
|
// (NUXT_SEO_ROUTE_REPORT_TOKEN). Empty: notfoundToken is used.
|
|
routeReportToken: '',
|
|
// How long a resolve call may take before the page renders without it
|
|
// (NUXT_SEO_TIMEOUT_MS).
|
|
timeoutMs: 1500,
|
|
// Seconds a resolve answer stays in the layer's cache
|
|
// (NUXT_SEO_RESOLVE_CACHE_TTL); the site cache purge clears it. 0
|
|
// turns the cache off.
|
|
resolveCacheTtl: 60,
|
|
},
|
|
// The shared site cache purge route POST /api/__site__/cache/purge
|
|
// (moved here from the journal, menu and FAQ layers, same contract).
|
|
cachePurge: {
|
|
// Server-only bearer token (NUXT_CACHE_PURGE_TOKEN), the backend's
|
|
// site_cache.purge_token. Shorter than 32 characters, the route
|
|
// answers 404. Not under NUXT_SITE_: nuxt-site-config copies every
|
|
// NUXT_SITE_* variable into the site config, which is published in
|
|
// every page's payload.
|
|
token: '',
|
|
// NUXT_CACHE_PURGE_ALLOW_PROXIED: set it to true when the backend
|
|
// reaches the site through a TLS-terminating proxy (an https
|
|
// site_cache.purge_url on another host), which adds X-Forwarded-For,
|
|
// X-Real-IP or Forwarded. The route then accepts proxied requests and
|
|
// the bearer token is the only gate; unset, it answers 404 to any
|
|
// proxied request.
|
|
allowProxied: false,
|
|
},
|
|
// Deprecated (one release): the earlier names of cachePurge.token
|
|
// (NUXT_SITE_CACHE_PURGE_TOKEN) and cachePurge.allowProxied
|
|
// (NUXT_SITE_CACHE_ALLOW_PROXIED), read when the new ones are unset. The
|
|
// layer's server/plugins/site-cache-purge.ts strips them from the site
|
|
// config and logs a deprecation warning.
|
|
siteCache: {
|
|
purgeToken: '',
|
|
allowProxied: false,
|
|
},
|
|
public: {
|
|
seo: {
|
|
// Same-origin base for browser navigations (NUXT_PUBLIC_SEO_API_BASE).
|
|
// The site's proxy routes GET <base>/resolve to the backend; set it
|
|
// to /api/__seo__ to resolve through the Nuxt server instead.
|
|
apiBase: '/_seo/api/v1',
|
|
// NUXT_PUBLIC_SEO_ENABLED=false turns the layer off: no resolve
|
|
// calls, no head, no redirects, no root files, no 404 reports. The
|
|
// module option seo.cms (NUXT_PUBLIC_SEO_CMS) is an alias.
|
|
enabled: true,
|
|
},
|
|
},
|
|
},
|
|
|
|
// The layer's routes and the shared site routes are never route-cached.
|
|
// Nitro wraps every handler matching an app rule such as '/**': { swr } in
|
|
// its cached handler, which keys by path, does not skip POST and hides
|
|
// request headers, so the purge route would answer from the cache without
|
|
// running.
|
|
routeRules: {
|
|
'/api/__seo__/**': { cache: false },
|
|
'/api/__site__/**': { cache: false },
|
|
},
|
|
})
|