На протяжении многих лет я разрабатывал веб-приложения на PHP, но в последнее время я больше занимался приложениями для iOS. Когда я вернулся к веб-разработке, то осознал, что очень соскучился по элегантности Objective-C и его структуры MVC.
Я смог найти похожую структуру для своего клиентского
JavaScript, но код на серверной части был ограничен моей зоной комфорта и PHP.
В PHP хороша его универсальность, а также низкий порог входа. Веб-приложение
можно заставить работать очень быстро, хотя сам код скоро может стать
чрезвычайно запущенным.
После каждой работы, которую я выполняю при помощи PHP, я
говорю себе: пора начать работать умнее. Тогда я начинаю изучать фреймворки для
PHP и размышляю о том, чтобы полностью перейти на совершенно новую платформу,
которая использует Java, Ruby или Python. Я начинаю колдовать над новым
подходом и создаю простые приложения. Неминуемо происходит следующее:
появляется новая работа, и мне приходится вернуться к PHP. Частично вина за это
лежит на мне, но в то же время это вина платформы, которую я пытаюсь изучить.
Я нашел точки входа для создания надежных приложений,
использующих другие, более продвинутые, чем PHP, языки. Частично поэтому PHP
является монстром индустрии, а Rails и Django используют обычно перфекционисты.
Помимо всех популярных альтернатив PHP, появилась
относительно новая - Node.js. Когда я начал возиться с Node несколько лет
назад, мне было приятно опираться на знания JavaScript, которые мне приходилось
использовать на стороне сервера. Однако Node никогда не казался реальным
конкурентом популярным языкам, когда речь шла о написании полного кода на
стороне сервера. Это было просто слишком ново и беспрецедентно.
Недавно я еще раз рассмотрел использование Node в качестве основного
языка для серверной стороны. Я был поражен его прогрессом и комьюнити. Он
достаточно развит, чтобы его можно было использовать в качестве важного
инструмента любому веб-разработчику. Он особенно полезен для UI- и
фронтенд-разработчиков. Пришло время снова покопаться в Node и посмотреть, не
разлучит ли он меня с PHP раз и навсегда.
Node:
вкратце
Установить и запустить Node на моем MacBook было очень
просто. Вот как выглядит установка для OSX:
// Install homebrew then Node
ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"brew install node
После этого вы будете готовы запустить код JavaScript на сервере. Приложение Node «Hello World» демонстрирует базовую
структуру кода и в то же время показывает, что это очень функциональный
веб-сервер. Имея всего 2 строки в терминале, вы получите всю мощь JavaScript и веб-сервер для
загрузки. Попробуйте поиграться. Откройте текстовый редактор и вставьте этот
код:
var http = require('http');http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello World\n');
}).listen(1337, '127.0.0.1');
console.log('Server running at http://127.0.0.1:1337/');
Сохраните файл как app.js и
введите в терминал:
node app.js
Загрузите ваш браузер и зайдите на http://localhost:1337
, и вуаля!
Сейчас вы можете спросить: «Хорошо, что теперь?» По крайней
мере я так и сделал, когда впервые опробовал Node. Я не знал и не понимал, как
применить какие-либо из моих существующих знаний о том, как создать
действительно правильное веб-приложение из этого примера.
NPM
Node становится действительно мощным, когда вы начинаете
добавлять к нему дополнения. Node Package Manager, или NPM, входит в комплект установки Node. Сообщество создало
несколько бесценных приложений, инструментов, фреймворков и промежуточного ПО,
чтобы помочь разработчикам UI сосредоточиться на ключевых задачах, создании
отличного пользовательского опыта. Если у вас есть опыт работы с composer при
создании веб-приложений на PHP, то использование NPM у вас не вызовет
трудностей. NPM использует файл package.json для описания метаданных вашего
приложения и, что наиболее важно, зависимости. Вы можете отредактировать этот
файл вручную и заполнить зависимости по своему усмотрению, как если бы вы
использовали файл composer.json. Вы также можете установить пакеты из командной
строки следующим образом:
npm install <package_name> --save
Обычно я добавляю опцию — save, чтобы пакет был добавлен в
список зависимостей в файле package.json.
Помимо веб-приложения, в NPM есть несколько замечательных
серверных приложений, которые упростят вам жизнь. Вы можете установить пакеты в
локальном каталоге приложения или выбрать глобальную установку. Глобальная
установка даст вам доступ к пакету из командной строки (вам нужно будет
добавить папку bin NPM в PATH терминала). Установка пакета в целом выглядит
так:
npm install -g <package_name>
После того как вы научились управлять пакетами, нужно будет
установить несколько важных вещей, прежде чем начать работать с Node.
Создание и
портирование вебсайтов
Я не так уж и давно начал разбираться в Node, но я нашел
важные вещи, которые помогут двигаться в правильном направлении. Я подобрал
самые полезные из них.
Express
Возможно, наиболее важным компонентом построения успешных
веб-приложений в Node является Express. Это пакет, который базируется на Node,
добавляя некоторые важные структуры для создания веб-приложений. Сам Node
делегирует большую часть ответственности веб-сервера программисту. Express
основан на middleware под названием Connect,
который заполняет этот пробел, поэтому разработчикам не нужно беспокоиться о
мелких деталях анализа ввода и обслуживания страниц. Вдобавок ко всему, Express
предоставляет очень удобную платформу для разработчика, чтобы код был богатым,
стабильным и понятным. Де-факто Express стал стандартом для создания
веб-приложений в Node. Я бы не стал создавать веб-приложение без него.
Nodemon
Запуск и тестирование приложения в PHP или Node сильно
отличаются. Обычно с PHP вы разрабатываете некоторый код, затем переходите в
браузер и обновляете страницу. Время от времени вам может понадобиться изменить
конфигурацию Apache и перезапустить веб-сервер. Процесс в Node довольно сильно
отличается. Поскольку веб-сервер и приложение объединены в один компактный
пакет, изменение кода стало означать необходимость перезапуска всего
веб-приложения, а также и веб-сервера. Когда я изучал основы, казалось, что
процесс нужно было постоянно "убивать", нажимая стрелку вверх, чтобы
перейти к последней команде, а затем Enter, чтобы перезапустить приложение
(цикл: [Ctrl + C] [Up] [Enter]). Это быстро стало надоедать. Для того, чтобы
люди делали удобную работу в Node, этот момент было необходимо улучшить. К
счастью, именно здесь поможет Nodemon. Установите Nodemon, используя NPM, и
вместо запуска своего приложения используйте:
node app.js
Далее примените:
nodemon app.js
Это приложение
будет отслеживать перемены в коде и автоматически перезапустит Node. Все очень
просто и важно.
Swig
Когда я создавал веб-приложения на PHP, я выбирал шаблонный
движок Twig от SensioLabs. Это был компонент фреймворка
Symfony, благодаря которому сборка внешнего интерфейса HTML становилась проще.
Twig был важным инструментом для меня. Если я собирался перенести какой-либо из
моих существующих проектов на Node, мне пришлось повторно использовать шаблоны
представлений, которые у меня уже были. Swig сделал этот переход невероятно
простым. Почти каждая часть Twig, которую я использовал, была доступна в Swig.
Мне пришлось внести пару небольших изменений в код шаблона, но в целом он был
готов сразу же. Он полностью совместим с Express.
Существует прямой порт Twig в Node, но, к сожалению, этот
проект остановился. Swig очень активно обновляется, поэтому я решил
использовать его и дальше.
MySQL для
Node
Когда вы читаете о Node, в большинстве случаев он связан с
базами данных типа NoSQL, такими как MongoDB. В дальнейшем я, скорее всего,
буду использовать Mongo просто из-за потрясающей библиотеки Mongoose. Она упрощает
управление моделями в веб-приложениях. Однако, учитывая, что у меня есть
несколько устаревших проектов для управления и портирования, я хочу сохранить
как можно больше программ. Значит, мне нужно сохранить существующие схемы и
данные MySQL. Доступно несколько пакетов MySQL, но, мне кажется, felixge
обладает всеми нужными функциями.
PassportJS
Почти все веб-приложения в наши дни имеют какую-то связь со
сторонними API. Аутентификация с помощью этих сервисов имеет свои проблемы. К
счастью, в PHP доступно множество пакетов, облегчающих доступ к этим API. С
Node вам действительно нужно заботиться только о PassportJS. Это совместимый с
Express пакет, который позволяет проходить аутентификацию практически в любом
месте в Интернете. Вы даже можете использовать его для аутентификации своего
локального входа в систему и управления сеансами, если это будет необходимо.
Мне кажется, этот инструмент бесценен при аутентификации на других сервисах,
таких как Twitter, Instagram и Facebook. Считается, что это дополнение может
аутентифицироваться на 140 различных сервисах. Маст-хэв для любого разработчика
веб-приложений.
Начало
работы
После того как я разобрался в основах Node и познакомился с
новой платформой, я был готов начинать создание приложений. Я потратил где-то
день на изучение книг о NodeJS и разработку пару примеров с помощью Express.
Так как я уже понимал основы механики платформы, теперь нужно было перенести
сюда одну из моих старых работ. На то, чтобы перенести многоязычный сайт малого
или среднего размера, ушло около 2-3 дней. Скорость портирования сайтов,
несомненно, будет увеличиваться по мере того, как я буду знакомиться с
процессом и структурами Node и Express. Тем, кто переходит с PHP или Node для
которых является первой платформой, будут полезны следующие замечания.
Синхронный или
асинхронный?
Одной из крупнейших перемен, которые мне необходимо было
осознать, является конвертация синхронного кода на PHP в асинхронный
JavaScript-код. Node – это неблокируемая система с событийными циклами и
одиночным потоком. Из-за этого любому действию не нужно блокирующее действие,
чтобы вернуть данные перед выполнением следующей строки кода. Все строки кода
выполняются сразу же, друг за другом. Здесь уже нет идеи о том, что запрошенные
данные будут доступны в следующей строке кода. Здесь-то вам и пригодится опыт
фронтенд-разработок на JavaScript. Как и в случае с клиентской стороной,
события управляются функциями обратного вызова. То же касается и кода
JavaScript на сервере. Чтобы создать синхронный код на JavaScript,
последовательность событий необходимо поместить в функции обратного вызова.
Например:
// PHP
$sql1 = "SELECT user_id FROM users WHERE email=?";
$stmt = DB()->prepare($sql);
$stmt->execute(array($email));$sql2 = "SELECT photo_id FROM photos WHERE user_id=?";
$stmt = DB()->prepare($sql);
$stmt->execute(array($user_id));
Что и требовалось ожидать. PHP выполнит первый запрос и дождется
его результата, а затем использует полученные данные во втором запросе. В Node запросы должны
находиться в обратных вызовах по завершению:
var sql1 = "SELECT user_id FROM users WHERE email=?";
connection.query(sql1, [email], function(err, rows)
{
var sql2 = "SELECT photo_id FROM photos WHERE user_id=?";
connection.query(sql2, [rows[0].user_id], function(err, rows)
{
console.log(rows); // output all the photos
}
}
Вам может показаться, что код такого типа со временем станет
громоздким, когда нужно будет выполнять большое количество асинхронного кода.
Вы правы. Эту проблему решает использование объектов promise.
Баги – это очень
плохо
Так как Node – это система одиночного потока, важно иметь в
виду, что если в коде обнаружится необработанное исключение, то программа на
Node «упадет» для всех, а не только для того, кто вызвал катастрофу. В PHP,
Apache, Nginx дело обстоит иначе, так как «отмирает» ветка, которая занималась
запросом, а не весь процесс. На среду разработок в Node это чаще всего не
влияло, но вдохновляло вас тщательно искать баги. А вот в эксплуатационной
среде это может иметь разрушительный эффект, так как веб-приложение «упадет»
для всех пользователей, которые посещают сайт. Чтобы справиться с этой
проблемой, нужно создать слушателя для всех необработанных исключений. Он и
будет ими заниматься. Код выглядит так:
process.on('uncaughtException', function (err) {
console.log('Caught exception: ' + err);
});
Данный шаг будет гарантировать, что приложение будет
работать даже в случае чего-либо неожиданного.
Правила замены
Один из мощнейших аспектов веб-разработки – способность
заменять хаотичные URL на более аккуратные. Это приводит в восторг поисковые
системы и пользователей. PHP не волновал внешний вид ссылок, ему просто нужны
были входные значения. Заменой ссылок можно было заняться в Apache или Nginx.
При использовании Node для разработки веб-приложений направлять запросы
помогает маршрутизация Express. Мне показалось, что управление маршрутами через
серверную часть кода программы, – очень интересная перемена. Разобравшись с
этой идеей, вы больше никогда не захотите снова писать правила маршрутизации
через входную точку <VirtualHost>
.
Вот небольшой пример:
RewriteRule ^/blog/([A-Za-z-]+)$ /blog/entry.php?slug=$1
С
использованием маршрутизации Express:
app.get('/blog/:slug([A-Za-z-]+)', blogController.entry);
Вам больше не придется носиться с маршрутизацией запросов
между веб-сервером и кодом приложения.
Запуск нескольких
сайтов Node на одном сервере
Поскольку Node является как процессором кода, так и
веб-сервером, встроенным в него, может возникнуть проблема при запуске
нескольких сайтов в одной среде. Для запуска веб-сервера Node необходимо
выбрать порт для запуска запросов. Запустив сайт на порту 80, вы не сможете
сделать второй сайт с тем же портом. Кто-то может просто сказать вам: получите
новый VPS для каждого веб-сайта, учитывая, что сейчас они очень доступны.
Однако во многих случаях VPS может вызвать проблемы на сайте. В этих случаях вы
можете выбрать запуск стандартного веб-сервера, такого как Apache или Nginx, и
передавать запросы в Node через прокси. Я выбрал прокси с использованием
переписывания Apache, потому что я часто его применяю. Вот как
выглядит пример записи <VirtualHost>
:
<VirtualHost *:80>
ServerName example.com
ServerAlias another-example.com
DocumentRoot /my/folder/
RewriteEngine On
RewriteRule ^(/.*)$ http://%{HTTP_HOST}:1337$1 [P]
</VirtualHost>
В nginx
будет нечто такое:
server {
listen 80;
server_name your-domain.com;
location / {
proxy_pass http://localhost:{YOUR_PORT};
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection ‘upgrade’;
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}
Также можно использовать подход JavaScript с помощью пакета Node-Http-Proxy. Используйте то, что больше приходится вам по душе.
Ищите, и вы точно
найдете
Одна из самых захватывающих частей программирования в Node —
это его комьюнити. Там так много всего происходит, причем очень быстро. Когда я
портировал свой первый сайт, я сталкивался с проблемой и спрашивал: «Как мне
это сделать в Node?». Я просто гуглил, какой бы ни была моя проблема, и был
уверен, что через несколько секунд у меня будут ответы. Я никогда не
сталкивался с проблемой, которую просто невозможно было решить с помощью Node.
Это свидетельствует о достигнутом прогрессе. Если вы столкнулись с проблемой,
просто гуглите ее. Несомненно, у кого-то найдется решение.
Заключение
Потратив
3-4 дня на Node и его дополнения, я был потрясен тем, как просто запустить
рабочий сайт. Барьер входа для разработки веб-приложений в Node еще не такой
низкий, как в PHP, но стремится к тому же! Знания, которые вы получите, поняв
менеджеры пакетов и фреймворки MVC, чрезвычайно важны для современных
веб-разработчиков. Только из-за этих двух концепций барьеры PHP или Node
различаются. Node+Express заставляют выучить эти концепции, перед тем как
начать разработку. Это замечательно для разработчика и его программ.
Наконец,
думаю, важно понимать, почему веб-разработчикам (в особенности UI- и
фронтенд-разработчикам) нужно писать серверный код на JavaScript.
Полный контроль
Большинство
UI-разработчиков уже знают все подробности и нюансы JavaScript. Использование
этих знаний при подготовке серверного кода увеличивает продуктивность. Кроме
того, судя по моему опыту, бизнес- и бекенд-разработчики обычно брезгуют
использованием UI-кода при создании сайтов. Они скорее фокусируются на
разработке основных функций приложения. Создание программ в Node позволяет
UI-разработчику «захватить» часть серверного приложения про интерфейс.
Функционал приложения можно полностью отделить от интерфейса, получить к нему
доступ через API. Отделение бекенда от фронтенда позволяет каждому разработчику
выбрать желаемую платформу для выполнения работы.
Учитывая
этот мой опыт, я решил перенести все мои будущие проекты на Node, где это
возможно, и использовать для UI-разработок платформу, полностью связанную с
JavaScript. Этот язык чрезвычайно важен для создания хорошего пользовательского
впечатления. Теперь им можно пользоваться и для создания серверной части кода.
Честно говоря, я считаю, что этот язык станет главным для разработки
фронтенд-приложений. Благодарю комьюнити разработчиков, которые своим трудом
сделали все эти великолепные инструменты, чтобы такие, как я, с помощью них
создавали замечательные сайты.