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

@contensis/contensis-for-councils

v2.4.1-beta.2

Published

A single React codebase that powers multiple UK council websites from the [Contensis](https://www.contensis.com/) CMS. One application serves many tenant sites — each driven by its own Contensis project and per-site configuration, and each deployed as

Readme

Contensis for Councils

A single React codebase that powers multiple UK council websites from the Contensis CMS. One application serves many tenant sites — each driven by its own Contensis project and per-site configuration, and each deployed as its own Contensis block.

Built on @zengenti/contensis-react-base (CRB) with server-side rendering, the Canvas and Forms packages, and full English / Welsh bilingual support (including Welsh-first sites that serve Welsh at the site root).

🧩 Tech stack

  • React 18 + TypeScript (strict)
  • @zengenti/contensis-react-base v4 — routing, search, SSR, Redux + sagas
  • Styled Components for styling (BEM class names for targeting)
  • @contensis/canvas-react for rich content, @contensis/forms for forms
  • Webpack build via the crb CLI; Express-backed SSR server
  • Jest for unit tests; ESLint + Prettier
  • Docker + GitLab CI/CD for block deployment

Requires Node 18 and a modern npm (7+).

🔌 Getting started

  1. Create a .env file in the project root pointing at the CMS project you want to run (see Environment configuration below).
  2. Install dependencies:
    npm install
    If you hit peer-dependency install errors, remove node_modules and run npm install --legacy-peer-deps.
  3. Start the dev server (HMR + SSR):
    npm run dev

🌎 Environment configuration

The app reads its CMS connection from a root .env file. Because this is a multi-tenant project, the .env is what selects which council site you run locally — point it at a given council's Contensis project and you're running that site.

| Variable | Purpose | | --- | --- | | ALIAS | Contensis environment alias (resolves the CMS/Delivery API URLs) | | PROJECT | Contensis project ID — the council site to serve | | ACCESS_TOKEN | Delivery API access token for that project | | PUBLIC_URL | The site's public URL (used for canonical URLs, sitemap, etc.) |

You can keep multiple environments side by side by adding a suffix — e.g. .env.<name> — and activating it on start/build:

npm --env=<name> run dev

📜 Scripts

| Script | Purpose | | --- | --- | | npm run dev | Development server with hot-reload and SSR | | npm run build | Production build (client + server bundles) | | npm run server | Run the built SSR server (dist/start.js) | | npm run build:server | Build, then start the SSR server (for debugging server-side code) | | npm run analyze | Production build with the webpack bundle analyzer | | npm test | Run the Jest test suite | | npm run test:watch | Jest in watch mode | | npm run test:coverage | Jest with a coverage report | | npm run lint / npm run lint:fix | ESLint check / auto-fix |

🗂️ Project structure

src/app/
├── App.tsx              # Root app component
├── components/          # Reusable UI components (BEM + Styled Components)
├── templates/           # Page templates per content type (article, event,
│                        #   councillor, location, listings, search, home, …)
├── listings/            # Listing/search config shared across listing pages
├── routes/              # Static routes, content-type → template mappings, withEvents
├── locale/              # Bilingual engine: language resolution, routes, slugs
├── siteConfig/          # Per-site config (theme, nav, footer, alerts, search facets)
├── schema/              # Content types, fields, locales, images, logos
├── redux/               # Store wiring (reducers + sagas)
├── styles/              # Theme types and global styles
└── util/                # Mappers, hooks and helpers

Content types are mapped to templates in src/app/routes/contentTypeMappings.ts (article, event, councillor, location, post, the listing pages, etc.).

🌐 Localisation (English / Welsh)

The app is bilingual and supports a dynamic primary language — a Welsh-first council serves Welsh at the site root (/, /chwilio) while English lives under /en-gb, and an English-first council does the reverse. The primary language is resolved at runtime from the Contensis project, not hard-coded.

  • Locales are declared in src/app/schema/locales.ts (path segments, aliases, per-locale route slugs such as searchchwilio).
  • Route registration, language resolution, canonical redirects and localised search facets/filters live under src/app/locale/.
  • The canonical URL form per locale is enforced with a 301 redirect (e.g. /en/search/en-gb/search).

🚀 Multi-tenancy & deployment

Each council site is a separate Contensis block deployed by GitLab CI. The shared sandbox/demo environment is gov/website; client sites are defined one file per council under .gitlab-ci/.

Releases are driven by the commit title on master (vX.Y.Z for a full release to all sites, vX.Y.Z-beta for a beta to the demo and opted-in sites). Routine master commits build but deploy nothing.

See docs/ci-cd.md for the full pipeline: branches, releases, the image-tagging model, onboarding a new council, and the per-job reference.

🍃 Contensis Delivery API

When writing backing code that calls the Delivery API, prefer the helpers exported from @zengenti/contensis-react-base/util (see src/app/util/contensisDeliveryClient.ts).

📝 Conventions

  • Commits follow Conventional Commits — e.g. feat: header component, fix(search): ….
  • Styling uses Styled Components; element class names follow the BEM (Block, Element, Modifier) convention.
  • TypeScript runs in strict mode; add explicit types and CMS-data mappers.

📚 Further docs