@stackonward/cms-nuxt

Nuxt 3 CMS runtime with composables, server routes, preview, and sitemap support
639
Install
npm install @stackonward/cms-nuxt
Latest Version:0.0.4
Vue:3
License:MIT
Last Updated:Sep 17, 2026
Links: npm
Maintainer: yhy2001

@stackonward/cms-nuxt

Nuxt module for product-agnostic CMS delivery integration. It registers CMS runtime configuration, auto-imported composables, Nuxt server endpoints, preview support, cache revalidation, runtime site configuration, route-policy URL generation, and optional @nuxtjs/sitemap integration.

The package owns the CMS client boundary and resource route policy. Consuming products own Nuxt page shells and choose the public URL shape through module options.

Install

pnpm add @stackonward/cms-nuxt @stackonward/cms-client @stackonward/section-renderer-vue

Peer Dependencies

  • nuxt >=3.15.0
  • @stackonward/cms-client ^0.0.3
  • @stackonward/section-renderer-vue ^0.0.1
  • install @nuxtjs/sitemap when cms.sitemap.enabled is true

Module Setup

Configure the module with the cms key in nuxt.config.ts. Do not create CMS runtimeConfig values by hand; the module derives the server and public runtime config from these options.

export default defineNuxtConfig({
  modules: ['@stackonward/cms-nuxt'],

  cms: {
    apiUrl: process.env.NUXT_CMS_API_URL ?? '',
    upstreamHeaders: {
      'X-Customer-Scope': process.env.NUXT_CMS_CUSTOMER_SCOPE ?? '',
    },
    defaultLocale: 'en',
    webhookSecret: process.env.NUXT_CMS_WEBHOOK_SECRET ?? '',

    routes: {
      resources: {
        index: '/resources',
        category: '/resources/{category_slug}',
        article: '/resources/{category_slug}/{slug}',
        author: '/resources/authors/{slug}',
      },
      sourceResources: {
        index: '/',
        category: '/{category_slug}',
        article: '/{category_slug}/{slug}',
        author: '/authors/{slug}',
      },
      locale: {
        defaultLocale: 'en',
        prefixes: {
          'zh-CN': 'zh',
        },
        includeDefaultLocale: false,
      },
    },

    localeMap: {
      'zh-CN': 'zh',
    },

    content: {
      articleCollectionPath: '/api/cms/articles',
      cmsProxyPath: '/cms-proxy',
    },

    site: {
      code: 'product-site',
      runtime: true,
      cacheTtl: 300000,
    },

    categories: {
      preload: true,
    },

    preview: {
      enabled: true,
      path: '/api/preview',
      cookieName: '__preview_token',
      cookieMaxAge: 1800,
    },

    revalidate: {
      enabled: true,
      path: '/api/_revalidate',
    },

    sitemap: {
      enabled: true,
      locales: ['en', 'zh-CN'],
      sourcePath: '/api/cms/sitemap-urls',
    },
  },
})

Backend-specific headers are composed outside the generic module. OneX consumers use the explicit adapter:

import { createOneXCmsUpstreamHeaders } from '@stackonward/onex-cms-client'

export default defineNuxtConfig({
  cms: {
    apiUrl: process.env.NUXT_CMS_API_URL ?? '',
    upstreamHeaders: createOneXCmsUpstreamHeaders('product_alpha'),
    webhookSecret: process.env.NUXT_CMS_WEBHOOK_SECRET ?? '',
  },
})

Module Options

