Communitygithub.com

Nuvraxis/nuvraxis-plugins

Règles de production pour les applications Next.js 16 App Router chez Nuvraxis — limites Serveur/Client, Composants Cache (« use cache », cacheLife, cacheTag, updateTag), actions serveur, gestionnaires de route, variables d'env, instrumentation, output standalone et la route /api/health. À utiliser lorsque le projet contient « next » dans package.json, un répertoire app/ ou src/app/, next.config.ts, proxy.ts, instrumentation.ts, ou des fichiers nommés page.tsx, layout.tsx, route.ts, loading.tsx, error.tsx.

Qu'est-ce que nuvraxis-plugins ?

Ce skill définit une collection de règles de production pour les applications Next.js 16 App Router développées chez Nuvraxis. Il complète le skill intégré `next-best-practices` avec des directives spécifiques à l'infrastructure et au style de l'entreprise. Il couvre notamment les Composants Cache avec `"use cache"`, `cacheLife` et `cacheTag`, ainsi que `updateTag` pour les invalidations en écriture dans les actions serveur. Les règles insistent sur la séparation stricte entre composants serveur (par défaut) et client (`"use client"` limité aux feuilles avec état ou événements), la validation des entrées avec `valibot`, l'autorisation systématique dans les actions serveur, et la gestion des erreurs via `error.tsx`, `loading.tsx` et `not-found.tsx`. Le skill précise aussi la configuration `output: "standalone"`, les itinéraires typés, l'absence de `next lint` au profit de Biome, l'utilisation de `instrumentation.ts` pour OpenTelemetry et `onRequestError`, et des règles pour les variables d'environnement (`NEXT_PUBLIC_*` uniquement pour les constantes de build) et les feuilles de style (SCSS BEM). Il inclut des références vers la documentation officielle Next.js et des fichiers locaux pour des détails supplémentaires sur la mise en cache, l'auto-hébergement et l'observabilité. Le skill est conçu pour être utilisé avec Claude Code et d'autres outils d'IA agentiques qui naviguent les fichiers du projet.

Compatible avec✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/Nuvraxis/nuvraxis-plugins/tree/HEAD/plugins/nuvraxis-frontend/skills/nextjs-production

Demander à votre IA préférée

Ouvre une nouvelle conversation avec cette compétence d'agent déjà préchargée.

Documentation

Next.js en production

À utiliser pour tout code dans une application Next.js 16 App Router. Les règles spécifiques à la sécurité (authentification dans les actions, CSP, en-têtes, taint) se trouvent dans nextjs-security ; les règles de conteneur dans docker-nextjs. Le skill intégré next-best-practices de Claude Code couvre en profondeur les conventions générales de fichiers, les métadonnées, l'optimisation des images et des polices ; ce skill n'ajoute que ce qui est spécifique à notre façon de construire et de livrer.

Base de référence : Next 16.4, React 19.3, Turbopack (par défaut pour dev et build), cacheComponents: true avec partialPrefetching: true, output: "standalone", typedRoutes: true. Le next.config.ts du modèle est la source de vérité.

