SitePoint Premium предоставляет вам полную коллекцию книг, посвященных основам разработки, таким как Pug, Gulp, Git и другим. Присоединяйтесь сейчас .
Как веб-дизайнеры или разработчики, мы, вероятно, все должны написать нашу справедливую долю HTML. И хотя это не самая сложная задача, часто она может показаться немного скучной или повторяющейся. HTML также является статическим, что означает, что если вы хотите отображать динамические данные (например, полученные из API), вы неизбежно получите путаницу HTML-строк в JavaScript. Это может быть кошмаром для отладки и поддержки.
Вот где приходит Pug . Pug — это шаблонизатор для Node и для браузера. Он компилируется в HTML и имеет упрощенный синтаксис, который может сделать вас более продуктивным и сделать ваш код более читабельным. Pug облегчает как написание многократно используемого HTML, так и рендеринга данных, извлеченных из базы данных или API.
В этом руководстве я покажу, как начать работу с Pug. Мы начнем с установки его из npm, рассмотрим его основной синтаксис, а затем рассмотрим несколько примеров использования JavaScript в Pug. Наконец, мы рассмотрим несколько более продвинутых функций Pug, создав простой проект Node / Express, который использует Pug в качестве механизма шаблонов.
Что такое шаблонизатор и зачем он мне нужен?
Прежде чем мы начнем смотреть на Pug, давайте на секунду разберемся с концепциями.
Механизм шаблонов — это программа, которая отвечает за компиляцию шаблона (который может быть написан с использованием любого из нескольких языков) в HTML. Механизм шаблонов обычно получает данные из внешнего источника, которые он вставляет в компилируемый шаблон. Это иллюстрируется следующей диаграммой.
Этот подход позволяет повторно использовать статические элементы веб-страницы, одновременно определяя динамические элементы на основе ваших данных. Это также облегчает разделение задач, сохраняя логику вашего приложения изолированной от логики отображения.
Вы, скорее всего, выиграете от механизма шаблонов, если ваш сайт или веб-приложение управляются данными — например, каталог персонала для администрирования сотрудников, веб-магазин, в котором перечислены различные продукты, которые могут купить пользователи, или сайт с функцией динамического поиска.
Вам не понадобится шаблонизатор, если вы извлекаете небольшой объем данных из API (в этом случае вы можете просто использовать собственные строки шаблонов JavaScript) или если вы создаете небольшой статический сайт.
Маленькая история
Стоит также отметить, что Pug раньше называли Jade, пока в 2015 году его не заставили сменить название из-за претензии на товарный знак. Изменение названия вступило в силу с версии 2.0.
В Интернете все еще есть много материалов, касающихся Джейд. И хотя некоторые из них, вероятно, все еще вполне допустимы, тот факт, что изменение имени совпало с ударом основной версии, означает, что синтаксис Pug имеет несколько различий, устареваний и удалений по сравнению с его предшественником. Это документировано здесь .
Если вы хотите узнать больше, вы можете прочитать оригинальное объявление об изменении имени в этом выпуске GitHub . В противном случае, просто добавьте слово «шаблон» к поиску в Google, связанном с Pug, чтобы результаты не были переполнены.
Установка мопса
Прежде чем мы сможем написать Pug, нам нужно установить Node, npm (который поставляется в комплекте с Node) и пакет pug-cli .
Есть несколько вариантов установки Node / npm. Либо зайдите на домашнюю страницу проекта и загрузите правильные двоичные файлы для вашей системы, либо используйте менеджер версий, такой как nvm . Я бы порекомендовал использовать менеджер версий, где это возможно, поскольку это позволит вам устанавливать разные версии Node и переключаться между ними по желанию. Это также сведет на нет кучу потенциальных ошибок разрешений.
Вы можете ознакомиться с нашим руководством « Установка нескольких версий Node.js с помощью nvm » для более подробного руководства.
После того, как Node и npm установлены в вашей системе, вы можете установить пакет pug-cli
следующим образом:
npm i -g pug-cli
Вы можете проверить правильность процесса установки, введя pug --version
в терминал. Это выведет версию Pug и версию CLI, которую вы установили.
На момент написания статьи это было так:
$ pug --version pug version: 2.0.3 pug-cli version: 1.0.0-alpha6
Подсветка синтаксиса в вашем редакторе
Если ваш редактор не предлагает подсветку синтаксиса для Pug, было бы неплохо найти расширение для добавления этой функциональности.
В настоящее время я использую Sublime Text 3, и из коробки вот как .pug
файл .pug
:
Чтобы исправить это, можно установить пакет Sublime Pug :
Подсветка синтаксиса значительно облегчит работу с файлами Pug, особенно с файлами любой длины.
Попробуйте Pug без установки
Если вы хотите следовать простым примерам этого руководства, вы также можете запускать их на различных игровых площадках онлайн-кода.
Например , CodePen имеет встроенную поддержку Pug. Просто создайте новое перо, затем выберите « Настройки» > « HTML» и выберите «Pug» в качестве препроцессора. Это позволит вам ввести код Pug в панель HTML и увидеть результат в реальном времени.
В качестве дополнительного бонуса вы можете нажать на стрелку вниз на панели HTML и выбрать « Просмотр скомпилированного HTML», чтобы увидеть разметку, созданную Pug.
Основной синтаксис мопса
Теперь, когда у нас установлен Pug, давайте попробуем. Создайте новый каталог с именем pug-examples
и перейдите в него. Затем создайте еще один каталог с именем html
и файл с именем index.pug
:
mkdir -p pug-examples/html cd pug-examples touch index.pug
Примечание: команда touch
специфична для Linux / macOS. Пользователи Windows будут делать echo.> index.pug
для достижения того же.
Это работает так, что мы напишем наш код Pug в index.pug
и index.pug
pug-cli
следить за этим файлом на предмет изменений. Когда он обнаружит что-либо, он возьмет содержимое index.pug
и отобразит его как HTML в каталоге html
.
Чтобы начать, откройте терминал в каталоге pug-examples
и введите:
pug -w . -o ./html -P
Вы должны увидеть что-то вроде следующего:
watching index.pug rendered /home/jim/Desktop/pug-examples/html/index.html
Примечание: в приведенной выше команде параметр -w
обозначает наблюдение, точка указывает Pug смотреть все в текущем каталоге, -o ./html
указывает Pug выводить свой HTML в каталог html
а параметр -P
предварительно выводит выходные данные. ,
Теперь давайте создадим страницу из скриншота выше (тот, который жалуется на отсутствие подсветки синтаксиса). Введите следующее в index.pug
:
doctype html html(lang='en') head title Hello, World! body h1 Hello, World! div.remark p Pug rocks!
Сохраните pug.index
а затем просмотрите содержимое ./html/index.html
. Вы должны увидеть следующее:
<!DOCTYPE html> <html lang="en"> <head> <title>Hello, World!</title> </head> <body> <h1>Hello, World!</h1> <div class="remark"> <p>Pug rocks!!</p> </div> </body> </html>
Неплохо, а? CLI Pug взял наш файл Pug и отобразил его как обычный HTML.
Этот пример служит для того, чтобы выделить пару важных моментов о Pug. Во-первых, он чувствителен к пробелам , что означает, что Pug использует отступы для определения, какие теги вложены друг в друга. Например:
div.remark p Pug rocks!!
Код выше производит это:
<div class="remark"> <p>Pug rocks!!</p> </div>
Теперь возьмите этот код:
div.remark p Pug rocks!!
Это производит следующее:
<div class="remark"></div> <p>Pug rocks!!</p>
Неважно, какой уровень отступа вы используете (вы даже можете использовать вкладки, если нужно), но настоятельно рекомендуется поддерживать постоянный уровень отступов. В этой статье я буду использовать два пробела.
Во-вторых, у Pug нет закрывающих тегов . Это, очевидно, избавит вас от нескольких нажатий клавиш и обеспечит Pug простым и легким для чтения синтаксисом.
Теперь, когда мы получили представление о каком-то простом Pug, давайте быстро рассмотрим его синтаксис. Если что-то из этого может показаться непонятным, или вы хотите углубиться, обязательно обратитесь к отличной документации проекта .
DOCTYPE
Вы можете использовать Pug для генерации нескольких объявлений типов документов.
Например, doctype html
будет скомпилирован в <!DOCTYPE html>
, стандартный тип документа HTML5, а doctype strict
даст нам <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
. Мопс приложит все усилия, чтобы гарантировать, что его вывод действителен для типа документа.
Теги
Как уже упоминалось, Pug не имеет закрывающих тегов и полагается на отступ для вложения. Это может потребовать небольшого количества привыкания, но как только вы это сделаете, это сделает чистый и читаемый код. В качестве примера:
nav navbar-default div h1 My Website! ul li a Home li a Page 1 li a Page 2 input
Код выше компилируется в это:
<nav> <div> <h1>My Website!</h1> </div> <ul> <li><a>Home</a></li> <li><a>Page 1</a></li> <li><a>Page 2</a></li> </ul> <input/> </nav>
Обратите внимание, что Pug достаточно умен, чтобы закрыть для нас любые самозакрывающиеся теги (например, элемент <input />
).
Классы, идентификаторы и атрибуты
Классы и идентификаторы выражаются с использованием обозначений .className
и #IDname
. Например:
nav#navbar-default div.container-fluid h1.navbar-header My Website!
Мопс также предлагает нам удобный ярлык. Если тег не указан, он будет иметь элемент <div>
:
nav#navbar-default .container-fluid h1.navbar-header My Website!
Оба из них компилируются в:
<nav id="navbar-default"> <div class="container-fluid"> <h1 class="navbar-header">My Website!</h1> </div> </nav>
Атрибуты добавляются в квадратных скобках:
ul li a(href='/') Home li a(href='/page-1') Page 1 li a(href='/page-2') Page 2 input.search( type='text' name='search' placeholder='Enter a search term...' )
Это приводит к следующему:
<ul> <li><a href="/">Home</a></li> <li><a href="/page-1">Page 1</a></li> <li><a href="/page-2">Page 2</a></li> </ul> <input class="search" type="text" name="search" placeholder="Enter a search term..."/>
Есть еще много чего сказать об атрибутах. Например, вы можете использовать JavaScript для включения переменных в свои атрибуты или назначить массив значений атрибуту. Мы перейдем к использованию JavaScript в Pug в следующем разделе.
Простой текст и текстовые блоки
Pug предоставляет различные методы для добавления простого текста непосредственно в визуализированный HTML.
Мы уже видели, как добавить обычный текст в строке:
h1.navbar-header My Website! We can write anything we want here …
Другой способ заключается в добавлении строки к символу канала ( |
):
p | You are logged in as | [email protected]
Это дает нам следующее:
<p> You are logged in as [email protected] </p>
Имея дело с большими блоками текста, вы можете просто добавить точку .
сразу после имени тега или после закрывающей скобки, если тег имеет атрибуты:
p. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
Это приводит к:
<p> Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. </p>
Комментарии
Наконец, комментарии могут быть добавлены так:
// My wonderful navbar nav#navbar-default
Этот комментарий будет добавлен к отображаемому HTML:
<!-- My wonderful navbar--> <nav id="navbar-default"></nav>
Вы начинаете комментарий так:
//- My wonderful navbar nav#navbar-default
Когда вы сделаете это, комментарий останется в файле Pug, но не появится в HTML.
Комментарии должны появляться в отдельной строке. Здесь комментарий будет рассматриваться как простой текст:
nav#navbar-default // My wonderful navbar
Также возможны многострочные комментарии:
// My wonderful navbar It is just so, awesome! nav#navbar-default
Демонстрация основного синтаксиса
Ниже вы можете найти демонстрацию макета в стиле Bootstrap, который демонстрирует методы, которые мы обсуждали до сих пор:
Использование JavaScript в Pug
Одна из замечательных особенностей Pug — возможность запуска JavaScript в ваших шаблонах. Это позволяет легко вставлять переменные в наши шаблоны, перебирать массивы и объекты, условно отображать HTML и многое другое.
Буферизованный и небуферизованный код
Это важное различие, о котором следует знать перед использованием JavaScript в Pug.
Небуферизованный код начинается с минуса ( -
). Он ничего не добавляет напрямую к выводу, но его значения могут быть использованы из Pug:
- const name = "Jim" //- Now I can refer to a 'name' variable in my Pug code
Буферный код , с другой стороны, начинается с равенства ( =
). Он оценивает выражение JavaScript и выводит результат.
p= 'Two to the power of ten is: ' + 2**10
Код выше компилируется в это:
<p>Two to the power of ten is: 1024</p>
Из соображений безопасности буферизованный код экранирован HTML.
p= '<script>alert("Hi")</script>'
Код выше компилируется в это:
<p><script>alert("Hi")</script></p>p>
интерполирование
Строковая интерполяция — это процесс замены одного или нескольких заполнителей в шаблоне соответствующим значением. Как мы только что видели, буферизованный ввод предлагает один из способов сделать это. Другой использует #{}
. Здесь Pug оценивает любой код в фигурных скобках, экранирует его и выводит в шаблон.
- const name = "jim" p Hi #{name}
Код выше компилируется в это:
<p>Hi jim</p>
Поскольку фигурные скобки могут содержать любое допустимое выражение JavaScript, это открывает множество возможностей:
- const name = "jim" - //- Upcase first letter p Hi #{name.charAt(0).toUpperCase() + name.slice(1)}
Это компилируется в:
<p>Hi Jim</p>
Также возможно отобразить неэкранированные значения в ваши шаблоны, используя !{}
. Но это не лучшая идея, если информация поступает из ненадежного источника.
Примечание: если вы хотите присвоить значение, содержащееся в переменной, атрибуту элемента, вы можете опустить #{}
. Например: img(alt=name)
.
итерация
each
ключевое слово Pug позволяет легко перебирать массивы:
- const employees = ['Angela', 'Jim', 'Nilson', 'Simone'] ul each employee in employees li= employee
Это приводит к следующему:
<ul> <li>Angela</li> <li>Jim</li> <li>Nilson</li> <li>Simone</li> </ul>
Вы также можете использовать его для перебора ключей в объекте:
- const employee = { 'First Name': 'James', 'Last Name': 'Hibbard' } ul each value, key in employee li= `${key}: ${value}`
Это приводит к:
<ul> <li>First Name: James</li> <li>Last Name: Hibbard</li> </ul>
Pug также позволяет вам предоставить блок else, который будет выполняться, если массив или объект пуст:
- const employees = [] ul each employee in employees li= employee else li The company doesn't have any employees. Maybe hire some?
Наконец, обратите внимание, что вы можете использовать в качестве псевдонима для each
.
Conditionals
Условные выражения предлагают очень удобный способ визуализации различного HTML в зависимости от результата выражения JavaScript:
- const employee = { firstName: 'James', lastName: 'Hibbard', extn: '12345' } #employee p= `${employee.firstName} ${employee.lastName}` p Extension: if employee.extn =employee.extn else | n/a
В этом примере мы проверяем, имеет ли объект extn
свойство extn
, затем либо extn
значение этого свойства (если оно существует), либо текст «n / a».
JavaScript в Pug Демо
Ниже вы можете найти демонстрацию некоторых методов, которые мы обсуждали в этом разделе. Это демонстрирует преимущества Pug несколько больше, чем в предыдущей демонстрации, так как все, что нам нужно сделать, чтобы добавить дополнительных сотрудников, — это добавить дополнительные объекты в наш массив sitePointEmployees
.
Практический пример
Теперь, когда у нас есть разумное представление о синтаксисе Pug и о том, как он работает, давайте закончим, создав небольшое приложение Express.js , чтобы продемонстрировать несколько более продвинутых функций Pug.
Код для этого примера доступен на GitHub .
Примечание: если вы раньше не пользовались Express, не беспокойтесь. Это веб-фреймворк для Node.js, который предоставляет надежный набор функций для создания веб-приложений. Если вы хотите узнать больше, ознакомьтесь с нашим руководством по Express .
Прежде всего, давайте создадим новый проект и установим Express:
mkdir pug-express cd pug-express npm init -y npm i express
Затем создайте файл app.js
папке pug-express
:
touch app.js
Затем добавьте следующее:
const express = require('express'); const app = express(); app.get('/', (req, res) => { res.send('Hello, World!'); }); app.listen(3000, () => { console.log('Listening on port 3000...'); });
Здесь мы объявляем маршрут ( /
), который будет отвечать на запрос GET с текстом «Hello, World!». Мы можем проверить это в наших браузерах, запустив сервер с node app.js
и посетив http: / / localhost: 3000 .
Если вы видите что-то подобное, то все идет по плану:
Добавление некоторых данных
Это приложение Express не будет делать ничего особенного. Мы создадим простой каталог персонала, который извлекает список сотрудников из базы данных и отображает их в виде таблицы. Для этого нам понадобится база данных и некоторые данные.
Однако… установка и настройка базы данных немного сложны для этого небольшого примера, поэтому я собираюсь использовать пакет под названием json-server . Это позволит нам создать файл db.json
который превратится в REST API, с которым мы можем выполнять операции CRUD.
Давайте установим это:
npm i -g json-server
Теперь создайте вышеупомянутый файл db.json
в корне проекта:
touch db.json
Наконец, нам нужен JSON для его заполнения. Мы будем использовать Random User Generator , который является бесплатным API с открытым исходным кодом для генерации случайных пользовательских данных. Двадцать пять человек должны сделать для нашего примера, поэтому db.json
на https://randomuser.me/api/?results=25
и скопируйте результаты в db.json
.
Наконец, запустите сервер во втором окне терминала с помощью:
json-server --watch db.json -p=3001
Это приведет к запуску json-сервера через порт 3001 и наблюдению за изменениями в файле нашей базы данных.
Настройка Pug в качестве движка шаблонов
Express имеет отличную поддержку для использования Pug, поэтому очень мало конфигурации необходимо.
Для начала давайте добавим Pug в наш проект:
npm i pug
Затем в app.js
нам нужно указать Express использовать Pug:
app.set('view engine', 'pug');
Затем создайте каталог представлений, затем в каталоге представлений добавьте файл index.pug
:
mkdir views touch views/index.pug
Добавьте контент в этот файл:
doctype html html(lang='en') head title Hello, World! body h1 Hello, World!
Затем app.js
так:
const express = require('express'); const app = express(); app.set('view engine', 'pug'); app.get('/', (req, res) => { res.render('index'); }); app.listen(3000, () => { console.log('Listening on port 3000...'); });
Наконец, перезапустите сервер Node, затем обновите ваш браузер, и вы должны увидеть это:
Вот и все. Тебе хорошо идти.
Создание каталога персонала
Следующая задача в списке — передать некоторые данные в шаблон Pug для отображения. Для этого нам понадобится метод извлечения данных с json-сервера. К сожалению, API извлечения не реализован в Node, поэтому давайте использовать Axios , популярный HTTP-клиент:
npm i axios
Затем app.js
так:
const express = require('express'); const axios = require('axios'); const app = express(); app.set('view engine', 'pug'); app.get('/', async (req, res) => { const query = await axios.get('http://localhost:3001/results'); res.render('index', { employees: query.data }); }); app.listen(3000, () => { console.log('Listening on port 3000...'); });
Здесь происходит несколько вещей. Мы превратили наш обработчик маршрута в асинхронную функцию , чтобы мы могли дождаться возвращения данных сотрудника с json-сервера, прежде чем передать их в шаблон.
Затем мы визуализируем индекс, как и раньше, но на этот раз мы передаем ему литерал объекта, содержащий все наши данные.
Примечание: вы должны перезапускать Node-сервер каждый раз, когда вы вносите изменения в app.js
Если это начинает раздражать, проверьте nodemon , который сделает это за вас.
Теперь для мопса. Измените index.pug
чтобы он выглядел следующим образом:
doctype html html(lang='en') head title Staff Directory link(rel='stylesheet' href='https://cdn.jsdelivr.net/npm/[email protected]/dist/semantic.min.css') style. table.ui.celled img { display: inline-block; } footer { margin: 35px 0 15px 0; text-align: center } body main#main h1.ui.center.aligned.header Staff Directory .ui.container table.ui.celled.table.center.aligned thead tr th Avatar th First Name th Last Name th Email th Phone th City tbody each employee in employees tr td img.ui.mini.rounded.image(src=employee.picture.thumbnail) td #{employee.name.first} td #{employee.name.last} td #{employee.email} td #{employee.phone} td #{employee.location.city} tfoot tr th(colspan='6') footer p © #{new Date().getFullYear()} My Company
Надеюсь, ничего удивительного здесь не происходит. Мы используем semantic-ui-css для некоторых стилей, а также несколько наших собственных стилей.
Затем в теле таблицы мы перебираем массив employees
которые передаем из app.js
и app.js
их данные в таблицу.
Внизу страницы находится нижний колонтитул с нашим заявлением об авторском праве и текущим годом.
Если вы обновите страницу сейчас, вы должны увидеть это:
Наследование шаблонов
Это уже довольно приятно, но, в заключение, я собираюсь продемонстрировать, как структурировать наши представления, чтобы обеспечить максимальную гибкость по мере роста проекта.
Начнем с создания файла layout.pug
в каталоге views
:
touch views/layout.pug
Затем добавьте следующее:
doctype html html head title Staff Directory link(rel='stylesheet' href='https://cdn.jsdelivr.net/npm/[email protected]/dist/semantic.min.css') style. table.ui.celled img { display: inline-block; } footer { margin: 35px 0 15px 0; text-align: center } body main#main h1.ui.center.aligned.header Staff Directory .ui.container block content block footer footer p © #{new Date().getFullYear()} My Company
Здесь мы создали файл макета, который может быть расширен другими файлами Pug в нашем проекте. Когда у вас есть большое количество файлов Pug, это сохраняет значительное количество кода.
Это работает так, что мы определили два блока контента ( block content
и block footer
), который может заменить дочерний шаблон. В случае блока footer
мы также определили некоторый запасной контент, который будет отображаться, если дочерний шаблон не переопределит этот блок.
Теперь мы можем указать нашему файлу index.pug
наследоваться от нашего макета:
extends layout.pug block content table.ui.celled.table.center.aligned thead tr th Avatar th First Name th Last Name th Email th Phone th City tbody each employee in employees tr td img.ui.mini.rounded.image(src=employee.picture.thumbnail) td #{employee.name.first} td #{employee.name.last} td #{employee.email} td #{employee.phone} td #{employee.location.city} tfoot tr th(colspan='6')
Результат такой же, как и раньше, но теперь код имеет лучшую структуру.
Примеси
Миксины позволяют создавать многоразовые блоки мопса. Мы можем использовать это для извлечения нашей строки таблицы в свой собственный файл.
Создайте папку с именем mixins
в папке представлений и в этой папке создайте файл с именем _tableRow.pug
:
mkdir views/mixins touch views/mixins/_tableRow.pug
Миксины объявляются с использованием ключевого слова mixin
. Они компилируются в функции и могут принимать аргументы. Добавьте следующее в views/mixins/_tableRow.pug
:
mixin tableRow(employee) tr td img.ui.mini.rounded.image(src=employee.picture.thumbnail) td #{employee.name.first} td #{employee.name.last} td #{employee.email} td #{employee.phone} td #{employee.location.city}
Теперь index.pug
так:
extends layout.pug include mixins/_tableRow block content table.ui.celled.table.center.aligned thead tr th Avatar th First Name th Last Name th Email th Phone th City tbody each employee in employees +tableRow(employee) tfoot tr th(colspan='6')
Как вы можете видеть, мы импортируем миксин вверху файла. Затем мы вызываем его, добавляя к его имени символ плюс и передавая объект нашего employee
для отображения.
Это излишне для нашего маленького приложения, но оно демонстрирует очень полезную функцию Pug, которая позволяет нам писать повторно используемый код.
Вывод
Хорошо, если вы сделали это так далеко! Мы рассмотрели много вопросов в этом уроке. Мы рассмотрели установку Pug, его основной синтаксис, поддержку JavaScript и конструкции для итерации и условного рендеринга. Наконец, мы создали полнофункциональное приложение Express, которое извлекает данные из удаленного источника и передает их в шаблон Pug.
Еще много чего может сделать Паг. Я бы посоветовал вам проверить отличную документацию и просто начать использовать ее в своих проектах. Вы также можете использовать его с несколькими современными средами JS, такими как React или Vue , и он даже был портирован на несколько других языков .
Если вы ищете проблему, почему бы не попробовать расширить каталог сотрудников, чтобы добавить недостающие функции CRUD. И если вы застряли с синтаксисом, не забывайте, что помощь всегда под рукой .