ngnext

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>
  );
}
AngularNext.jsPadrão de URL
blog/:slugblog/[slug]/page.tsx/blog/meu-post
shop/:cat/:idshop/[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*"],
};