Règles

  1. Composants serveur par défaut ; "use client" uniquement pour l'état, les effets, les API navigateur ou les gestionnaires d'événements. Placez la directive sur la plus petite feuille qui en a besoin. Ne l'ajoutez pas parce qu'un fichier importe nuvui : les parties avec état de nuvui portent leur propre directive (voir le skill nuvui, rules/server-components.md).

    // Erreur : toute la page est client à cause d'un seul gestionnaire
    "use client";
    export default function Page() { … <Select onValueChange={…} /> … }
    
    // Correct : la page reste sur le serveur, le gestionnaire vit dans une feuille
    export default async function Page() {
      const people = await getPeople();
      return <PeopleFilter people={people} />; // people-filter.tsx a "use client"
    }
    

    Les props passées à un composant client doivent être sérialisables : pas de fonctions (sauf les actions serveur), pas d'instances de classe.

  2. Récupérez les données sur le serveur, dans le composant qui en a besoin. Pas de récupération avec useEffect, pas de gestionnaire de route uniquement pour alimenter votre propre page. Dédupliquez par requête avec cache() de React ; mettez en cache entre requêtes avec la règle 3.

  3. Mettez en cache avec "use cache" + cacheLife + cacheTag ; tout le reste est dynamique. Avec les Composants Cache, rien n'est mis en cache sauf si vous le dites, et fetch n'a pas de cache implicite.

    import { cacheLife, cacheTag } from "next/cache";
    
    export async function getInvoice(id: InvoiceId) {
      "use cache";
      cacheLife("minutes");
      cacheTag(`invoice:${id}`);
      return db.invoice.findUnique({ where: { id } });
    }
    

    N'utilisez pas l'ancienne configuration de segment (export const dynamic, revalidate, fetchCache) : elle génère une erreur avec les Composants Cache. Les arguments et les valeurs fermées deviennent partie de la clé de cache, donc passez des ids, pas des objets de requête entiers. Détails, les profils et "use cache: private" : references/caching.md.

  4. Invalidez avec updateTag dans les actions serveur, revalidateTag(tag, "max") ailleurs. updateTag(tag) permet les lectures après écriture et ne fonctionne qu'à l'intérieur d'une action serveur. Depuis un webhook ou un gestionnaire de route, utilisez revalidateTag(tag, "max") (stale-while-revalidate) ou revalidateTag(tag, { expire: 0 }). La version à un argument revalidateTag(tag) est dépréciée.

  5. Enveloppez les données au moment de la requête dans <Suspense>, sinon la build échoue. cookies(), headers(), searchParams, connection() et les E/S non mises en cache en dehors d'une limite Suspense arrêtent le pré-rendu avec « uncached or runtime data during prerendering ». Donnez-lui une limite avec un squelette de fallback, mettez-le en cache, ou (layout racine uniquement, voir règle 14) marquez le blocage de la route avec export const instant = false. Tous les params, searchParams, cookies(), headers() sont asynchrones : attendez-les avec await.

  6. Chaque action serveur valide ses entrées et vérifie elle-même l'autorisation. Une action serveur est un point de terminaison POST public, quelle que soit la page sur laquelle elle est écrite. Analysez FormData avec le schéma de typescript-production (valibot), puis autorisez, puis muterez, puis updateTag. Retournez un résultat typé pour les échecs attendus ; ne levez une exception que pour les bugs. L'ensemble complet des règles se trouve dans nextjs-security.

    "use server";
    export async function renameProject(_: State, form: FormData): Promise<State> {
      const session = await requireSession();                  // 401 si absent
      const input = v.safeParse(RenameProject, Object.fromEntries(form));
      if (!input.success) return { ok: false, errors: flatten(input.issues) };
      await assertCanEdit(session, input.output.projectId);    // 403 si non autorisé
      await db.project.update(…);
      updateTag(`project:${input.output.projectId}`);
      return { ok: true };
    }
    
  7. Les gestionnaires de route sont destinés aux autres clients (webhooks, mobile, santé), pas à vos propres pages. Placez-les sous app/api/. Validez le corps comme une action, retournez Response.json(...), et définissez les codes de statut intentionnellement.

  8. Chaque application a GET /api/health, dynamique et sans dépendance. Le HEALTHCHECK Docker et les sondes Kubernetes l'appellent. Il doit répondre sans toucher à la base de données, afin qu'une dépendance lente ne redémarre pas chaque pod. await connection() l'empêche d'être pré-rendu en un fichier statique. Il se trouve dans le modèle à src/app/api/health/route.ts ; proxy.ts exclut /api/health de son filtre.

  9. error.tsx, loading.tsx et not-found.tsx à la racine, et par segment là où l'expérience utilisateur diffère. error.tsx est un composant client ; enregistrez via onRequestError de instrumentation.ts, affichez une réessai avec reset, jamais le message d'erreur. Appelez notFound() pour les enregistrements manquants au lieu de rendre un état vide.

  10. NEXT_PUBLIC_* est intégré à la build ; tout le reste est lu à l'exécution sur le serveur. Une seule image est promue de la branche principale à la production inchangée, donc une valeur NEXT_PUBLIC_ est la même dans tous les environnements. Mettez-y uniquement des constantes de build (nom de l'application, un DSN Sentry public identique partout). La configuration par environnement (URLs API, feature flags, secrets) est un process.env.X côté serveur, lu dans un composant serveur ou une action, et passé au client sous forme de props si nécessaire. Validez l'environnement une fois dans src/env.ts (valibot) et importez de là. N'utilisez jamais la clé env dans next.config.ts : elle est incorporée dans les bundles clients.

  11. Marquez les modules serveur uniquement avec import "server-only". Tout ce qui lit des secrets, parle à la base de données ou importe un SDK avec des identifiants. Une importation cliente de ce module échoue alors à la build au lieu de fuiter.

  12. after() pour le travail qui ne doit pas retarder la réponse (journaux d'audit, analytics, préchauffage du cache). Lisez cookies()/headers() avant d'appeler after, pas à l'intérieur. Il s'exécute dans le même processus, donc le pod a besoin de son délai de grâce SIGTERM (le chart définit terminationGracePeriodSeconds).

  13. Instrumentez avec src/instrumentation.ts : registerOTel + onRequestError. OpenTelemetry via @vercel/otel, exportateur configuré par les variables d'environnement standard OTEL_EXPORTER_OTLP_* à l'exécution. Voir references/observability.md.

  14. Gardez output: "standalone" et n'importez jamais depuis l'extérieur du workspace. Le runner Docker copie uniquement .next/standalone, .next/static et public. Dans le monorepo, server.js atterrit à .next/standalone/apps/<app>/server.js ; la racine du workspace est trouvée à partir de pnpm-lock.yaml, donc ne définissez pas outputFileTracingRoot ou turbopack.root sauf si la build prévient. Détails de l'auto-hébergement (multi-réplicas, clés d'actions serveur, deploymentId) : references/self-hosting.md.

  15. Le layout racine lit le nonce CSP, donc l'application s'affiche par requête. Le proxy.ts du modèle définit un CSP basé sur un nonce et src/app/layout.tsx a export const instant = false. C'est un compromis délibéré : les nonces et les shells statiques pré-rendus ne peuvent pas coexister, et pour les applications métier connectées, un CSP strict l'emporte. La mise en cache des données avec "use cache" fonctionne toujours. Ne supprimez aucune des deux parties sans lire la règle 4 de nextjs-security.

  16. Styles : SCSS BEM global, importé par le composant. Turbopack compile Sass avec le package sass ; sassOptions.loadPaths: ["src/styles"] rend @use "abstracts" accessible depuis n'importe quelle profondeur. Pas d'imports ~, pas de sassOptions.functions. Règles dans scss-bem.

  17. Images via next/image, polices via next/font. sharp est fourni avec Next pour l'optimiseur ; l'image du runner n'a besoin d'aucun package supplémentaire. Les images distantes nécessitent images.remotePatterns avec un nom d'hôte exact.

  18. Vérifiez la taille du bundle avec pnpm next analyze (l'analyseur de Turbopack ; @next/bundle-analyzer est réservé à webpack). Chargez paresseusement les widgets clients lourds (éditeur nuvui, cartes, graphiques sous la ligne de flottaison) avec next/dynamic.

  19. Utilisez les routes typées et les types générés. typedRoutes: true vérifie <Link href> ; PageProps<"/invoices/[id]"> et LayoutProps sont globaux après next typegen (exécuté automatiquement par next dev/next build). N'écrivez pas manuellement les types params.

  20. Pas de next lint. Il a été supprimé dans la version 16. Biome se charge du lint (voir biome) ; TypeScript vérifie avec tsc --noEmit par package.

Vérifier

pnpm typecheck
pnpm lint
pnpm build                      # turbo run build : échoue en cas d'erreurs de pré-rendu, d'erreurs de type, d'erreurs Sass
pnpm --filter <app> start &     # puis :
curl -fsS localhost:3000/api/health

Sources

Individual skills in this repo

This repo contains 4 individual skills — each has its own dedicated page.

Nuvraxis/nuvraxis-plugins

>- Biome 2.5 setup and rules for Nuvraxis monorepos — root biome.json with pinned $schema, VCS ignore, formatter settings, the recommended preset with a11y and the react/next domains, nursery policy, organize imports, overrides, nested per-package configs ("extends": "//"), biome check --write locally, biome ci in CI, VS Code settings, and migrating from ESLint/Prettier. Use when the repo has biome.json or biome.jsonc, @biomejs/biome in package.json, .eslintrc*/eslint.config.*/.prettierrc* to migrate, or when fixing lint and formatting errors.

Nuvraxis/nuvraxis-plugins

>- Dockerfile rules for Next.js standalone apps in a pnpm + Turborepo monorepo — multi-stage build (turbo prune → pnpm fetch/offline install → turbo build → minimal runner), pinned Node 26 Alpine by digest, checksum-verified pnpm binary, non-root uid 1001, read-only root filesystem with a writable .next/cache, HEALTHCHECK on /api/health, build args only for NEXT_PUBLIC_* values, BuildKit secrets and cache mounts, multi-arch, OCI labels and .dockerignore. Use when the repo has a Dockerfile, .dockerignore, compose file, or next.config with output "standalone", or when asked to containerise, shrink, harden or debug an image.

Nuvraxis/nuvraxis-plugins

>- GitHub Actions conventions for Nuvraxis Next.js apps — exactly three workflows: pr.yaml (every PR to any branch: Biome, stylelint, typecheck/test/build with turbo --affected, Docker build + health check, helm lint + kubeconform; publishes nothing), main.yaml (push to main: one multi-arch image to GHCR tagged sha-SHORTSHA and main, provenance + SBOM, gha cache), release.yaml (tag vX.Y.Z: verify on main, retag the existing image without rebuilding, package and push the Helm chart to OCI, GitHub Release with chart, digest and SBOM). Minimal permissions per job, GITHUB_TOKEN only, pinned action majors. Use when editing .github/workflows/*, adding a CI step, or debugging a failed run or release.

Nuvraxis/nuvraxis-plugins

>- Helm chart rules for Nuvraxis Next.js apps — one chart per app in charts/ (named after the app), published to oci://ghcr.io/nuvraxis/charts and synced by Argo CD; Chart.yaml version/appVersion set only by release.yaml; Deployment with startup/liveness/readiness probes on /api/health, non-root read-only security context, emptyDir for .next/cache, ConfigMap + existing Secret via envFrom, Service, Ingress with cert-manager, HPA, PDB, ServiceAccount, topology spread; no Helm hooks; helm lint --strict + kubeconform. Use when the repo has charts/, Chart.yaml, values*.yaml, templates/*.yaml with Helm syntax, or an Argo CD Application, or when asked to deploy, scale, expose or configure the app on Kubernetes.

Skills associés