Roteamento
No Angular, rotas são configuradas explicitamente em TypeScript. No Next.js, a estrutura de pastas dentro de app/ é a configuração de rotas. Não há arquivo de rotas separado.
Definição de rotas
Compare como as mesmas rotas são definidas nos dois frameworks:
Angular — configuração explícita
// app-routing.module.ts
const routes: Routes = [
{ path: '', component: HomeComponent },
{ path: 'blog', component: BlogComponent },
{ path: 'blog/:slug', component: PostComponent },
{
path: 'dashboard',
canActivate: [AuthGuard],
children: [
{ path: '', component: DashboardComponent },
{ path: 'settings', component: SettingsComponent },
],
},
{ path: '**', redirectTo: '' },
];Next.js — estrutura de pastas
app/
page.tsx → "/"
blog/
page.tsx → "/blog"
[slug]/
page.tsx → "/blog/meu-post"
dashboard/
layout.tsx → layout de /dashboard e filhos
page.tsx → "/dashboard"
settings/
page.tsx → "/dashboard/settings"
not-found.tsx → 404 (equivale ao path "**")
middleware.ts → canActivate / Guards✓
No Next.js, criar uma pasta com um arquivo page.tsx é suficiente para criar uma rota. Não há nada mais a registrar.
Rotas dinâmicas
O :slug do Angular Router vira uma pasta com colchetes: [slug]. O parâmetro é acessado via prop params (Promise no Next.js 15+).
Angularpost.component.ts
// blog/:slug
@Component({ ... })
export class PostComponent implements OnInit {
post: Post | null = null;
constructor(
private route: ActivatedRoute,
private postService: PostService
) {}
ngOnInit() {
this.route.params.subscribe(params => {
this.postService
.getPost(params['slug'])
.subscribe(post => this.post = post);
});
}
}Next.jsapp/blog/[slug]/page.tsx
// app/blog/[slug]/page.tsx
// params é uma Promise no Next.js 15+
export default async function PostPage({
params,
}: {
params: Promise<{ slug: string }>;
}) {
const { slug } = await params;
const post = await getPost(slug); // busca direto no servidor
return (
<article>
<h1>{post.title}</h1>
<div>{post.content}</div>
</article>
);
}| Angular | Next.js | Padrão de URL |
|---|---|---|
| blog/:slug | blog/[slug]/page.tsx | /blog/meu-post |
| shop/:cat/:id | shop/[cat]/[id]/page.tsx | /shop/roupas/123 |
| docs/** | docs/[...slug]/page.tsx | /docs/a/b/c |
| docs (opcional) | docs/[[...slug]]/page.tsx | /docs ou /docs/a/b |
Navegação com Link
RouterLink vs. componente Link
Angular
<!-- Template Angular -->
<nav>
<a routerLink="/">Home</a>
<a routerLink="/blog">Blog</a>
<a [routerLink]="['/blog', post.slug]">
{{ post.title }}
</a>
</nav>
<!-- RouterLinkActive para classe ativa -->
<a routerLink="/blog" routerLinkActive="active">
Blog
</a>Next.js
// Next.js — componente Link
import Link from "next/link";
export default function Nav() {
return (
<nav>
<Link href="/">Home</Link>
<Link href="/blog">Blog</Link>
<Link href={"/blog/" + post.slug}>
{post.title}
</Link>
</nav>
);
}
// Classe ativa — use usePathname() em Client Componentℹ
No Next.js, para detectar a rota ativa e adicionar uma classe, use o hook
usePathname() de next/navigation em um Client Component. Veja o componente Sidebar.tsx deste projeto como exemplo.Navegação programática
Angularlogin.component.ts
// Navegação programática no Angular
@Component({ ... })
export class LoginComponent {
constructor(private router: Router) {}
onLogin() {
// navegar após login
this.router.navigate(['/dashboard']);
// com query params
this.router.navigate(['/search'], {
queryParams: { q: 'angular' }
});
}
}Next.jsLoginForm.tsx
"use client";
import { useRouter } from "next/navigation";
export default function LoginForm() {
const router = useRouter();
function onLogin() {
// navegar após login
router.push("/dashboard");
// com query params
router.push("/search?q=nextjs");
// voltar
router.back();
}
return <button onClick={onLogin}>Entrar</button>;
}Route Guards vs. Middleware
Os Guards do Angular (CanActivate, CanDeactivate) são equivalentes ao middleware.ts do Next.js, que roda antes de qualquer rota ser processada.
Angularauth.guard.ts
// Route Guard no Angular
@Injectable({ providedIn: 'root' })
export class AuthGuard implements CanActivate {
constructor(
private authService: AuthService,
private router: Router
) {}
canActivate(): boolean {
if (this.authService.isLoggedIn()) {
return true;
}
this.router.navigate(['/login']);
return false;
}
}Next.jsmiddleware.ts (raiz do projeto)
// middleware.ts — na raiz do projeto
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
export function middleware(request: NextRequest) {
const token = request.cookies.get("token");
if (!token) {
return NextResponse.redirect(
new URL("/login", request.url)
);
}
return NextResponse.next();
}
// Aplicar apenas em rotas específicas
export const config = {
matcher: ["/dashboard/:path*"],
};Referência oficial: Layouts and Pages — Next.js Docs ↗