Communitygithub.com

Nuvraxis/nuvraxis-plugins

Nuvraxis における Next.js 16 App Router アプリケーションのプロダクションルール — サーバー/クライアントコンポーネントの境界、キャッシュコンポーネント("use cache"、cacheLife、cacheTag、updateTag)、Server Actions、ルートハンドラ、環境変数処理、インストルメンテーション、output standalone、/api/health ルートをカバーします。package.json に "next" がある場合、app/ または src/app/ ディレクトリ、next.config.ts、proxy.ts、instrumentation.ts、または page.tsx、layout.tsx、route.ts、loading.tsx、error.tsx ファイルが存在するプロジェクトで使用します。

nuvraxis-plugins とは?

このスキルは、Nuvraxis が Next.js 16 App Router アプリケーションをプロダクションで構築・出荷するための具体的なルールセットを提供します。サーバーコンポーネントをデフォルトとし、状態やブラウザAPIが必要な場合のみ `"use client"` を使用する境界設定や、`"use cache"`、`cacheLife`、`cacheTag` を利用した明示的なデータキャッシュ戦略、Server Actions における入力検証と認可の徹底、`updateTag` による読み取り後書き込みの整合性確保など、Next.js 16 の新機能を最大限に活用する方法を規定しています。また、`output: "standalone"` によるセルフホスティング、`instrumentation.ts` を用いた OpenTelemetry トレーシング、動的かつ依存関係のない `/api/health` エンドポイント、ビルド時に埋め込まれる `NEXT_PUBLIC_*` 環境変数とランタイムに読み込まれるサーバーサイド環境変数の区別など、実運用で重要な設定をカバーしています。このスキルは、Claude Code、Cursor、Codex などの AI エージェントが Nuvraxis の Next.js プロジェクトでコードを生成・レビューする際に、一貫性とベストプラクティスを守るために使用されます。

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

お気に入りのAIに質問する

このエージェントスキルを事前に読み込んだ状態で新しいチャットを開きます。

ドキュメント

Next.js プロダクション運用

Next.js 16 App Router アプリのコードに使用します。セキュリティ固有のルール(アクション内の認証、CSP、ヘッダー、taint)は nextjs-security に、コンテナのルールは docker-nextjs にあります。Claude Code のビルトイン next-best-practices スキルはファイル規則、メタデータ、画像・フォント最適化を詳細にカバーしています。このスキルでは、Nuvraxis での構築・出荷方法に固有のルールのみを追加します。

基準: Next 16.4、React 19.3、Turbopack(dev および build のデフォルト)、cacheComponents: true(partialPrefetching: true 付き)、output: "standalone"、typedRoutes: true。テンプレートの next.config.ts が信頼できる情報源です。