Option Default Purpose
apiUrl '' CMS API base URL used by CmsClient, server routes, and SSR fetches.
upstreamHeaders {} Server-only static headers sent to the CMS upstream.
defaultLocale 'en' Public default locale used by composables and route policy.
webhookSecret '' Server-only HMAC secret for the revalidate endpoint.
routes.resources built-in defaults Public resource URL patterns generated by useCmsRoutes, preview, revalidate, and sitemap.
routes.sourceResources built-in defaults CMS API resource URL patterns used to parse preview and sitemap input before rebuilding public URLs.
routes.locale default locale policy Locale prefix policy for generated public URLs.
content.articleCollectionPath '/api/cms/articles' Nuxt server endpoint for normalized article collection queries.
content.cmsProxyPath '/cms-proxy' Nuxt server proxy prefix used by client-side CMS fetches.
site.code '' Stable CMS site lookup key used before URL or request-host lookup.
site.url '' Site URL whose host is used when no site code is configured.
site.runtime false Loads CMS site config and its route policy at request/runtime boundaries.
site.cacheTtl 300000 In-memory server cache TTL for resolved site config; 0 disables caching.
categories.preload false Fetches /categories during module setup and exposes the result in public runtime config.
preview enabled by default Preview route and preview cookie behavior.
revalidate enabled by default Signed ISR cache invalidation endpoint.
redirects enabled by default CMS redirect middleware with priority-aware matching and configurable in-memory cache TTL.
sitemap disabled by default @nuxtjs/sitemap provider integration and sitemap source endpoint path.
localeMap {} Maps public locale codes to CMS API locale codes.
localePrefixes {} Additional prefix input merged into routes.locale.prefixes.

Resource Route Policy

Resource Route Policy is the package's public URL extension point. It keeps the CMS integration product-neutral: the package knows how to build and parse resource routes, while each product chooses its page structure.

Default resource patterns are:

const defaultResourcePatterns = {
  index: '/',
  category: '/{category_slug}',
  article: '/{category_slug}/{slug}',
  author: '/authors/{slug}',
} as const

routes.resources defines public site paths. routes.sourceResources defines the path shape returned by CMS preview and sitemap payloads when that source path differs from the public site path. routes.locale controls locale prefixes:

export default defineNuxtConfig({
  cms: {
    routes: {
      resources: {
        article: '/learn/{category_slug}/{slug}',
      },
      sourceResources: {
        article: '/{category_slug}/{slug}',
      },
      locale: {
        defaultLocale: 'en',
        prefixes: { fr: 'fr' },
        includeDefaultLocale: false,
      },
    },
  },
})

useCmsRoutes() exposes the resolved policy and route builder:

<script setup lang="ts">
const cmsRoutes = useCmsRoutes()

const articlePath = cmsRoutes.build(
  'article',
  {
    category_slug: 'guides',
    slug: 'getting-started',
    locale: 'fr',
  },
  true,
)
</script>

A new product should change only:

  • cms.routes.resources, cms.routes.sourceResources, and cms.routes.locale
  • Nuxt page shells that map those URL patterns to UI components

The CMS client, preview endpoint, revalidation endpoint, category preload, fetch proxy, and sitemap source stay inside the package.

Content Endpoints

The module registers no-cache Nuxt server endpoints from the configured paths.

