Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

Многостраничный сайт

Соберём всё вместе: сайт кофейни «Утро» из трёх страниц — главная, меню и контакты. У страниц общий макет, шапка и подвал, а скрипт сборки сам находит все страницы и записывает HTML-файлы.

Структура проекта

Страницы переезжают в папку src/pages/, а общие части остаются в src/:

cafe/
├── build.js
├── dist/               ← index.html, menu.html, contacts.html
└── src/
    ├── layout.pug
    ├── mixins.pug
    ├── includes/
    │   ├── header.pug
    │   └── footer.pug
    └── pages/
        ├── index.pug
        ├── menu.pug
        └── contacts.pug

Файл src/mixins.pug — тот же, что в уроке о подключении файлов: миксин drink(name, price).

Скрипт для всех страниц

Замените build.js:

// build.js
import { mkdirSync, readdirSync, writeFileSync } from "node:fs";
import pug from "pug";
 
const data = {
  year: new Date().getFullYear(),
  phone: "+1 555 0100",
  menu: [
    { name: "Эспрессо", price: 2 },
    { name: "Капучино", price: 3 },
    { name: "Какао", price: 3 },
  ],
};
 
mkdirSync("dist", { recursive: true });
 
for (const file of readdirSync("src/pages")) {
  const page = file.replace(".pug", "");
  const html = pug.renderFile(`src/pages/${file}`, { pretty: true, page, ...data });
  writeFileSync(`dist/${page}.html`, html);
  console.log(`Готово: dist/${page}.html`);
}

Цикл берёт каждый файл из src/pages/ и передаёт в шаблон общие данные и переменную page — имя страницы без расширения. Новая страница появится на сайте, как только вы создадите для неё файл .pug.

Макет, шапка и подвал

Создайте src/includes/header.pug. Ссылка на текущую страницу получает класс active:

header
  a.logo(href="index.html") Кофейня «Утро»
  nav
    each title, slug in { index: "Главная", menu: "Меню", contacts: "Контакты" }
      a(href=slug + ".html" class=page === slug ? "active" : undefined)= title

Подвал — src/includes/footer.pug:

footer
  p © #{year} Кофейня «Утро» · #{phone}

Макет src/layout.pug подключает обе части. Пути в include отсчитываются от самого макета:

doctype html
html(lang="ru")
  head
    meta(charset="utf-8")
    block title
      title Кофейня «Утро»
    link(rel="stylesheet" href="style.css")
  body
    include includes/header.pug
    main
      block content
    include includes/footer.pug

Страницы

Главная — src/pages/index.pug:

extends ../layout.pug
 
block content
  h1 Свежий кофе каждый день
  p Заходите на завтрак с 8:00.

Контакты — src/pages/contacts.pug:

extends ../layout.pug
 
block title
  title Контакты — Кофейня «Утро»
 
block content
  h1 Контакты
  p Звоните: #{phone}

Меню — src/pages/menu.pug. Миксины подключаются строкой include рядом с extends:

extends ../layout.pug
include ../mixins.pug
 
block title
  title Меню — Кофейня «Утро»
 
block content
  h1 Меню
  each item in menu
    +drink(item.name, item.price)

Результат

Запустите npm run build — в терминале появятся три строки «Готово», а в dist/ три страницы. Так выглядит dist/menu.html:

<!DOCTYPE html>
<html lang="ru">
  <head>
    <meta charset="utf-8">
    <title>Меню — Кофейня «Утро»</title>
    <link rel="stylesheet" href="style.css">
  </head>
  <body>
    <header><a class="logo" href="index.html">Кофейня «Утро»</a>
      <nav><a href="index.html">Главная</a><a class="active" href="menu.html">Меню</a><a href="contacts.html">Контакты</a>
      </nav>
    </header>
    <main>
      <h1>Меню</h1>
      <div class="card">
        <h3>Эспрессо</h3>
        <p class="price">$2</p>
      </div>
      <div class="card">
        <h3>Капучино</h3>
        <p class="price">$3</p>
      </div>
      <div class="card">
        <h3>Какао</h3>
        <p class="price">$3</p>
      </div>
    </main>
    <footer>
      <p>© 2026 Кофейня «Утро» · +1 555 0100</p>
    </footer>
  </body>
</html>

У ссылки «Меню» класс active, а цены взяты из данных в build.js. Положите style.css в dist/ и откройте dist/index.html — по ссылкам в шапке можно переходить между страницами.

Частая ошибка

Положить в src/pages/ что-то кроме страниц, например миксины или шапку. Скрипт попытается собрать такой файл как отдельную страницу и создаст лишний HTML. В src/pages/ держите только страницы, а общие части — в src/ и src/includes/.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.