Перейти к содержимому

8. Маршрутизация в Qwik City

Qwik City использует файловую маршрутизацию — структура директорий в src/routes/ напрямую определяет URL-адреса приложения. Этот подход аналогичен Next.js App Router или Remix.

src/routes/
├── index.tsx → /
├── about/
│ └── index.tsx → /about
├── blog/
│ ├── index.tsx → /blog
│ └── [slug]/
│ └── index.tsx → /blog/:slug (динамический)
├── (auth)/ → Группа маршрутов (не влияет на URL)
│ ├── login/
│ │ └── index.tsx → /login
│ └── register/
│ └── index.tsx → /register
└── api/
└── hello/
└── index.ts → /api/hello (API маршрут)

Каждый index.tsx в директории — это страница:

src/routes/about/index.tsx
import { component$ } from '@builder.io/qwik';
import type { DocumentHead } from '@builder.io/qwik-city';
export default component$(() => {
return (
<main>
<h1>О нас</h1>
<p>Мы делаем быстрые сайты на Qwik!</p>
</main>
);
});
// SEO метаданные
export const head: DocumentHead = {
title: 'О нас — Мой Сайт',
meta: [
{ name: 'description', content: 'Узнайте о нашей команде' },
],
};

Квадратные скобки [param] создают динамические сегменты:

src/routes/blog/[slug]/index.tsx
import { component$ } from '@builder.io/qwik';
import { useLocation } from '@builder.io/qwik-city';
export default component$(() => {
const loc = useLocation();
return (
<article>
<h1>Пост: {loc.params.slug}</h1>
<p>URL: {loc.url.pathname}</p>
</article>
);
});
import { component$ } from '@builder.io/qwik';
import { Link, useNavigate } from '@builder.io/qwik-city';
export default component$(() => {
const nav = useNavigate();
return (
<nav>
{/* Декларативная навигация */}
<Link href="/">Главная</Link>
<Link href="/about">О нас</Link>
<Link href="/blog/hello-world">Пост</Link>
{/* Программная навигация */}
<button onClick$={() => nav('/dashboard')}>
Дэшборд
</button>
</nav>
);
});
import { useLocation } from '@builder.io/qwik-city';
export default component$(() => {
const loc = useLocation();
return (
<div>
<p>Путь: {loc.url.pathname}</p>
<p>Параметры: {JSON.stringify(loc.params)}</p>
<p>Поиск: {loc.url.search}</p>
<p>Хэш: {loc.url.hash}</p>
{/* Загружается ли страница? */}
{loc.isNavigating && <div>Загрузка...</div>}
</div>
);
});

Папки в скобках (groupName) создают логическую группировку без влияния на URL:

src/routes/
├── (marketing)/ → Группа маркетинговых страниц
│ ├── layout.tsx → Лейаут для маркетинга
│ ├── index.tsx → /
│ └── pricing/
│ └── index.tsx → /pricing
└── (app)/ → Группа приложения
├── layout.tsx → Другой лейаут
└── dashboard/
└── index.tsx → /dashboard

Файлы index.ts (без x) в routes/ создают API-эндпоинты:

src/routes/api/users/index.ts
import type { RequestHandler } from '@builder.io/qwik-city';
export const onGet: RequestHandler = async ({ json }) => {
const users = await fetchUsers();
json(200, users);
};
export const onPost: RequestHandler = async ({ request, json }) => {
const body = await request.json();
const user = await createUser(body);
json(201, user);
};
// Middleware применяется к маршруту и всем дочерним
export const onRequest: RequestHandler = async ({ cookie, redirect }) => {
const token = cookie.get('auth-token');
if (!token) {
throw redirect(302, '/login');
}
};