ルール

  1. サーバーコンポーネントをデフォルトとし、"use client" は状態、エフェクト、ブラウザAPI、またはイベントハンドラが必要な場合のみ使用する。 ディレクティブは、それが本当に必要な最小のリーフに配置します。ファイルが nuvui をインポートしているからといって追加してはいけません。nuvui のステートフルな部分は独自のディレクティブを持っています(nuvui スキール、rules/server-components.md を参照)。

    // 誤り: 1つのハンドラのためにページ全体がクライアントになる
    "use client";
    export default function Page() { … <Select onValueChange={…} /> … }
    
    // 正しい: ページはサーバーに残り、ハンドラはリーフにある
    export default async function Page() {
      const people = await getPeople();
      return <PeopleFilter people={people} />; // people-filter.tsx に "use client" がある
    }
    

    クライアントコンポーネントに渡すプロパティはシリアライズ可能でなければなりません。関数(Server Actions を除く)やクラスインスタンスは許可されません。

  2. データを必要とするコンポーネント内で、サーバーサイドでフェッチする。 useEffect によるフェッチや、単に自分のページにデータを供給するためのルートハンドラは使用しません。リクエストごとの重複排除には React の cache() を使用し、リクエスト間のキャッシュにはルール3を使用します。

  3. "use cache" + cacheLife + cacheTag でキャッシュする。それ以外はすべて動的とする。 キャッシュコンポーネントでは、明示的に指定しない限り何もキャッシュされず、fetch に暗黙のキャッシュはありません。

    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 } });
    }
    

    古いセグメント設定(export const dynamic、revalidate、fetchCache)は使用しないでください。キャッシュコンポーネントではエラーになります。引数とクロージャでキャプチャされた値がキャッシュキーの一部となるため、リクエストオブジェクト全体ではなく ID を渡します。詳細、プロファイル、および "use cache: private" については、references/caching.md を参照してください。

  4. Server Actions 内では updateTag で、それ以外では revalidateTag(tag, "max") で無効化する。 updateTag(tag) は「読み取り後書き込み」の整合性を提供し、Server Actions 内でのみ動作します。Webhook やルートハンドラからは revalidateTag(tag, "max")(stale-while-revalidate)または revalidateTag(tag, { expire: 0 }) を使用します。1引数の revalidateTag(tag) は非推奨です。

  5. リクエスト時にしか確定しないデータは <Suspense> でラップする。そうしないとビルドが失敗する。 cookies()、headers()、searchParams、connection()、およびキャッシュされていない I/O を Suspense 境界外で使用すると、「プリレンダリング中にキャッシュされていないデータまたはランタイムデータ」というエラーでプリレンダリングが停止します。スケルトンフォールバック付きの境界を設定するか、キャッシュするか、または(ルートレイアウトのみ。ルール14を参照)export const instant = false でルートをブロッキングにマークします。params、searchParams、cookies()、headers() はすべて非同期です。await してください。

  6. すべての Server Action は、自身で入力の検証と認可のチェックを行う。 Server Action は、どのページに書かれていても公開 POST エンドポイントです。FormData は typescript-production(valibot)のスキーマでパースし、認可し、ミューテーションし、updateTag します。期待される失敗には型付きの結果を返し、バグの場合のみスローします。完全なルールセットは nextjs-security にあります。

    "use server";
    export async function renameProject(_: State, form: FormData): Promise<State> {
      const session = await requireSession();                  // 不在時は 401
      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
      await db.project.update(…);
      updateTag(`project:${input.output.projectId}`);
      return { ok: true };
    }
    
  7. ルートハンドラは、他のクライアント(Webhook、モバイル、ヘルスチェック)向けであり、自分のページ向けではない。 app/api/ 配下に配置します。アクションと同様にボディを検証し、Response.json(...) を返し、ステータスコードを意図的に設定します。

  8. すべてのアプリに動的で依存関係のない GET /api/health を設置する。 Docker の HEALTHCHECK と Kubernetes のプローブがこれを叩きます。データベースにアクセスせずに応答する必要があるため、遅い依存関係があってもすべての Pod が再起動されることはありません。await connection() により、静的ファイルとしてプリレンダリングされることを防ぎます。テンプレートの src/app/api/health/route.ts にあり、proxy.ts は /api/health をマッチャーから除外します。

  9. ルートレベル、および UX が異なるセグメントごとに error.tsx、loading.tsx、not-found.tsx を配置する。 error.tsx はクライアントコンポーネントです。instrumentation.ts の onRequestError でログ出力し、reset でリトライできるように表示します。エラーメッセージは絶対に表示しません。空の状態をレンダリングする代わりに、レコードが見つからない場合は notFound() を呼び出します。

  10. NEXT_PUBLIC_* はビルド時に埋め込まれ、それ以外はランタイムにサーバー上で読み込まれる。 1つのイメージが変更されずに main からプロダクションに昇格するため、NEXT_PUBLIC_ の値はすべての環境で同じです。ビルド時の定数(アプリ名、すべての環境で同じパブリック Sentry DSN)のみをそこに配置します。環境ごとの設定(API URL、フィーチャーフラグ、シークレット)はサーバーサイドの process.env.X であり、サーバーコンポーネントまたはアクション内で読み取り、必要に応じてプロパティとしてクライアントに渡します。環境変数は src/env.ts(valibot)で1回検証し、そこからインポートします。next.config.ts の env キーは使用しないでください。クライアントバンドルにインライン化されます。

  11. サーバー専用モジュールには import "server-only" を記述する。 シークレットを読み取るもの、データベースにアクセスするもの、認証情報を持つ SDK をインポートするものなど。クライアントがこれをインポートすると、情報漏洩ではなくビルドエラーになります。

  12. after() はレスポンスを遅らせるべきでない処理(監査ログ、分析、キャッシュウォームアップ)に使用する。 after を呼び出す前に cookies()/headers() を読み取り、after 内では読み取りません。同じプロセス内で実行されるため、Pod は SIGTERM の猶予期間を必要とします(チャートで terminationGracePeriodSeconds を設定)。

  13. src/instrumentation.ts で registerOTel + onRequestError によりインストルメンテーションを行う。 @vercel/otel による OpenTelemetry、エクスポーターはランタイムの標準 OTEL_EXPORTER_OTLP_* 環境変数で設定します。references/observability.md を参照してください。

  14. output: "standalone" を維持し、ワークスペースの外部からインポートしない。 Docker ランナーは .next/standalone、.next/static、public のみをコピーします。モノレポでは、server.js は .next/standalone/apps/<app>/server.js に配置されます。ワークスペースルートは pnpm-lock.yaml から検出されるため、ビルドが警告しない限り outputFileTracingRoot や turbopack.root は設定しないでください。セルフホスティングの詳細(マルチレプリカ、Server Action キー、deploymentId)については、references/self-hosting.md を参照してください。

  15. ルートレイアウトは CSP nonce を読み取るため、アプリはリクエストごとにレンダリングされる。 テンプレートの proxy.ts は nonce ベースの CSP を設定し、src/app/layout.tsx には export const instant = false があります。これは意図的なトレードオフです。nonce とプリレンダリングされた静的シェルは共存できず、ログイン済みのビジネスアプリでは厳格な CSP が優先されます。"use cache" によるデータキャッシュは引き続き機能します。nextjs-security のルール4を読まずにこれらのいずれかを削除しないでください。

  16. スタイル: グローバル BEM SCSS、コンポーネントがインポートする。 Turbopack は sass パッケージで Sass をコンパイルします。sassOptions.loadPaths: ["src/styles"] により、任意の深さから @use "abstracts" が機能します。~ インポートや sassOptions.functions は使用しません。ルールは scss-bem にあります。

  17. 画像は next/image、フォントは next/font を使用する。 sharp は最適化のために Next に同梱されています。ランナーイメージに追加のパッケージは必要ありません。リモート画像には、正確なホスト名を指定した images.remotePatterns が必要です。

  18. pnpm next analyze でバンドルサイズをチェックする(Turbopack のアナライザー。@next/bundle-analyzer は webpack 専用)。重いクライアントウィジェット(nuvui エディター、マップ、スクロールしないと見えないチャート)は next/dynamic で遅延読み込みします。

  19. 型付きルートと生成された型を使用する。 typedRoutes: true は <Link href> をチェックします。PageProps<"/invoices/[id]"> と LayoutProps は、next typegen(next dev/next build で自動実行)の後にグローバルになります。params の型を手書きしないでください。

  20. next lint は使用しない。 16 で削除されました。Biome がリンターとして機能します(biome を参照)。TypeScript はパッケージごとに tsc --noEmit でチェックします。

確認

pnpm typecheck
pnpm lint
pnpm build                      # turbo run build: プリレンダリングエラー、型エラー、Sass エラーで失敗
pnpm --filter <app> start &     # その後:
curl -fsS localhost:3000/api/health

ソース

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.

関連スキル