Endpoint Method Behavior
content.articleCollectionPath GET Returns Paginated<ArticleListItem> with locale, category_slug, q, page, and page_size query support. Search results are normalized into article cards.
${content.cmsProxyPath}/** any Proxies client-side CMS requests to apiUrl, applying server-only upstream headers and the preview token when present.
/api/cms/site GET Resolves CMS site configuration by configured code, configured URL host, or request host.
sitemap.sourcePath GET Returns Nuxt sitemap entries for ?locale=... using route policy and CMS sitemap data.
preview.path GET Reads preview input, sets the preview cookie, and redirects to the route-policy-generated resource path.
revalidate.path POST Verifies x-webhook-signature and clears matching Nitro route cache entries.

Categories

Set categories.preload to true when category navigation or route guards need category data at render time. The module fetches ${apiUrl}/categories during setup and exposes the data to useCmsCategories().

<script setup lang="ts">
const { currentCategories, getCategoryPath, categoryExists } = useCmsCategories()
</script>

Use useCategories() when the page should fetch categories through @stackonward/cms-client with useAsyncData.

Runtime site configuration

Set site.runtime: true when the CMS owns per-site route policy and site metadata. Resolution prefers site.code, then the host from site.url, then the current request host. The server rejects a site response without route_policy instead of silently falling back to static routes.

The site plugin loads /api/cms/site once into useCmsSiteConfig() for SSR and client hydration. Preview, redirect, sitemap, and server route builders use the resolved CMS route policy while runtime mode is enabled. Keep site.runtime disabled when the Nuxt configuration is the single route-policy owner.

Preview

Preview mode is enabled unless preview.enabled is false.

GET /api/preview?token=preview-token&resource=article&slug=guides/getting-started&locale=en

The preview endpoint:

  • reads token, resource or resource_type, slug, locale, and additional route params from the query string
  • parses slug with routes.sourceResources when possible
  • fetches article detail when the public article pattern requires category_slug
  • sets the configured preview cookie
  • redirects to the generated public route with _preview=1

useCmsPreview() returns { isPreview, previewToken, exitPreview }. useCmsPreviewToken() is available for lower-level integrations.

Revalidate

The revalidate endpoint is enabled unless revalidate.enabled is false. It expects a raw JSON CMS webhook payload signed with @stackonward/cms-client/webhook HMAC verification.

POST /api/_revalidate
X-Webhook-Signature: sha256=...
Content-Type: application/json
{
  "event": "article.published",
  "resource_type": "article",
  "locale": "en",
  "slug": "getting-started",
  "category_slug": "guides",
  "route_params": {
    "category_slug": "guides",
    "slug": "getting-started"
  }
}

The endpoint builds index, category, and resource paths with the configured route policy, then removes matching Nitro route cache entries.

Sitemap

There are two sitemap integration surfaces:

  • GET sitemap.sourcePath?locale=en returns route-policy-generated sitemap entries for a single locale.
  • sitemap.enabled: true hooks into @nuxtjs/sitemap and pushes CMS entries for sitemap.locales.

CMS sitemap entries can include resource types, route params, hreflang alternatives, images, last_mod, change_freq, and priority. The package converts them into Nuxt sitemap entries with public paths generated from the route policy.

Composables

All runtime composables are auto-imported.

Composable Purpose
useCmsClient() Returns a CmsClient configured from public CMS runtime config and preview token state.
useCmsFetch<T>(path, options) SSR fetches CMS directly and CSR fetches through content.cmsProxyPath.
useArticle(slug) Fetches article detail, related articles, SEO meta, Open Graph meta, Twitter meta, and JSON-LD.
useArticleList(params) Fetches article lists through CmsClient.getArticles.
useCmsArticleCollection(params) Fetches the normalized article collection endpoint with category, search, and pagination support.
useCategories() Fetches categories through CmsClient.getCategories.
useCmsCategories() Reads preloaded category data and exposes category lookup/path helpers.
useAuthor(slug) Fetches author detail and author articles.
useCmsPreviewToken() Reads the preview token in SSR and CSR contexts.
useCmsPreview() Exposes preview state and exit behavior.
useCmsRoutes() Exposes the resolved route policy and route builder.
useCmsSiteConfig() Reads the runtime CMS site configuration loaded during app setup.
useBlogSeo(options) Applies list-page SEO meta.
useLocalizedResourceSeo(options) Applies canonical, alternate, social, and structured SEO for a localized resource.
useHreflangLinks(resource, builder) Injects alternate links from resource locales with caller-defined URL building.

Compatibility

  • Nuxt >=3.15.0
  • @stackonward/cms-client ^0.0.3
  • @stackonward/section-renderer-vue ^0.0.1
  • Vue runtime supplied by Nuxt
  • Node.js version should satisfy the consuming Nuxt application's runtime requirements

License

MIT

Related Packages

@stackonward/nuxt-layer-base

De-branded Nuxt layer foundation: api-client wiring, session/token store, SEO an...

754
@stackonward/composables

Framework-agnostic Vue composables — headless technical capabilities, no styling...

372
@stackonward/onex-identity-nuxt

Nuxt BFF integration for OneX opaque identity sessions

316
@stackonward/google-tag-manager-nuxt

Consent-aware Google Tag Manager transport and analytics composition module for...

1,601
@stackonward/analytics-nuxt

Provider-neutral Nuxt analytics module with consent, SPA views, composables, dir...

1,451

Version History

Version Released Vue License
0.0.4 ^3.0 MIT
0.0.3 ^3.0 MIT
0.0.2 ^3.0 MIT
0.0.1 ^3.0 MIT