npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@frontic/nuxt

v1.3.0

Published

Nuxt module for Frontic - data fetching composables with smart caching, page routing, and context management

Downloads

1,337

Readme

@frontic/nuxt

Nuxt module for building with the Frontic API and Frontic UI components. Provides auto-imported composables for data fetching with smart caching, page routing, and context management.

Features

  • Smart caching via Pinia Colada - stale-while-revalidate, request deduplication, SSR hydration
  • Type-safe composables - Full TypeScript support with generated types from your Frontic schema
  • Search & filtering - Ready-to-use search state management with filters, sorting, pagination, and infinite scroll
  • Page routing - Dynamic page resolution with automatic redirects and 404 handling
  • Context management - Locale and region switching with cookie persistence
  • Infinite scroll - Bidirectional infinite loading with deep-link support via Pinia Colada's useInfiniteQuery
  • Analytics hooks - Typed frontic:listing:resolved, frontic:search:committed and frontic:page:resolved events for any analytics vendor
  • Built-in proxy - CORS-free API requests through your Nuxt server

Installation

npx nuxi@latest module add @frontic/nuxt

Quick Start

// nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@frontic/nuxt'],
  frontic: {
    contextDomain: 'demo-shop.com',
  },
})

Generate the Frontic client:

npx @frontic/cli generate

Composables

useFronticPage

Dynamic page routing with automatic redirects and 404 handling:

const { page, data, type, block, alternates } = useFronticPage()

useFronticSearch

Full-featured search with filtering, sorting, and pagination:

const { result, state, searchTerm, filterResult, sortResult, loadNext } = useFronticSearch(
  'ProductSearch',
  {},
  {
    filter: {
      select: ['properties.color', 'properties.size'],
      label: { 'properties.color': 'Color' },
    },
    sorting: {
      label: { 'name:asc': 'Name A-Z', 'price.amount:asc': 'Price: Low to High' },
    },
  }
)

useFronticListing

Simple listing access:

// Second argument is the listing's parameters; query options go in the third
const { listing, status, error } = useFronticListing('CategoryProducts', { categoryKey: 'shoes' }, { query: { limit: 10 } })

useFronticBlock

Fetch single blocks (products, categories):

const { block, status, error } = useFronticBlock('ProductCard', 'product-handle')

Every data composable returns status and error alongside its data, plus refresh and refetch.

useFronticTree

Hierarchical menu trees:

const { items, status } = useFronticTree('CategoryNavigation', { depth: 2 })

useFronticContext

Manage locale and region:

const { contexts, current, update } = useFronticContext()
await update({ region: 'de', locale: 'de-DE' })

The selection is stored against a context token, persisted in the fs-context cookie. Every composable resolves that token and sends it — you do not pass it per call — and it is part of every cache key, so a switch re-keys each active query and the new context's content is fetched. contextKey overrides it for one call, contextKey: false opts a call out so it resolves through the domain alone (useful behind a shared cache), and disableContext: true hands token management to you entirely.

Server routes

useFronticClient is a Nuxt app composable and does not run in Nitro. A server/ route uses createFronticServerClient(event), which resolves the context domain from config, the visitor's token from the request's context cookie, and the request URL from the event — and reports failures on the Nitro frontic:fetch:error hook:

// server/api/stock.get.ts
import { createFronticServerClient } from '@frontic/nuxt/server'

export default defineEventHandler(async (event) => {
  const client = createFronticServerClient(event)
  return await client.listing('ProductSearch', {}, { query: { limit: 5 } })
})

The API secret needs no wiring — the module's Nitro plugin attaches it to every Frontic request the server makes. contextDomain: true (read the active i18n locale) cannot resolve here, since there is no i18n instance in Nitro; pass the domain per call in that setup. The module's disableContext is what decides whether the cookie is read here — a per-instance useFronticContext({ disableContext }) override lives inside the Nuxt app, and a server route cannot see it. Pass contextKey explicitly if your app overrides the module setting and also fetches server-side.

Configuration

export default defineNuxtConfig({
  frontic: {
    // Page routing
    contextDomain: 'demo-shop.com',
    redirectOn301: true,
    throwOn404: true,

    // API proxy
    proxy: true, // or '/api/custom-path'
    fetchApiSecret: process.env.FRONTIC_FETCH_SECRET, // only if the project's Fetch API is protected

    // Sitemap
    sitemap: true,

    // Context cookies
    contextCookieName: 'fs-context',
    contextCookieMaxAge: 31536000,

    // Composables
    composables: true, // or ['page', 'search', 'listing', 'block', 'tree', 'context', 'client']

    // UI components (optional)
    componentsPrefix: '',
    componentDir: '@/components/ui',
  },
})

Sitemap

With sitemap: true, requests to /sitemap.xml (and /sitemapN.xml for split sitemaps) on any locale prefix serve the Frontic sitemap for the matching domain — generated from the Pages marked "Visible in Sitemap". Responses carry the upstream ETag and are cached with stale-while-revalidate. When your config declares domains (sitemap: { domains: [...] }, a contextDomain string, or contextDomain: true with i18n locales carrying contextDomain properties), only those domains are served — other hosts get a 404. With no declared domains the route serves any well-formed forwarded host and the module warns at build time. When @nuxtjs/robots is installed, the sitemap is added to robots.txt automatically. Not compatible with @nuxtjs/sitemap yet — with both installed the option is ignored with a warning.

Multi-locale domains

Frontic resolves scope, region and locale from the domain each request carries. Set contextDomain: true to take it from the locale @nuxtjs/i18n currently has active, instead of hardcoding one:

export default defineNuxtConfig({
  modules: ['@frontic/nuxt', '@nuxtjs/i18n'],

  frontic: {
    contextDomain: true,
  },

  i18n: {
    defaultLocale: 'en',
    locales: [
      { code: 'en', contextDomain: 'demo-shop.com' },
      { code: 'de', contextDomain: 'demo-shop.com/de' },
    ],
  },
})

contextDomain on the locale object is a property you add — the module reads it through i18n's localeProperties, and each value must match a domain configured in your Frontic project. The resolved domain is part of every cache key, so locales never share a cached response.

Per call, any composable accepts contextDomain to override it, and useFronticClient({ contextDomain: false }) sends none at all.

Analytics

Listing, search and page events are announced as typed Nuxt hooks, so any vendor can be wired up in one plugin:

export default defineNuxtPlugin((nuxtApp) => {
  nuxtApp.hook('frontic:listing:resolved', (payload) => {
    if (payload.trigger === 'initial') {
      track('view_item_list', { list: payload.listing, count: payload.resultCount })
    }
  })
})

Hooks are client-only and deduplicated per route entry. Payload types are importable from @frontic/nuxt/types when you factor handlers out of the plugin.

TypeScript

Composable typing comes from your generated client (npx @frontic/cli generate): block, listing and tree names, listing parameters, filter and sort fields, and response types all resolve to your project's schema, and invalid names fail the typecheck. Helper types are available from @frontic/nuxt/types:

import type { ResponseOf, ListingQuery, SortString, FronticClient } from '@frontic/nuxt/types'

Documentation

Full documentation at docs.frontic.com

License

MIT