Структура проекта
Express не создаёт папки за вас: всё можно написать в одном файле. Но когда маршрутов становится больше десятка, такой файл трудно читать. Поэтому проект раскладывают по папкам, где у каждой части своя роль.
Структура блога
Так будет выглядеть проект к середине курса:
blog/
├── package.json
├── .env настройки, не попадают в Git
├── src/
│ ├── app.js создаёт приложение и подключает всё остальное
│ ├── server.js запускает сервер
│ ├── routes/
│ │ └── posts.js адреса раздела статей
│ ├── controllers/
│ │ └── postsController.js функции-обработчики
│ ├── models/
│ │ └── post.js работа с данными
│ └── middleware/
│ └── requireAuth.js
├── views/ шаблоны HTML-страниц
│ └── posts/
│ └── index.ejs
├── public/ CSS, картинки, скрипты для браузера
│ └── css/style.css
└── test/ автотестыПапки views/ и public/ лежат в корне: Express по умолчанию ищет шаблоны в views/ относительно папки, из которой запущен сервер.
Роли папок
| Папка или файл | Что внутри |
|---|---|
src/app.js | Настройка приложения: middleware, маршруты, обработка ошибок |
src/server.js | Только запуск: app.listen() |
src/routes/ | Какой адрес какой функцией обрабатывается |
src/controllers/ | Что делать с запросом: получить данные, ответить |
src/models/ | Чтение и запись данных |
views/ | Шаблоны страниц |
public/ | Файлы, которые браузер получает как есть |
Разделяем app.js и server.js
Создайте файл src/app.js, перенесите в него приложение и экспортируйте его:
// src/app.js
import express from 'express';
const app = express();
app.get('/', (req, res) => {
res.send('Привет от блога!');
});
export default app;А src/server.js теперь только импортирует приложение и запускает его:
// src/server.js
import app from './app.js';
const PORT = 3000;
app.listen(PORT, () => {
console.log(`Сервер запущен: http://localhost:${PORT}`);
});Команда npm run dev работает как раньше: http://localhost:3000 показывает то же приветствие. Зато приложение из app.js теперь можно импортировать в тестах, не запуская настоящий сервер, — это пригодится в уроке о тестировании.
Как файлы связаны
Запрос проходит путь сверху вниз: server.js запускает приложение из app.js, app.js передаёт запрос в нужный файл из routes/, маршрут вызывает функцию из controllers/, контроллер берёт данные из models/ и отдаёт страницу по шаблону из views/. Каждое звено появится в своём уроке.
Частая ошибка
В ES-модулях путь к своему файлу пишется полностью, с расширением: import app from './app.js'. Запись './app' без .js работает в некоторых сборщиках, но Node.js на ней остановится с ошибкой ERR_MODULE_NOT_FOUND.