Несколько лет назад я, как и многие люди, начал все больше и больше слышать о Node.js. Я создавал серверные приложения в ColdFusion более десяти лет, но мне всегда было любопытно посмотреть, как работают другие платформы. Мне понравился JavaScript на клиенте, и его использование на сервере показалось мне увлекательным. (Хотя и не обязательно новый. Я достаточно взрослый, чтобы помнить, когда Netscape выпустил SSJS еще в 90-х годах.) Я прочитал несколько уроков, провел несколько сессий и вообще ушел … не впечатлил.
Каждый раз, когда я что-то читал об Node, все возвращалось к одной и той же истории: созданию веб-сервера. Честно говоря, это не было захватывающим. Даже когда я впервые делал веб-приложения на скриптах Perl CGI, мне не пришлось об этом беспокоиться. Я мог видеть потенциал в небольших, легких провайдерах API, но мог бы я создать на нем простой сайт? Ни за что!
Но однажды мне повезло. Я решил сесть на еще одну презентацию Node (в основном потому, что хорошо знал докладчика), и во время его презентации спикер продемонстрировал Express . Лампа погасла. Здесь была структура Node, которую я ждал! Да, теоретически вы все еще создаете свой собственный веб-сервер, но этот аспект сведен к минимуму, и вместо этого вы можете сосредоточиться на логике и содержании вашего сайта. Более того, я видел, как интеграция шаблонизаторов позволяет работать почти с ColdFusion (или PHP). В этой статье я покажу вам, как установить Express и как начать создавать веб-приложения с использованием фреймворка.
Установка
Скорее всего, вы уже разработчик Node. Если вы новичок в платформе, то вы все равно можете быть в восторге от силы npm. Я знаю, что я есть. Как я уже говорил, большую часть своей жизни я провел в ColdFusion. Для этой платформы существует богатая, если не большая, экосистема открытого кода. Но поиск и установка — дело рук. Первые несколько раз, когда я использовал npm, я был в восторге. Честно говоря, сейчас мне трудно представить себе платформу без такого инструмента, как npm. Начнем с файла package.json
который мы добавим зависимость Express.
1
2
3
4
5
6
7
8
|
{
«name»: «demo1»,
«description»: «First Express app»,
«version»: «0.0.1»,
«dependencies»: {
«express»: «3.x»
}
}
|
Опять же, это должно быть достаточно стандартным для разработчиков Node. Спуститесь в командную строку и запустите:
1
|
npm install
|
Который установит Express и его зависимости.
И наоборот, вы также можете установить Express как инструмент командной строки для быстрой генерации скелетных приложений. Это можно сделать, запустив:
1
|
npm install -g express
|
Как только вы это сделаете, вы можете запустить express
в командной строке, чтобы сгенерировать приложение.
Первые шаги
Вернемся к приложению, которое мы создали с помощью предыдущего файла package.json
и добавим файл app.js
Как минимум, ваше приложение создаст новый экземпляр объекта Express и начнет прослушивать определенный порт. Давайте начнем с этого:
1
2
3
4
|
var express = require(‘express’);
var app = express();
app.listen(3000);
|
Лично я, как правило, воспринимаю новую среду довольно медленно, поэтому может иметь смысл быстро запустить node app
чтобы убедиться, что ничего не испорчено.
Определение наших маршрутов
Теперь давайте попробуем добавить несколько простых маршрутов в приложение. Приложения Express могут реагировать на различные HTTP-глаголы как методы API. Итак, в качестве примера:
1
2
3
4
5
6
7
8
|
//Regular HTTP get
app.get(some url, do something);
//Some other page
app.get(some other url, do something else);
//I can respond to a form post
app.post(some url, do more stuff);
|
Давайте создадим реальный пример этого и добавим домашнюю страницу в приложение:
1
2
3
|
app.get(‘/’, function(request, response) {
response.send(«This would be some HTML»);
});
|
Обратите внимание, что Express добавляет простой метод send()
к объекту response
. Это абстрагирует часть стандартного кода для обработки ответов. Если вы все сделали правильно, теперь вы можете перезапустить приложение и открыть браузер для порта 3000.
API request.send()
также интеллектуально обрабатывает различные типы данных. Представьте, что вы хотите добавить на свой сайт простой API на основе JSON. Просто возвращая объект вместо строки, Express выполнит преобразование результата в JSON, а также установит соответствующие заголовки ответа.
1
2
3
|
app.get(‘/api’, function(request, response) {
response.send({name:»Raymond»,age:40});
});
|
Как вы можете себе представить, на этом этапе создание приложения будет состоять из добавления все большего и большего количества маршрутов для обработки любых ваших потребностей. Давайте создадим очень простой статический сайт, который использует то, что мы изучили до сих пор.
Generic Blog App 9000
Для нашего первого сайта мы создадим блог. Да, это не ужасно новое и не захватывающее, но это также то, что каждый концептуально понимает. Вы можете найти полный исходный код этого приложения в прилагаемой загрузке в папке blog1 . Мы пропустим файл package.json
как он точно такой же, за исключением имени. Давайте вместо этого посмотрим на app.js
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
|
var express = require(‘express’);
var app = express();
app.get(‘/’, function(req, res) {
res.sendfile(‘./views/index.html’);
});
app.get(‘/about’, function(req, res) {
res.sendfile(‘./views/about.html’);
});
app.get(‘/article’, function(req, res) {
res.sendfile(‘./views/article.html’);
});
app.listen(3000);
|
Первое, что вы заметите, это то, что мы перешли с send
api на sendfile
. Хотя мы могли бы вставлять большие HTML-строки в наш файл app.js
, это было бы чертовски быстро. У нас есть три маршрута для этого приложения. Один для домашней страницы, один для страницы «О нас» и один для статьи. Как правило, страница статьи представляет одну запись в блоге, но пока мы делаем все просто.
Добавление в HTML
HTML-код для наших страниц также довольно прост. Вот домашняя страница:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
|
<html>
<head>
<title>Home Page</title>
</head>
<body>
<h1>Blog!</h1>
<footer>
<p>
<a href=»/»>Home</a> ~ <a href=»/about»>About Me</a> ~ <a href=»/article»>Some Article</a>
</p>
</footer>
</body>
</html>
|
Обратите внимание, что здесь нет ничего особенного. Это простой статический HTML, который будет возвращен приложением Express как есть. Страницы как О, так и Статьи одинаковы за пределами изменений заголовка и значений h1
.
Еще раз, запустите это в командной строке и откройте ваш браузер. (Кстати, одна из распространенных ошибок, которые я сделал при первом изучении Node, заключалась в том, чтобы забыть убить мои предыдущие демонстрации. Если вы все еще запускаете последнее приложение, оно будет содержать порт 3000. Либо уничтожьте его, либо используйте другой порт для этого. Приложение.) Вы должны иметь возможность просматривать это простое приложение в несколько простых кликов.
Теперь давайте перейдем от статического к динамическому.
От статического к динамическому
Express поддерживает множество шаблонизаторов. Шаблонные движки похожи на многие вещи в мире технологий — на один шаг ниже, чем религия и политика. В экспресс-командной строке можно добавить поддержку Jade, EJS, JSHTML и Hogan. Согласно документации Express, любой шаблонизатор, который соответствует определенной подписи, будет работать с ним. Они также рекомендуют проверить библиотеку Consolidate.js на наличие списка поддерживаемых шаблонизаторов.
Лично я большой поклонник Handlebars (handlebarsjs.com). Я использовал его во многих клиентских приложениях, и это было естественно для меня, чтобы использовать на стороне сервера. Чтобы использовать Handlebars, вам нужно установить библиотеку-оболочку hbs . Давайте добавим это в наше приложение.
1
2
3
4
5
6
7
8
9
|
{
«name»: «blog2»,
«description»: «Blog app»,
«version»: «0.0.1»,
«dependencies»: {
«express»: «3.x»,
«hbs»:»*»
}
}
|
Теперь давайте обновим наш app.js
чтобы использовать этот движок:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
|
var express = require(‘express’);
var app = express();
var hbs = require(‘hbs’);
app.set(‘view engine’, ‘html’);
app.engine(‘html’, hbs.__express);
app.get(‘/’, function(req, res) {
res.render(‘index’);
});
app.get(‘/about’, function(req, res) {
res.render(‘about’);
});
app.get(‘/article’, function(req, res) {
res.render(‘article’);
});
app.listen(3000);
|
Мы сделали несколько важных вещей здесь. Чтобы использовать Handlebars, мы загружаем (через require) библиотеку оболочки HBS. Затем мы должны сказать Экспресс, чтобы использовать его. По умолчанию Handlebars будет работать с файлами, которые содержат расширение, соответствующее конкретному движку. В нашем случае something.hbs
. Но мы можем указать Express, чтобы он относился к HTML-файлам как к динамическим, используя директиву "view engine"
, как вы видели выше. Это не обязательно, но я предпочитаю работать с файлами HTML. Мой редактор может обеспечить более приятную подсказку кода и подсветку синтаксиса. На самом деле загрузка двигателя выполняется через app.engine
.
Наконец, все маршруты переключаются на использование нового метода render
. Express по умолчанию использует папку views, поэтому мы можем ее отключить. Так как Express также знает расширение, которое мы предпочитаем, мы также можем забыть об этом. По сути, res.render('something')
равносильно тому, чтобы Express res.render('something')
искать views/something.html
, анализировать его на основе правил нашего движка шаблонов и возвращать его в браузер.
Вы можете найти этот пример в папке blog2 , в прилагаемом исходном коде. Как я уже говорил, мне нравится делать маленькие шаги, поэтому, хотя мы на самом деле не делаем ничего динамичного, я рекомендую запустить это в командной строке и убедиться, что вы все еще можете просматривать сайт.
Отображение записей блога на домашней странице
Учитывая, что мы теперь поддерживаем динамические шаблоны, давайте фактически сделаем их динамическими. Так как мы создаем блог, мы должны добавить поддержку для перечисления набора записей блога на главной странице и позволить вам ссылаться на определенный движок блога. Хотя мы можем запустить соединение с MySQL или Mongo, давайте создадим статический набор данных, а также простую библиотеку-оболочку для него. Вот файл blog.js
который обеспечивает как получение набора записей, так и получение только одной.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
|
var entries = [
{«id»:1, «title»:»Hello World!», «body»:»This is the body of my blog entry. Sooo exciting.», «published»:»6/2/2013″},
{«id»:2, «title»:»Eggs for Breakfast», «body»:»Today I had eggs for breakfast. Sooo exciting.», «published»:»6/3/2013″},
{«id»:3, «title»:»Beer is Good», «body»:»News Flash! Beer is awesome!», «published»:»6/4/2013″},
{«id»:4, «title»:»Mean People Suck», «body»:»People who are mean aren’t nice or fun to hang around.», «published»:»6/5/2013″},
{«id»:5, «title»:»I’m Leaving Technology X and You Care», «body»:»Let me write some link bait about why I’m not using a particular technology anymore.», «published»:»6/10/2013″},
{«id»:6, «title»:»Help My Kickstarter», «body»:»I want a new XBox One. Please fund my Kickstarter.», «published»:»6/12/2013″}];
exports.getBlogEntries = function() {
return entries;
}
exports.getBlogEntry = function(id) {
for(var i=0; i < entries.length; i++) {
if(entries[i].id == id) return entries[i];
}
}
|
Как правило, у нас также есть методы для добавления, редактирования и удаления, но пока этого достаточно. Давайте теперь посмотрим на обновленный файл app.js
который использует этот движок.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
var express = require(‘express’);
var app = express();
var hbs = require(‘hbs’);
var blogEngine = require(‘./blog’);
app.set(‘view engine’, ‘html’);
app.engine(‘html’, hbs.__express);
app.use(express.bodyParser());
app.get(‘/’, function(req, res) {
res.render(‘index’,{title:»My Blog», entries:blogEngine.getBlogEntries()});
});
app.get(‘/about’, function(req, res) {
res.render(‘about’, {title:»About Me»});
});
app.get(‘/article/:id’, function(req, res) {
var entry = blogEngine.getBlogEntry(req.params.id);
res.render(‘article’,{title:entry.title, blog:entry});
});
app.listen(3000);
|
Давайте рассмотрим обновления по одному. (Эту версию можно найти в папке blog3 .) Сначала мы загружаем в наш движок быстрый вызов по требованию. Это дает нам возможность позвонить и получить записи. Вы можете заметить новую строку, вызывающую bodyParser
, но bodyParser
игнорируйте ее.
В маршрутизаторе нашей домашней страницы мы передали второй аргумент в API рендеринга. Аргумент является объектом с двумя ключами, title
и entries
. Значение для title — просто строка, но записи вызывают наш API blogEngine
. Здесь вещи становятся интересными. Любые данные, которые мы передаем здесь, будут доступны для наших шаблонов. В зависимости от языка вашего шаблона, особенности его использования могут меняться, но давайте посмотрим на домашнюю страницу.
1
2
3
4
5
6
7
8
|
<h1>Blog!</h1>
{{#each entries}}
<p>
<a href=»/article/{{id}}»>{{title}}</a><br/>
Published: {{published}}
</p>
{{/each}}
|
Если вы никогда раньше не пользовались Handlebars, вы, вероятно, можете догадаться, что здесь происходит. Директива #each
будет перебирать массив. Внутри блока я использовал комбинацию маркеров Handlebar, которые указывают на данные моего блога, а также HTML, чтобы сгенерировать простой список записей блога. Исходя из фона ColdFusion, это очень знакомо.
Создание макета
Могу поспорить, вы также задаетесь вопросом, куда ушёл остальной HTML. При использовании шаблонизаторов в Express вы получаете автоматическую поддержку макетов. Это означает, что я могу создать общий макет с дизайном своего сайта, и Express будет вставлять в него вывод определенной страницы. По соглашению это называется layout.something
где «что-то» — это конкретное расширение, которое вы используете. Поскольку мы использовали HTML, это будет просто layout.html
:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
|
<html>
<head>
<title>{{title}}</title>
</head>
<body>
{{{body}}}
<footer>
<p>
<a href=»/»>Home</a> ~ <a href=»/about»>About Me</a>
</p>
</footer>
</body>
</html>
|
Довольно гладко, верно? Страница About не интересна, поэтому мы пропустим ее, но ознакомимся с маршрутом статьи. Теперь в URL включен токен :id
. Express позволяет нам создавать динамические URL-адреса, которые затем могут отображаться для запроса аргументов. Вы заметите, что на главной странице мы определили ссылки, которые выглядели так: /article/{{id}}
.
Теоретически мы бы добавили один маршрут для каждой записи в нашем блоге, но гораздо лучше создать абстрактный маршрут, который будет соответствовать любому запросу этой конкретной формы. Чтобы получить доступ к этому значению, мы также добавляем еще одну часть, строку bodyParser
мы определили ранее. (Эта конкретная функция взята из среды Connect и на самом деле предоставляет вам небольшую помощь в поддержке как строки запроса, так и тела формы. Почти каждое приложение Express захочет включить это.)
Отображение отдельных статей
Поскольку мы получаем доступ к динамическому значению в конце URL-адреса, мы можем просто передать его объекту blogEngine
и использовать результат в качестве аргумента представления.
Вот файл article.html
:
1
2
3
4
5
6
|
<h1>{{blog.title}}</h1>
Published: {{blog.published}}
<p/>
{{blog.body}}
|
Теперь у нас действительно динамичное, но безобразное приложение. Вот наша новая домашняя страница:
А вот одна из конкретных записей в блоге:
Положите немного помады на эту свинью!
Давайте добавим немного базовых стилей в наше приложение, чтобы сделать его немного красивее. Express предоставляет простой способ добавить поддержку статических ресурсов, таких как изображения, библиотеки JavaScript и таблицы стилей. Путем простого определения статической папки любой запрос на файл будет проверен для этой конкретной папки перед сравнением с маршрутами. Вот пример из окончательной версии нашего блогового движка (который можно найти в папке blog4 ):
1
|
app.use(express.static(‘public’));
|
На этом этапе, если вы запрашиваете /foo.css
, а файл foo.css
существует в foo.css
папке, он будет возвращен. Поскольку мои навыки в области дизайна такие же, как у любого разработчика, я выбрал легкий путь и взял копию Bootstrap (http://twitter.github.io/bootstrap/). Я бросил его и копию jQuery в мою public
папку.
Затем в моем layout.html
я могу ссылаться на эти ресурсы. Вот один пример ссылки в bootstrap.css
:
1
|
<link href=»/bootstrap/css/bootstrap.css» rel=»stylesheet»>
|
Экспресс теперь будет автоматически проверять этот файл в public
папке. У вас может быть несколько статических папок, подобных этой, и даже вы можете настроить для них собственные префиксы URL. Результат — потрясающий. (Хорошо, по сравнению с первой версией, это огромное улучшение!)
Домашняя страница:
И статья:
Что дальше?
Хотите узнать больше? Вот несколько ссылок, которые могут быть полезны.
- Очевидно, что ваша первая остановка должна быть на главной странице Express .
- Вы можете присоединиться к группе Google, чтобы поговорить с другими разработчиками.
- Если вы хотите быть по-настоящему модным, присоединяйтесь к каналу IRC: #express.
- Наконец, вы можете посмотреть целую кучу примеров на GitHub .