nextjs-15 by prowler-cloud/prowler
npx skills add https://github.com/prowler-cloud/prowler --skill nextjs-15app/
├── layout.tsx # 根布局(必需)
├── page.tsx # 首页(/)
├── loading.tsx # 加载界面(Suspense)
├── error.tsx # 错误边界
├── not-found.tsx # 404 页面
├── (auth)/ # 路由分组(不影响 URL)
│ ├── login/page.tsx # /login
│ └── signup/page.tsx # /signup
├── api/
│ └── route.ts # API 处理器
└── _components/ # 私有文件夹(不参与路由)
// 无需指令 - 默认异步
export default async function Page() {
const data = await db.query();
return <Component data={data} />;
}
// app/actions.ts
"use server";
import { revalidatePath } from "next/cache";
import { redirect } from "next/navigation";
export async function createUser(formData: FormData) {
const name = formData.get("name") as string;
await db.users.create({ data: { name } });
revalidatePath("/users");
redirect("/users");
}
// 用法
<form action={createUser}>
<input name="name" required />
<button type="submit">创建</button>
</form>
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
// 并行
async function Page() {
const [users, posts] = await Promise.all([
getUsers(),
getPosts(),
]);
return <Dashboard users={users} posts={posts} />;
}
// 使用 Suspense 流式传输
<Suspense fallback={<Loading />}>
<SlowComponent />
</Suspense>
// app/api/users/route.ts
import { NextRequest, NextResponse } from "next/server";
export async function GET(request: NextRequest) {
const users = await db.users.findMany();
return NextResponse.json(users);
}
export async function POST(request: NextRequest) {
const body = await request.json();
const user = await db.users.create({ data: body });
return NextResponse.json(user, { status: 201 });
}
// middleware.ts(根目录)
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
export function middleware(request: NextRequest) {
const token = request.cookies.get("token");
if (!token && request.nextUrl.pathname.startsWith("/dashboard")) {
return NextResponse.redirect(new URL("/login", request.url));
}
return NextResponse.next();
}
export const config = {
matcher: ["/dashboard/:path*"],
};
// 静态
export const metadata = {
title: "我的应用",
description: "描述",
};
// 动态
export async function generateMetadata({ params }) {
const product = await getProduct(params.id);
return { title: product.name };
}
import "server-only";
// 如果在客户端组件中导入,将会报错
export async function getSecretData() {
return db.secrets.findMany();
}
每周安装量
82
代码仓库
GitHub 星标数
13.5K
首次出现
2026年1月21日
安全审计
安装于
opencode74
codex71
gemini-cli70
cursor67
github-copilot64
claude-code64
app/
├── layout.tsx # Root layout (required)
├── page.tsx # Home page (/)
├── loading.tsx # Loading UI (Suspense)
├── error.tsx # Error boundary
├── not-found.tsx # 404 page
├── (auth)/ # Route group (no URL impact)
│ ├── login/page.tsx # /login
│ └── signup/page.tsx # /signup
├── api/
│ └── route.ts # API handler
└── _components/ # Private folder (not routed)
// No directive needed - async by default
export default async function Page() {
const data = await db.query();
return <Component data={data} />;
}
// app/actions.ts
"use server";
import { revalidatePath } from "next/cache";
import { redirect } from "next/navigation";
export async function createUser(formData: FormData) {
const name = formData.get("name") as string;
await db.users.create({ data: { name } });
revalidatePath("/users");
redirect("/users");
}
// Usage
<form action={createUser}>
<input name="name" required />
<button type="submit">Create</button>
</form>
// Parallel
async function Page() {
const [users, posts] = await Promise.all([
getUsers(),
getPosts(),
]);
return <Dashboard users={users} posts={posts} />;
}
// Streaming with Suspense
<Suspense fallback={<Loading />}>
<SlowComponent />
</Suspense>
// app/api/users/route.ts
import { NextRequest, NextResponse } from "next/server";
export async function GET(request: NextRequest) {
const users = await db.users.findMany();
return NextResponse.json(users);
}
export async function POST(request: NextRequest) {
const body = await request.json();
const user = await db.users.create({ data: body });
return NextResponse.json(user, { status: 201 });
}
// middleware.ts (root level)
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
export function middleware(request: NextRequest) {
const token = request.cookies.get("token");
if (!token && request.nextUrl.pathname.startsWith("/dashboard")) {
return NextResponse.redirect(new URL("/login", request.url));
}
return NextResponse.next();
}
export const config = {
matcher: ["/dashboard/:path*"],
};
// Static
export const metadata = {
title: "My App",
description: "Description",
};
// Dynamic
export async function generateMetadata({ params }) {
const product = await getProduct(params.id);
return { title: product.name };
}
import "server-only";
// This will error if imported in client component
export async function getSecretData() {
return db.secrets.findMany();
}
Weekly Installs
82
Repository
GitHub Stars
13.5K
First Seen
Jan 21, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
opencode74
codex71
gemini-cli70
cursor67
github-copilot64
claude-code64
Vue 3 调试指南:解决响应式、计算属性与监听器常见错误
11,900 周安装