Files
vue-journal-layer/nuxt.config.ts
Jakub Zych 289d031201 feat!: render the post page on the shared SEO layer with one H1 in both Journal H1 modes (tracer)
- extend vue-seo-layer (link dependency during development) and drop
  @nuxtjs/seo: the page head, canonical and the one JSON-LD graph come
  from the CMS resolve answer; the post's own title, excerpt and image
  apply only while there is no CMS answer
- remove the journal sitemap source and the copied shared purge route,
  library and plugin (the SEO layer serves POST /api/__site__/cache/purge);
  the deprecated POST /api/__journal__/cache/purge keeps working
- post title is h1 while the Journal API reports content_h1_to_h2 on
  (or absent) and p.journal-post__title while off; journal.postTitleTag
  ('auto' | 'h1' | 'p') overrides it; body h1 headings are demoted to h2
  while the setting is on (gateJournalHtml/sanitizeJournalHtml demoteH1)
- journal.breadcrumbs option and post-title CSS tokens
- smoke harness: count=, header=, noheader= and resolves lines; the
  fixture API also answers the SEO resolve and site endpoints

BREAKING CHANGE: the layer no longer installs @nuxtjs/seo (no
nuxt-site-config, nuxt-schema-org, robots or sitemap module, no
/api/__sitemap__/journal source, no useSiteConfig()); apps take their
head, sitemaps and robots from the SEO plugin through vue-seo-layer.
2026-11-04 13:37:11 +01:00

66 lines
2.7 KiB
TypeScript

// vue-journal-layer: reusable Journal views as a Nuxt layer. An app consumes
// it with `extends: ['vue-journal-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.
import { fileURLToPath } from 'node:url'
const currentDir = fileURLToPath(new URL('.', import.meta.url))
export default defineNuxtConfig({
compatibilityDate: '2025-07-15',
devtools: { enabled: false },
// The SEO layer owns the page head (title, description, canonical,
// robots, Open Graph, hreflang and the one JSON-LD @graph) from the CMS
// resolve answer, the shared site cache purge route and the visible
// breadcrumbs and pagination. Resolved from this layer's own
// node_modules.
extends: ['vue-seo-layer'],
// The consuming app may have no app/pages directory; the Journal pages are
// registered by the journal module, so the router must be on regardless.
pages: true,
// Declared once here, so the app never re-lists them (two copies of
// @nuxtjs/i18n split locale state).
modules: ['@nuxt/fonts', '@nuxtjs/i18n', `${currentDir}lib/journal-module.ts`],
// Tokens first, then the neutral styles that use them. The app's own css
// array loads after these, so its token overrides win.
css: [`${currentDir}app/assets/css/journal-tokens.css`, `${currentDir}app/assets/css/journal-base.css`],
runtimeConfig: {
journal: {
// Server-only base for SSR fetches (NUXT_JOURNAL_API_BASE). It never
// comes from request input.
apiBase: 'http://127.0.0.1:8096/_journal/api/v1',
// Server-only bearer token of the old Journal purge route
// POST /api/__journal__/cache/purge (NUXT_JOURNAL_CACHE_PURGE_TOKEN),
// kept for one release; new sites use cachePurge.token, the SEO
// layer's POST /api/__site__/cache/purge. Shorter than 32 characters,
// the route answers 404.
cachePurgeToken: '',
},
public: {
journal: {
// Same-origin base for browser fetches (NUXT_PUBLIC_JOURNAL_API_BASE).
apiBase: '/_journal/api/v1',
},
},
},
// The Journal's internal 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. The SEO layer keeps '/api/__site__/**' out of the cache.
routeRules: {
'/api/__journal__/**': { cache: false },
},
// i18n: the layer declares no locales. The journal module registers the
// layer's pl/en strings only for locales the app enables.
})