Communitygithub.com

Nuvraxis/nuvraxis-plugins

Nuvraxis Next.js 16 App Router 应用的生产规则——涵盖 Server/Client 组件边界、缓存组件("use cache"、cacheLife、cacheTag、updateTag)、Server Actions、路由处理、环境变量处理、instrumentation、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 是什么?

此技能为 Next.js 16 App Router 应用提供了全面的生产级规则和最佳实践。它涵盖了核心概念,如默认使用 Server Components,仅在必要时使用 "use client"、使用 "use cache" + cacheLife + cacheTag 进行缓存管理、在 Server Actions 中使用 updateTag 进行失效处理,以及确保请求时数据(cookies、headers、searchParams)被包裹在 <Suspense> 中以避免构建失败。该技能还涉及 Server Actions 的安全验证和授权、专用于外部客户端的路由处理程序、依赖无关的 /api/health 健康检查端点、正确的环境变量处理(NEXT_PUBLIC_* 与运行时环境变量)、通过 instrument.ts 进行可观测性设置、为缩小 Docker 镜像设置 output: "standalone"、样式指南(全局 BEM SCSS 和 next/image)、以及使用 TypedRoutes 和 TypeScript 类型检查。它专为 Nuvraxis 的开发工作流程量身定制,并假设使用 Next 16.4、React 19.3 和 Turbopack。

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

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

Next.js 生产实践

适用于 Next.js 16 App Router 应用中的任何代码。安全相关规则(操作中的认证、CSP、标头、taint)在 nextjs-security 中;容器规则在 docker-nextjs 中。Claude Code 的内置 next-best-practices 技能涵盖了通用文件约定、元数据、图片和字体优化;本技能只补充我们构建和交付方式特有的内容。

基线:Next 16.4、React 19.3、Turbopack(dev 和 build 的默认值)、cacheComponents: true 且 partialPrefetching: true、output: "standalone"、typedRoutes: true。模板的 next.config.ts 是权威来源。

规则

  1. 默认使用 Server Components;仅在需要状态、副作用、浏览器 API 或事件处理程序时使用 "use client"。 将指令放在需要它的最小叶子组件上。不要因为文件导入了 nuvui 就添加它:nuvui 的有状态部分自带指令(参考 nuvui 技能中的 rules/server-components.md)。

    // 错误:整个页面因为一个处理程序变成了客户端组件
    "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"
    }
    

    传递给客户端组件的 props 必须是可序列化的:不能包含函数(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 Action 内部有效。从 webhook 或路由处理程序中,使用 revalidateTag(tag, "max")(stale-while-revalidate)或 revalidateTag(tag, { expire: 0 })。单参数形式 revalidateTag(tag) 已废弃。

  5. 将请求时的数据包裹在 <Suspense> 中,否则构建会失败。 在 Suspense 边界之外的 cookies()、headers()、searchParams、connection() 和未缓存的 I/O 会因“预渲染期间存在未缓存或运行时数据”而停止预渲染。为其提供一个包含骨架屏 fallback 的边界,缓存它,或者(仅根布局,见规则 14)使用 export const instant = false 标记路由为阻塞式。params、searchParams、cookies()、headers() 都是异步的:使用 await。

  6. 每个 Server Action 都必须自行验证输入并检查授权。 Server Action 是一个公共的 POST 端点,无论它写在哪个页面。使用 typescript-production 中的 schema(valibot)解析 FormData,然后授权,接着进行变更,最后调用 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/ 下。像 action 一样验证 body,返回 Response.json(...),并有意设置状态码。

  8. 每个应用都有 GET /api/health,动态且无依赖。 Docker HEALTHCHECK 和 Kubernetes 探针会访问它。它必须在不接触数据库的情况下响应,因此慢速依赖不会导致每个 pod 重启。await connection() 防止它被预渲染为静态文件。它位于模板的 src/app/api/health/route.ts;proxy.ts 在其 matcher 中排除了 /api/health。

  9. 在根目录以及用户体验不同的每个段放置 error.tsx、loading.tsx 和 not-found.tsx。 error.tsx 是一个客户端组件;通过 instrumentation.ts 的 onRequestError 记录日志,显示带有 reset 的重试按钮,绝不显示错误消息。对缺失的记录调用 notFound(),而不是渲染空状态。

  10. NEXT_PUBLIC_* 在构建时被内联;其他所有内容在运行时于服务端读取。 同一个镜像从主环境无需修改即可提升到生产环境,因此 NEXT_PUBLIC_ 值在每个环境中都是相同的。只在那里放置构建时常量(应用名称、一个各环境都相同的公共 Sentry DSN)。每个环境的配置(API URL、特性开关、密钥)是服务端的 process.env.X,在 Server Component 或 action 中读取,并在需要时作为 props 传递给客户端。在 src/env.ts 中使用 valibot 一次性验证环境变量,并从那里导入。绝不要在 next.config.ts 中使用 env 键:它会被内联到客户端 bundle 中。

  11. 使用 import "server-only" 标记仅服务端模块。 任何读取密钥、访问数据库或导入带有凭据的 SDK 的模块。客户端导入它会导致构建失败,而不是泄露信息。

  12. 使用 after() 处理不应延迟响应的任务(审计日志、分析、缓存预热)。在调用 after 之前读取 cookies()/headers(),而不是在它内部。它在同一进程中运行,因此 pod 需要其 SIGTERM 宽限期(chart 设置了 terminationGracePeriodSeconds)。

  13. 使用 src/instrumentation.ts 进行 Instrumentation:registerOTel + onRequestError。 通过 @vercel/otel 实现 OpenTelemetry,导出器由运行时标准的 OTEL_EXPORTER_OTLP_* 环境变量配置。参考 references/observability.md。

  14. 保持 output: "standalone",且绝不从工作区外部导入。 Docker runner 只复制 .next/standalone、.next/static 和 public。在 monorepo 中,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 和预渲染的静态 shell 无法共存,对于登录后的业务应用,严格的 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。 Next 自带用于优化器的 sharp;runner 镜像不需要额外包。远程图片需要带有精确主机名的 images.remotePatterns。

  18. 使用 pnpm next analyze 检查 bundle 大小(Turbopack 的分析器;@next/bundle-analyzer 仅适用于 webpack)。使用 next/dynamic 懒加载重型客户端组件(nuvui 编辑器、地图、折叠线以下的图表)。

  19. 使用类型化路由和生成的类型。 typedRoutes: true 检查 <Link href>;PageProps<"/invoices/[id]"> 和 LayoutProps 在 next typegen 之后全局可用(由 next dev/next build 自动运行)。不要手动编写 params 类型。

  20. 不使用 next lint。 它在 16 版本中被移除了。Biome 负责 lint 检查(参见 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.

相关技能