EJS — что это за шаблонизатор и в каких случаях он может быть полезен в современной web-разработке
Любопытно, что в мире современной web-разработке все ещё находится место использованию таких старых и проверенных инструментов, как EJS, вместо повсеместного (и не всегда уместного) использования современных компонентных фреймворков, наподобие Vue/React/Angular.
EJS (Embedded JavaScript templates) представляет собой простой JS-шаблонизатор, который был когда-то очень популярным в среде матерых фронтендеров, да и сейчас вполне находит применение. Я уж думаю не надо объяснять, зачем вообще в разработке нужны шаблонизаторы.
На мой взгляд у EJS можно выделить несколько плюсов, по сравнению с многими другими JS-шаблонизаторами:
- Проект существует уже более 15-ти лет и до сих пор развивается и поддерживается, т.е. это вполне зрелый и устоявшийся проект.
- По факту, ничего нового учить не нужно, поскольку синтаксис шаблонизатора, представляющий собой нативный JavaScript.
- Существует множество расширений для различных бандлеров (Vite, Webpack, ...) и редакторов кода для поддержки синтаксиса EJS.
- Общая простота конфигурирования и работы.
В общем это чистый JS -шаблонизатор, который заточен именно под шаблонизацию и ничего более.
Несколько примеров синтаксиса EJS
Сам по себе синтаксис представляет собой теги вида <% %>
(их есть несколько видов), внутри которых пишется простейший JavaScript. Например так (пример из документации):
<% if (user) { %>
<h2><%= user.name %></h2>
<% } %>
Тег вида <%= user.name %>
просто выводит значение user.name
с экранированием символов. Если нужно вывести без экранирования (часто не рекомендуется), то тогда используется тег вида <%- %>
В тегах <% %>
вы вполне можете написать любой удобный вам JS-код, для последующей более удобной его обработки в шаблонах. Например что-то вроде этого:
<%
const filteredData = […].map((elem) => …).filter((elem) => …).reverse();
%>
<ul>
<% for (let item of filteredData) { %>
<li><%= item %></li>
<% } %>
</ul>
Для использования других шаблонов (скорее подшаблонов) в коде, в EJS есть специальная функция include()
:
<body>
<%- include('src/header.ejs', {title: 'Hello World'}) %>
<%- include('src/main.ejs') %>
<%- include('src/footer.ejs') %>
</body>
В примере выше можно заметить, что в include()
помимо пути к шаблону, можно передавать дополнительные данные этому шаблону для обработки и отображения.
В общем я постарался кратко показать, что примерно из себя представляет синтаксис EJS. В статье я не планирую дублировать всю документацию этого шаблонизатора и поэтому если вы хотите подробнее изучить возможности и синтаксис этого шаблонизатора, то тогда вам стоит обратить внимание на раздел документации на сайте EJS, там все достаточно кратко и понятно.
Почему я иногда для верстки использую именно EJS
При разработке верстки проекта, я использую EJS как шаблонизатор, выделяя определенные части на подшаблоны, с последующим их переиспользованием. Фактически такое разделение на подшаблоны в какой-то степени тоже можно представить как компонентный подход, хотя это и очень грубое сравнение.
Как я уже не раз упоминал, я предпочитаю подбирать инструменты в зависимости от решаемой задачи и того, как это будет дальше будет поддерживаться. Когда я делаю веб-приложение, я беру тот же Vue (+ кучу еще всяких расширений к нему) и клепаю нужные компоненты. Но вот если мне нужно сделать простую верстку которую я затем буду передавать другому специалисту, то тут надо обходиться по возможности максимально простыми и доступными всем решениями. На то есть несколько причин:
- Человек который будет принимать верстку, не обязательно будет знать Vue. Если это backend-разработчик на каком-нибудь PHP или Python, то им зачастую нужны простые и ясные HTML-шаблоны. Ведь если такому разработчику который отвечает за бэкэнд, одни верстальщики будут высылать верстку в виде Vue-компонентов, другие в виде React-компонентов, а третьи вообще в виде Angular-компонентов, просто потому что им так удобно, то так можно и с ума сойти. А потом опять будем удивляться, почему некоторые бэкэндеры с ужасом смотрят на безумие фреймворков на фронтенде.
- Не все верстальщики знают именно Vue (React / Angular и т.д.). Т.е. для того, чтобы доработать вашу верстку или внести правки, верстальщику, который имел опыт только с React, волей-неволей придется будет копаться во Vue. Тут вообще надо учитывать тот факт, что жизненный цикл верстки не заканчивается на моменте ее передачи, ибо еще в течение некоторого времени скорее всего найдутся какие-либо баги которые нужно будет править, ну или в процессе появятся какие-либо доработки. И какое-то время это надо будет делать именно в исходнике верстки.
- Vue/React/Angular работают с виртуальным DOM и соответственно при наличии внешних сторонних скриптов, это может привести к конфликтам или усложнению кода. Для тех кто с этими фреймворками работает, в этом нет ничего особенного, ибо это рядовой случай, но для тех, кому нужна просто верстка, это становится излишним переусложнением.
Т.е. с вашей версткой в итоге могут работать как бэкендеры, так и другие фронтенд-разработчики, которые не факт что знакомы именно с вашим специфичным стеком технологий. И тогда лучше все-таки ограничиваться (в разумных пределах) теми технологиями, которые известны большинству в команде. В нашем случае, это все тот-же стек из HTML/JS/CSS. И соответственно тут как раз и становится удобен EJS, ибо у него синтаксис как раз представляет собой простейший JavaScript.
А вообще, EJS не только для верстки удобен, он также вполне неплох и при использовании в качестве шаблонизатора для фреймворка ExpressJS.
Маленький нюанс, который иногда меня раздражает в синтаксисе EJS
К сожалению при всех плюсах этого шаблонизатора, я не могу не упомянуть один навязчивый момент, который местами меня раздражает. А заключается он именно в некоторой неудобности фигурных скобок { }
, особенно когда их много:
<% if (!isHidden) { %>
<div>
<% for (let item of data) { %>
<div>
<% if (item === '...') { %>
<div>...</div>
<% } else { %>
<div>...</div>
<% } %>
</div>
<% } %>
</div>
<% } %>
В общем я имею ввиду что иногда в этих фигурных скобках можно запутаться. Тут я вспоминаю PHP, у которого в качестве встроенной шаблонизации можно использовать альтернативный синтаксис без использования фигурных скобок:
<?php if (!$isHidden): ?>
<div>
<?php foreach ($item of $data): ?>
<div>
<?php if (item === '...'): ?>
<div><?= item ?></div>
<?php else: ?>
<div>...</div>
<?php endif; ?>
</div>
<?php endforeach; ?>
</div>
<?php endif; ?>
Тут конечно достаточно многословно, но эти endif;
endfor;
endforeach;
вместо кучи безликих закрывающих скобок, местами облегчают чтение кода, особенно если шаблон немаленький и довольно-таки сложный.
Но это я просто поделился с вами своими мыслями, ибо все это вкусовщина и кому-то вариант с фигурными скобками может казаться существенно удобней. Да и в общем-то это является чужеродным синтаксисом для JS, что в чем-то нарушает саму идею шаблонизатора EJS в плане использования нативного синтаксиса JS.
Заключение
Резюмируя, я хочу сказать, что компонентные реактивные фреймворки, аля Vue/React/Angular - это безусловно отличные инструменты, дающие широчайшие возможности и которые я сам активно использую. Но все-таки в некоторых задачах их использование является местами чрезмерным.
В свою очередь EJS является старым и проверенным шаблонизатором, который достаточно прост и базируется на многим знакомом синтаксисе JavaScript. Т.е. если разработчик знает базовый JavaScript, то фактически он уже умеет пользоваться и EJS, что местами может оказаться немаловажным фактором в выборе именно этого инструмента.