Перейти к содержанию

Первый проект Next.js и путь запроса

Оглавление курса · Скачать все состояния проекта.

Учебная задача: Разделить страницу, корневую компоновку и среду выполнения приложения.

Входное состояние: Есть знания React, компонентов и JavaScript; проекта ещё нет. Выходное состояние: Структура App Router и первая публичная страница «Смены». Продолжаем «Смену» — учебную диспетчерскую заявок мастерской. Нужны основы JavaScript, TypeScript, React и HTTP. Используем App Router, Next 16.4.0, React 19.3.0 и Node.js не ниже 20.9.0. Основные версии закреплены; диапазоны остальных пакетов ещё не разрешены установкой и lockfile отсутствует. Полный каталог lesson-01 в архиве соответствует окончанию этой главы. Выбирайте один снимок целиком: перенос отдельных файлов из будущих этапов меняет его зависимости и правила данных.

Исходники подготовлены редакционным чтением. Пакеты, сервер, сборка, миграции, примеры и внешнее размещение не выполнялись. Ответы страницы и изменения данных ниже являются ожидаемыми, example_execution: not_run.

Мастерская ведёт заявки на бумажных карточках. В учебном проекте «Смена» перенесём этот процесс в небольшое веб-приложение: сначала покажем список, затем добавим данные, вход и действия сотрудников. Начнём с самой короткой цепочки запроса. Посетитель открывает адрес, Next.js выбирает страницу, React описывает её содержимое, а браузер получает документ и необходимые ресурсы. Уже здесь полезно различать исходник страницы и ответ, который увидит человек.

Next.js добавляет к React договорённости о маршрутах, серверной работе и сборке приложения. React-компонент остаётся способом описать интерфейс, но не отвечает сам по себе на вопрос, какой файл обслуживает /tickets. В App Router этот вопрос связан с деревом каталога app. Имя page.tsx обозначает страницу, layout.tsx задаёт общую оболочку. Обычный файл рядом не становится страницей только потому, что содержит JSX.

Устройство минимального состояния

В package.json указаны точные версии Next 16.4.0 и React 19.3.0. Требуется Node.js не ниже 20.9.0. Дополнительные пакеты пока относятся к TypeScript и описанию типов. Диапазоны этих зависимостей ещё не разрешены в фиксированный набор: установка и получение lockfile не выполнялись. Поэтому архив фиксирует намерение автора и версии основных библиотек, но не заявляет о подтверждённой сборке окружения.

Команды dev, build и start имеют разные роли. Первая предназначена для разработки, вторая готовит выпуск, третья обслуживает уже подготовленный выпуск. Наличие этих строк не означает, что любая из команд была выполнена. При самостоятельном прохождении читатель готовит среду выбранного снимка; мы рассматриваем команды как часть договора проекта. Не следует исправлять предполагаемую ошибку выпуска только по тому, что страница видна в режиме разработки.

Корневая компоновка возвращает html с языком ru и body. Она принимает children, куда маршрутизатор помещает выбранную страницу. Это место для общих правил документа и подключения глобального CSS. Текст «Смена» и ссылка на заявки находятся в page.tsx, поскольку относятся к конкретной главной странице. Такое разделение позволит добавить рабочие разделы без копирования полного HTML-документа.

Страница по умолчанию является Server Component. Здесь нет директивы use client, состояния или обработчика клика. Компонент описывает заголовок, абзац и ссылку Link. Серверная природа компонента не делает его вывод секретным: текст и данные, которые вы включили в страницу, предназначены посетителю. Позже мы отдельно ограничим данные пользователя до того, как они попадут в интерфейс.

Зачем нужны настройки TypeScript

