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

@bettercms-ai/nuxt

v0.4.0

Published

BetterCMS for Nuxt: settings from NUXT_PUBLIC_BCMS_*, the read client per request with draft mode, the editor's draft routes, and the page sections server-rendered by BetterCMS.

Readme

@bettercms-ai/nuxt

BetterCMS for Nuxt. Your own components stay your own: they bind a few attributes onto their elements, and every element becomes editable in the BetterCMS visual editor. Pages stay current when content is published.

npm i @bettercms-ai/nuxt
// server/utils/bcms.ts
export const bcms = createBcms({ env: process.env });

// server/plugins/bcms.ts: <html data-bcms-draft> in drafts, <meta name="generator">
export default defineNitroPlugin(bcmsNitroPlugin(bcms));

// plugins/bcms.client.ts: a publish, and the editor's re-render request, refetch the page's data
export default defineNuxtPlugin(() => {
  startBcmsLive({ refresh: () => refreshNuxtData(), src: useRuntimeConfig().public.bcmsLiveUrl });
});

// server/routes/api/draft.get.ts: the path the editor's "Preview on site" opens
export default defineEventHandler((e) => bcms.draftEnable(toWebRequest(e)));

// server/api/post/[slug].get.ts: drafts while the editor previews
export default defineEventHandler(async (e) => (await bcms.client(toWebRequest(e))).getEntry(getRouterParam(e, "slug")!));
<!-- your own markup, bound to its content -->
<script setup>
import { entryAttrs, entryField, imageAttrs, rich } from "@bettercms-ai/nuxt";
const { data: post } = await useFetch("/api/post/hello-world");
</script>
<template>
  <article v-bind="entryAttrs(post)">
    <h1 v-bind="entryField(post, 'title')">{{ post.data.title }}</h1>
    <img v-bind="{ ...imageAttrs(post.data.cover, { sizes: '100vw' }), ...entryField(post, 'cover') }" class="cover" />
    <div v-bind="entryField(post, 'body')" v-html="rich(post.data.body)" />
  </article>
</template>

| Helper | What it binds | |---|---| | fieldAttrs(path, page.fieldStyles) | A page field. It also applies the field's stored style, which turns on the editor's Align, Size and Weight controls. | | entryAttrs(entry) | A collection entry's card. | | entryField(entry, path) | A field of that entry. | | sectionRootAttrs(block) | A section root (its spacing and design). | | sectionColumnAttrs(block) | The section's content column. | | imageAttrs(value, { path, sizes }) | An optimized <img> with a srcset, alt text, the focal point and the field binding. | | rich(value), lines(value), plain(value) | Rich text as HTML, a one-line value, or plain text for attributes. |

Sections

A page built from sections in BetterCMS renders as the hosted renderer draws it, so forms, sliders and tabs work exactly as they do on a BetterCMS-hosted site. Pass the request and the editor's session gets the draft, with every section and value clickable:

// server/api/sections/[slug].get.ts
export default defineEventHandler((e) => bcms.sections(getRouterParam(e, "slug")!, undefined, toWebRequest(e)));
<div v-bcms-sections v-html="sectionsMarkup(sections)" />

Your own sections in the CMS order

A page that draws its own sections can let BetterCMS order them, and draw sections added in the editor between them: name the page's sections (slots, in source order) and loop over sectionItems. npx @bettercms-ai/convert --sections writes this for you.

// server/api/bcms-sections/[slug].get.ts
export default defineEventHandler((e) =>
  bcms.sections(getRouterParam(e, "slug")!, undefined, toWebRequest(e), { slots: String(getQuery(e).slots ?? "").split(",").filter(Boolean) }));
<script setup>
import { sectionItems, vBcmsSections } from "@bettercms-ai/nuxt";
const bcmsSlots = ["hero", "code:features"];
const { data } = await useFetch("/api/bcms-sections/home", { query: { slots: bcmsSlots.join(",") } });
const bcmsSections = computed(() => sectionItems(data.value, bcmsSlots, "home"));
</script>

<template>
  <template v-for="item in bcmsSections" :key="item.key">
    <template v-if="item.slot === 'hero'"><section class="hero" v-bind="item.root">…</section></template>
    <template v-else-if="item.slot === 'code:features'"><div v-bind="item.box"><Features /></div></template>
    <div v-else-if="item.slot === null" data-bcms-rendered="platform" v-bcms-sections v-html="item.html" />
  </template>
</template>

root goes on a section's own root element (its placement's data-bcms-block and style); box on a wrapper when the section is a component. With no answer, every slot renders in source order.

Settings

Options are read first, then NUXT_PUBLIC_BCMS_*, then BCMS_*, the same precedence as every adapter:

| Variable | Purpose | |---|---| | NUXT_PUBLIC_BCMS_API_URL | The API to read from. | | NUXT_PUBLIC_BCMS_WORKSPACE | Your workspace. | | NUXT_PUBLIC_BCMS_PROJECT_ID | Your project. | | BCMS_DRAFT_SECRET | Signs the draft cookie. |

Don't put a page that a draft session can render behind a shared routeRules cache (swr, isr). The draft marker would be cached and served to visitors.

The sections run small inline scripts (forms, sliders and tabs), so a Content-Security-Policy must allow inline scripts.