Как создать свой первый веб-сайт Node.js с помощью Express и Pug


Предпосылки
Если вы знаете JavaScript, но никогда раньше не занимались серверным программированием, это руководство для вас. Прежде чем продолжить, вам необходимо установить npmNode.js.
Вы можете поискать в Интернете инструкции по установке Node.js и npm предпочитаемой вами платформы или посетить веб- сайт Node.js ( npmпоставляется с Node). Версии, которые я использовал при создании этого проекта, следующие:
Node.js v16.15.1
npm v8.11.0
Вы можете просмотреть версию Node npm, которую вы установили, выполнив следующие команды в своем терминале:
node -v
npm -v
Я полагаю, что код все еще будет работать, даже если вы используете более старую версию Node , но если у вас возникнут проблемы с выполнением руководства, попробуйте выполнить обновление до версий, которые я использовал, чтобы посмотреть, решит ли это вашу проблему.
Что мы будем делать
Я расскажу вам, как создать простой веб-сайт с помощью Node.js, Express и Pug. Веб-сайт будет иметь домашнюю страницу и несколько других страниц, на которые мы сможем перейти.
Начиная
Загрузите начальные файлы затем выполните следующую команду из корня загруженной папки, чтобы установить зависимости проекта.
npm install
Я решил предоставить эти начальные файлы, чтобы вы не рисковали столкнуться с ошибками в результате использования версии пакета, отличной от той, которую использовал я. Не волнуйтесь, я объясню, что делает каждая зависимость, по ходу дела.
Теперь откройте server.jsв корневом каталоге и введите следующий код:
const express = require('express'); const app = express();
Мы начнем с импорта Express , который представляет собой используемую нами структуру веб-сервера. Функция express()является функцией верхнего уровня, экспортируемой expressмодулем.
Затем нам нужно настроить веб-сайт для работы на порту 7000. Вы можете выбрать другой порт, если на вашем компьютере используется порт 7000.
const server = app.listen(7000, () => { console.log(`Express running → PORT ${server.address().port}`); });
Вы можете запустить веб-сервер, запустив его node server.jsиз корня папки вашего проекта.
Если вы откроете http://localhost:7000в своем браузере, вы увидите сообщение об ошибке «Cannot GET /». Это связано с тем, что мы не определили корневой маршрут для нашего веб-сайта, поэтому давайте продолжим и сделаем именно это.
Добавьте следующий код перед serverобъявлением переменной в server.js:
app.get('/', (req, res) => { res.send('Hello World!'); });
Приведенный выше код указывает, что при выполнении запроса GET к корню нашего веб-сайта get()будет вызываться функция обратного вызова, которую мы указали в методе. В данном случае мы отправляем текст «Hello World!»
Хотя вы можете настроить маршруты для других типов HTTP-запросов, таких как POST, PUT и им подобных, в этом руководстве мы будем рассматривать только запросы GET.
Теперь вам нужно перезагрузить сервер, прежде чем изменения вступят в силу. Делать это каждый раз, когда вы вносите изменения в свой код, может стать невероятно утомительным, но я покажу вам, как обойти это в следующем разделе.
На данный момент остановите процесс Node в своем терминале с помощью ctrl + c запустите его снова, командой node server.jsзатем обновите браузер. Вы должны увидеть текст «Hello World!» на странице.
Настройте Nodemon для автоматического перезапуска сервера приложений Node.js.
Есть несколько инструментов, которые вы можете использовать для автоматического перезапуска сервера Node после каждого изменения, чтобы вам не приходилось с этим сталкиваться. Я предпочитаю Nodemon , который очень хорошо зарекомендовал себя в моих проектах.
Если вы посмотрите на package.jsonфайл, вы увидите, что nodemonон указан в разделе devDependencies, так что вы можете сразу начать его использовать.
Измените стартовый скрипт в package.json на следующий:
{ "scripts": { "start": "npx nodemon server.js" } }
Остановите процесс node и запустите npm start. Теперь веб-сервер будет перезапускаться автоматически каждый раз, когда вы вносите изменения.
Отображение HTML в браузере
Вместо того, чтобы просто отправлять текст в браузер, когда кто-то выбирает маршрут, мы можем отправить HTML-код, как это делают большинство веб-сайтов. Мы можем создавать HTML-файлы вручную и указывать, какой файл отправлять в браузер после того, как запрос GET достигнет маршрута, но почти всегда лучше использовать механизм шаблонов для создания HTML-файлов на лету.
Механизм шаблонов позволяет вам определять шаблоны для вашего приложения и заменять переменные в шаблоне фактическими значениями во время выполнения при преобразовании шаблона в фактический файл HTML, который затем отправляется клиенту.
Есть несколько механизмов шаблонов, которые вы можете использовать с Express. Pug , Mustache и EJS — одни из самых популярных. Я буду использовать здесь Pug, потому что мне нравится его синтаксис, но вы можете выполнить руководство в другом механизме шаблонов, если хотите.
Я уже включил pugпакет в зависимости нашего проекта, чтобы мы могли продолжить и использовать его в экспресс-режиме.
Добавьте следующий код в свой server.jsфайл под appпеременной. Это говорит об экспрессе, который мы используем pugв качестве нашего механизма шаблонов.
app.set('view engine', 'pug');
Express ожидает, что файлы наших шаблонов будут храниться в папке с именем views. Создайте эту папку в корне каталога вашего проекта, затем создайте файл с именем index.pugв viewsпапке и вставьте в него следующий код:
p Hello Pug!
Теперь измените строку в вашем server.jsфайле res.send('Hello World!')на res.render('index'). Это говорит Express об отображении шаблона индекса, который мы только что создали. Вам не нужно ставить .pugрасширение в конце.
Если вы обновите свой браузер, вы должны увидеть слова «Hello Pug!» на странице. Если вы проверите текст с помощью инструментов разработчика вашего браузера, вы должны увидеть, что код, который вы написали, index.pugбыл преобразован в обычный HTML.
основы мопса
Первое, что нужно знать, это то, что Pug использует отступы для описания структуры шаблона, а закрывающие теги отсутствуют.
Вот основной синтаксис для Pug, который вам нужно понять, чтобы завершить это руководство, а также HTML-эквивалент в комментарии под кодом Pug.
У вас есть свой элемент, пробел и содержимое, как мы сделали выше:
// <p>Hello Pug!</p>
Вы можете поместить содержимое элемента в отдельную строку, чтобы добиться того же результата:
p | Hello Pug! // <p>Hello Pug!</p>
Если вы хотите вложить элементы, вам нужно сделать отступ на один уровень:
div p Hello Pug! button Click Me // <div> // <p>Hello Pug!</p> // <button>Click Me</button> // </div>
Вы можете использовать классы и идентификаторы для своих элементов следующим образом:
div.container p#hello Hello Pug! button.btn.btn-blue Click Me // <div class="container"> // <p id="hello">Hello Pug!</p> // <button class="btn btn-blue">Click Me</button> // </div>
А вот как вы используете атрибуты HTML:
img(src="fish.png" alt="A big fish") // <img src="fish.png" alt="A big fish">
передача переменных в pug
Вы можете передать информацию из своего маршрута в свой шаблон, передав объект при отображении шаблона следующим образом:
server.js
res.render('index', { name: 'Ayo' });
И в вашем файле шаблона вы можете сослаться на него следующим образом:
index.pug
p Hello my name is #{name} // <p>Hello my name is Ayo</p>
Если вы хотите использовать переменную в атрибуте, вы должны сделать это с помощью литералов шаблона ES2015:
img(src=`${name}.jpg` alt=`This is ${name}`) // <img src="Ayo.jpg" alt="This is Ayo">
Давайте создадим сайт
Мы можем продемонстрировать мощь Pug и Express, создав простой веб-сайт.
Сначала создайте default.pugфайл в viewsкаталоге и вставьте в него следующее содержимое. Этот файл выступает своего рода шаблоном для других наших шаблонов.
doctype html html head title #{title} link(rel='stylesheet', href='/css/style.css') meta(name="viewport" content="width=device-width, initial-scale=1") body main block header header.header h1 #{title} block content
Ключевое blockслово позволяет нам расширить шаблон посредством наследования. При расширении шаблона вы можете определить пользовательский контент для любого блока в родительском шаблоне.
Вот пример того, как это работает. В index.pugфайле введите следующее:
extends default block content div.container
Шаблон по умолчанию ожидает переменную title, поэтому нам нужно передать ее при рендеринге любого шаблона, который ее расширяет.
server.js
res.render('index', { title: 'Homepage' });
Обновите браузер, чтобы увидеть изменения.
работа со статическим контентом
Нам нужно сообщить Express, где размещаются статические файлы (такие как таблицы стилей, шрифты или изображения) для нашего веб-сайта, чтобы он знал, как правильно их обслуживать.
Измените свой server.jsфайл, чтобы он выглядел так:
// ... app.set('view engine', 'pug'); // serve static files from the `public` folder app.use(express.static(__dirname + '/public')); // ...
Если вы обновите свой браузер, стили, на которые есть ссылки, default.pugдолжны сработать.
работа с json-данными
В корневой папке находится people.jsonфайл, который мы будем использовать для построения страниц сайта. Если вы просмотрите его, вы увидите profilesключ, представляющий собой массив, содержащий несколько объектов, каждый из которых представляет профиль человека.
В реальном приложении вы, скорее всего, будете извлекать эти данные из какой-то базы данных, но этот метод должен хорошо проиллюстрировать концепцию.
Давайте создадим домашнюю страницу сайта. Нам нужно передать данные json в наш шаблон индекса и отобразить карту для каждого человека, определенного в нем.
Измените свой server.jsфайл, чтобы он выглядел так:
const express = require('express'); const people = require('./people.json'); const app = express(); app.set('view engine', 'pug'); app.use(express.static(__dirname + '/public')); app.get('/', (req, res) => { res.render('index', { title: 'Homepage', people: people.profiles }); }); const server = app.listen(7000, () => { console.log(`Express running → PORT ${server.address().port}`); });
Здесь мы сохраняем ссылку на people.jsonфайл в peopleпеременной. Далее мы передаем profilesмассив в indexшаблон в качестве peopleключа.
Теперь измените свой index.pugфайл, чтобы он выглядел так:
extends default block content div.container each person in people div.person div.person-image(style=`background: url('/images/${person.imgSrc}') top center no-repeat; background-size: cover;`) h2.person-name | #{person.firstname} #{person.lastname} a(href=`/profile?id=${person.id}`) | View Profile
Ключевое eachслово в pug позволяет нам перебирать массивы и объекты. К каждому объекту в peopleмассиве можно получить доступ по personключу для каждой итерации, и мы используем это для создания карты для каждого человека на главной странице.
Внизу каждого человека есть ссылка, которая должна перейти к его соответствующим профилям. Но когда вы щелкаете по нему, вы получаете сообщение об ошибке «невозможно получить/профиль».
Давайте исправим это, создав новый маршрут для /profile. В server.js, добавьте следующий код под корневой маршрут:
app.get('/profile', (req, res) => { res.send(req.query.id); });
Как только вы нажмете на профиль человека, он должен отправить идентификатор человека обратно в браузер. В Express вы можете получить доступ к параметрам запроса URL в разделе req.query.
Давайте создадим новый файл шаблона, который будет отображаться, как только кто-то попадет на маршрут профиля. Идите вперед и создайте profile.pugв viewsпапке и добавьте следующее содержимое:
extends default block header block content div.profile div.profile-image(style=`background: url('/images/${person.imgSrc}') top center no-repeat; background-size: cover;`) div.profile-details h1.profile-name | #{person.firstname} #{person.lastname} h2.profile-tagline | #{person.tagline} p.profile-bio | #{person.bio} a.button.button-twitter(href=`${person.twitter}`) | Follow me on Twitter
Здесь мы снова расширяем шаблон по умолчанию и заменяем headerблок, определенный внутри, пустым блоком, потому что мы не хотим, чтобы содержимое заголовка по умолчанию отображалось на этой странице.
В contentблок я добавил необходимую разметку для каждого профиля. Как видите, этот шаблон ожидает, что мы передадим объект, описывающий каждого человека, так что давайте сделаем именно это.
Измените /profileмаршрут, чтобы он выглядел так:
app.get('/profile', (req, res) => { const person = people.profiles.find(p => p.id === req.query.id); res.render('profile', { title: `About ${person.firstname} ${person.lastname}`, person, }); });
Сначала мы используем метод массива find()для извлечения первого объекта, idсвойство которого соответствует полученному в параметрах запроса. Затем мы передаем этот объект в profileшаблон.
В результате профиль каждого человека можно просмотреть, щелкнув соответствующие ссылки профиля на главной странице.
вот итоговый код наших файлов
server.js
const express = require("express"); const people = require("./people.json"); const app = express(); app.set("view engine", "pug"); // serve static files from the `public` folder app.use(express.static(__dirname + "/public")); app.get("/", (req, res) => { res.render("index", { title: "Homepage", people: people.profiles }); }); app.get("/profile", (req, res) => { const person = people.profiles.find(p => p.id === req.query.id); res.render("profile", { title: `About ${person.firstname} ${person.lastname}`, person }); }); const server = app.listen(7000, () => { console.log(`Express running → PORT ${server.address().port}`); });
index.pug
extends default block content div.container each person in people div.person div.person-image(style=`background: url('/images/${person.imgSrc}') top center no-repeat; background-size: cover;`) h2.person-name | #{person.firstname} #{person.lastname} a(href=`/profile?id=${person.id}`) | View Profile
default.pug
doctype html html head title #{title} link(rel='stylesheet', href='/css/style.css') meta(name="viewport" content="width=device-width, initial-scale=1") body main block header header.header h1 #{title} block content
profile.pug
extends default block header block content div.profile div.profile-image(style=`background: url('/images/${person.imgSrc}') top center no-repeat; background-size: cover;`) div.profile-details h1.profile-name | #{person.firstname} #{person.lastname} h2.profile-tagline | #{person.tagline} p.profile-bio | #{person.bio} a.button.button-twitter(href=`${person.twitter}`) | Follow me on Twitter
можете скачать готовый проект.
не забудьте прописать команду npm i