tsconfig.json включает строгий режим и обработку модулей в договоре сборщика. Алиас @/* соответствует корню снимка. Когда дальше напишем @/lib/tickets, инструмент должен найти модуль именно в этом проекте, а не в случайном соседнем каталоге. Настройки не создают сам файл и не проверяют внешние данные в момент запроса. Они помогают согласовать исходники до исполнения, но значения JSON потребуют отдельной проверки.

next-env.d.ts подключает описания типов Next и изображений. Это служебный файл проекта, а не страница и не место для предметной логики заявок. Глобальный CSS задаёт базовую ширину, читабельный размер текста и заметный фокус. Такой минимум позволяет оценивать маршрут и содержимое, не отвлекаясь на сложное оформление. Стили обслуживаются вместе с приложением, но не управляют выбором серверного обработчика.

Флаг private в пакете предотвращает случайную публикацию учебного пакета в npm. Он не закрывает веб-страницу от посетителей и не шифрует содержимое архива. Аналогично .gitignore помогает не добавлять локальные артефакты в репозиторий, но не является проверкой доступа к заявкам. Уже на первом этапе отделяем организацию исходников от полномочий пользователя: дальше эти уровни будут часто встречаться рядом.

Ожидаемая страница и границы шага

В подготовленном состоянии ожидается публичная главная страница с названием, кратким назначением и ссылкой /tickets. Следующая глава создаст соответствующий маршрут. Сейчас сама ссылка ещё не доказывает, что страница заявок существует. Она задаёт целевой адрес. Если открыть неизвестный путь, маршрутизатор ожидаемо не найдёт страницу; изменение текста главной страницы не создаст новый маршрут.

Попробуйте проследить, какой файл отвечает за язык документа, какой за текст приветствия и какой за версии библиотек. Затем объясните, почему добавление файла tickets.tsx в произвольный каталог не гарантирует появления URL. Эти вопросы позволяют читать приложение как набор согласованных обязанностей. В дальнейших уроках будем менять одну часть договора и показывать, что именно получает следующий участник цепочки.

До подключения базы используем только вымышленные учебные данные. Персональные обращения клиентов и рабочие ключи не нужны для понимания маршрутизатора. Полные снимки помогают вернуться к этому минимальному состоянию: выберите каталог первого урока целиком, если хотите изучить только запрос и страницу. Более поздние файлы входа, миграций и таблиц здесь ещё не являются предпосылкой.

Проверьте смысл границ

Если перенести только page.tsx в пустой каталог, у страницы ещё не появится договор компилятора и корневого документа. Полный снимок содержит эти связи вместе. Обратная ситуация тоже показательна: корректный package.json не создаёт содержимое главной страницы. Поэтому при самостоятельной подготовке выбирайте весь каталог и сначала сопоставьте имена файлов с их обязанностями.

Исходный JSX не является буквальным файлом, который браузер исполняет без инструментов. Серверная и клиентская работа организуется Next на основании модулей и специальных файлов. Такое различие позволит дальше читать директивы и импорты осмысленно: изменение границы влияет на код и данные, которые нужны браузеру, а не только на место хранения текста.

Полные файлы этого шага

Следующие файлы показаны полностью. Остальные согласованные компоненты и настройки находятся в том же каталоге архива; сохраняйте их вместе при самостоятельном прохождении.

package.json

{
  "name": "professorweb-smena",
  "version": "1.0.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start"
  },
  "engines": {
    "node": ">=20.9.0"
  },
  "dependencies": {
    "next": "16.4.0",
    "react": "19.3.0",
    "react-dom": "19.3.0"
  },
  "devDependencies": {
    "typescript": "^6.0.2",
    "@types/node": "^22",
    "@types/react": "^19",
    "@types/react-dom": "^19"
  }
}

tsconfig.json

{
  "compilerOptions": {
    "target": "ES2017",
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": true,
    "noEmit": true,
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "bundler",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "react-jsx",
    "incremental": true,
    "plugins": [
      {
        "name": "next"
      }
    ],
    "paths": {
      "@/*": [
        "./*"
      ]
    }
  },
  "include": [
    "next-env.d.ts",
    "**/*.ts",
    "**/*.tsx",
    ".next/types/**/*.ts",
    ".next/dev/types/**/*.ts"
  ],
  "exclude": [
    "node_modules"
  ]
}

app/layout.tsx

import "./globals.css";
import type { ReactNode } from "react";
export default function RootLayout({ children }: { children: ReactNode }) {
  return <html lang="ru"><body>{children}</body></html>;
}

app/page.tsx

import Link from "next/link";
export default function Home() {
  return <main><h1>Смена</h1><p>Учебная диспетчерская заявок мастерской.</p><Link href="/tickets">Открыть заявки</Link></main>;
}

Документация и исходники

Договор этой главы раскрыт в официальной документации. Сопоставьте её API с выбранной версией и с объяснённым источником каждого значения. Архив «Смены» содержит двадцать полных состояний и условия самостоятельной подготовки. Ожидаемый результат оценивается по текущей главе: поздние проверки владельца, база и внешние ключи не являются неявно выполненными предпосылками раннего учебного состояния.