Октябрь 2016

Том 31 номер 10

Работающий программист - MEAN: исследуем Yeoman

Тэд Ньюард | Октябрь 2016

Тэд НьюардС возвращением, дорогие «министы».

Как я упоминал в предыдущей статье, пора сделать шаг, как в комиксах, и совершить реткон1 — распространенный прием в сериалах, когда для продолжения сюжета нужно что-то изменить в его начале, чтобы развивать его и дальше. В данном конкретном случае необходимый нам реткон — задействовать некоторые из инструментов, которые следовало бы использовать с самого начала, но которые мы не применяли, так как я счел необходимым обойти определенные части, чтобы последовательно рассказать об остальных.

Например, один вопрос, который встречался в ваших сообщениях по электронной почте, заключается в том, насколько сильно разработка под MEAN отличается от таковой под традиционную .NET. Один из комментаторов зашел так далеко, что указал мне на то, что в Visual Studio есть все шаблоны проектов, способных снять большую часть бремени по организации исходного кода. Так, в ASP.NET MVC давным-давно решили, в каком каталоге должны находиться контроллеры, чтобы любой разработчик, использующий ASP.NET MVC и открывший любой проект ASP.NET MVC, точно знал, где находится та или иная его часть.

На этой ноте я начинаю обсуждение Yeoman, утилиты скаффолдинга в ECMAScript, которая служит той же цели, что и механизм шаблонов проектов в Visual Studio. (Для тех, кто не знаком с этимологией слова «yeoman», привожу определение из одного словаря: «слуга в королевском или аристократическом доме, занимающий место между сержантом и конюхом или между сквайром и мальчиком на побегушках». По этой причине в утилите Yeoman, ее документации и на сайте проявляется тенденция подавать себя в стиле кокни.)

Получите свой Yeoman

Как почти все во вселенной JavaScript, Yeoman является утилитой командной строки, устанавливаемой через npm. Документация на Yeoman доступна на yeoman.io, но первый шаг уже очевиден и так: выполнение команды npm install --g yo. После этой команды утилита командной строки yo будет вписана в PATH, и самый простой способ проверить, что она установлена, — просто запустить ее. Команда yo --help выдаст обычный список параметров, но на самом деле запуск yo самой по себе будет интереснее: на экране появится интерактивное меню командной строки с командами, которые Yeoman может выполнить за вас (рис. 1).

Yeoman с командами выполнения
Рис. 1. Yeoman с командами выполнения

При новой установке для Yeoman пока не установлены никакие генераторы (в противоположность моему списку на рис. 1, где уже есть несколько генераторов), но прокрутка вверх и вниз (с помощью клавиш-стрелок) покажет некоторые другие варианты, такие как «Install a generator», «Find some help» или «Get me out of here!». Yeoman очевиден, как ничто другое.

Термин «генератор» вполне уместный и подходящий; как и Visual Studio, Yeoman сама по себе не знает, как генерировать что-либо. Вместо этого она полагается на «генераторы» — пакеты, созданные сообществом и состоящие из скриптов и шаблонов, которые могут запросить у пользователя всю специфику того, что нужно сгенерировать. Однако, чтобы Yeoman использовал один из этих генераторов, он должен быть установлен в локальной системе. Кроме того, чтобы его установить, следует выяснить, какой именно из почти 4000 генераторов (на момент написания этой статьи) нужен конкретно вам.

Поиск генераторов

Хотя вы определенно можете предложить Yeoman выполнить поиск генераторов в npm (это один из вариантов в командной строке при запуске Yeoman), как правило, проще переложить это на поисковые системы или просто воспользоваться браузером и зайти на сайт Yeoman (yeoman.io/generators). Поэтому, например, если вы хотите, чтобы Yeoman сформировал шаблон для нового MEAN-приложения, то должны найти генератор, который поддерживает Angular (v1 на данный момент) и MongoDB. Как оказалось, на момент написания этой статьи самый популярный такой генератор — angular-fullstack, который находится почти в самом верху списка. Однако, если это не ваш случай или вам требуется нечто другое (скажем, генератор с поддержкой React или для расширения Chrome, или даже ASP.NET Core), вы могли бы поискать его на странице generators сайта Yeoman. Например, вам может понадобиться разбить код на два проекта: один для Web API серверной части, а другой для Angular на клиентской стороне. Это означало бы, что вам нужен проект «Express плюс MongoDB» (иногда называемый проектом MEN), для которого доступна пара генераторов, в том числе express-api или node-express-mongo, плюс другой генератор, который способен создавать клиентскую часть Angular.

1Реткон (retcon, retroactive continuity) — намеренное изменение ранее установленных фактов при работе над многосерийным сюжетом. — Прим. ред.

А пока вам нужен генератор angular-fullstack, поскольку он сгенерирует шаблоны как клиентской, так и серверной части. Как только вы выяснили, какой генератор вам нужен, вы должны установить его с помощью npm. (Yeoman не использует yo для управления установкой генераторов — в этой задаче он полагается на npm.) Таким образом, следующий шаг — выполнение команды npm install --g generator-angular-fullstack. Обратите внимание на префикс «generator-»; это соглашение для всех пакетов генераторов Yeoman.

После установки Yeoman может использовать этот генератор, просто ссылаясь на него (без префикса «generator-») в качестве параметра в команде yo angular-fullstack. В этот момент Yeoman передаст управление самому генератору, и в случае angular-fullstack вам будет задан ряд вопросов.

  • Что использовать — Babel или TypeScript?
  • Что использовать для разметки — HTML или Jade (популярная JavaScript-библиотека для генерации HTML-шаблонов)?
  • Какое CSS-средство следует задействовать (чистый CSS, Sass, Stylus или Less)?
  • Какой Angular-маршрутизатор следует использовать — ngRoute или uiRouter?
  • Включать ли Bootstrap?
  • Включать ли UI-Bootstrap (расширение Angular для Bootstrap)?
  • Что использовать для моделей в приложении — Mongoose (вы уже знакомы с ним) или Sequelize (моделирование для реляционных СУБД)?
  • Надо ли генерировать код аутентификации через Passport, и, если да, то для каких сервисов — Google, Twitter или Facebook?
  • Что использовать в качестве инструмента сборки проекта — Grunt или Gulp (о втором я расскажу в следующий раз)?
  • Наконец, какие средства тестирования следует применять (Jasmine или набор из нескольких библиотек)?

По окончании сеанса вопросов-ответов Yeoman сгенерирует множество файлов (большинство из которых попадут в созданные каталоги client или server). Затем он запустит npm install для получения всех зависимостей для сервера и выполнит bower install (это может потребовать установки bower командой npm install –g bower), чтобы сделать то же самое для клиента. Заметьте: поскольку зависимости, получаемые на этих этапах, будут варьироваться в зависимости от точной версии генератора (и различных библиотек, на которые делаются ссылки из сгенерированного кода), вполне возможно и даже очень вероятно, что на этих этапах будут генерироваться предупреждения.

Однако по окончании вы получите полностью сформированный каркас (scaffolded) приложения. Он не делает ничего особенного, но, если вы запустите его с gulp serve, как указано в сгенерированном файле README (это потребует установки Gulp командой npm install –g gulp-cli), и если на локальной машине в изолированной среде выполняется MongoDB, то этот каркас приложения выведет страницу, похожую на ту, которую генерирует шаблон проекта ASP.NET MVC (рис. 2).

Клиентская часть сформированного каркаса приложения
Рис. 2. Клиентская часть сформированного каркаса приложения

Заметьте, что она имеет полную поддержку управления пользователями, включая возможность аутентификации через Google, Facebook или Twitter (однако использование каждого из этих провайдеров потребует получения от них соответствующих маркеров или ключей удостоверений и их указания в каталоге конфигурации в серверном коде) или с применением адресов электронной почты/паролей.

Добавление объектов speaker

Поскольку создаваемое вами приложение является в своем роде рейтинговой системой докладчиков (speaker-rating system), первым делом нужна модель объекта speaker в этой новой кодовой базе. И хотя вы могли бы начать с поиска в сгенерированных файлах того, где объявляются модели и прочее, гораздо проще позволить Yeoman помочь вам в этом: yo angular-fullstack:endpoint speaker. Он спросит, что вы хотите использовать для URL конечной точки API, а затем сделает то, что вы скажете. Это эквивалентно аналогичной операции в ASP.NET MVC, где после щелчка правой кнопкой мыши вы выбираете Add Controller. Yeoman сгенерирует некоторые файлы-заготовки в server/api/speaker, которые вы модифицируете так, как вам нужно.

Генератор angular-fullstack может делать это для целого ряда других элементов приложения — как на серверной стороне, так и на клиентской. Полный список «субгенераторов» можно увидеть, запросив у самого генератора список командой yo angular-fullstack --help.

Разметка

Поскольку я еще толком не исследовал клиентскую сторону, я пока так и оставлю ее. Но серверную сторону я исследую уже некоторое время, так что без лишних предисловий погрузимся в нее.

Весь серверный код (что не удивительно) содержится в каталоге server. Этот каталог хранит основной файл приложения, app.js, список Express-маршрутов в routes.js и несколько подкаталогов, содержащих остальной код серверной стороны. Эти подкаталоги включают api (где находится код, относящийся к модели и контроллеру), auth (код аутентификации), components (будет содержать компоненты, не относящиеся к API), config (конфигурация) и views (который содержит лишь файл 404.html на случай обнаружения неизвестных URL в запросах).

Каталог auth, в целом, уже заполнен всем необходимым; необходимость просмотра этого каталога возникает очень редко (если вообще возникает). Как и подразумевает название, config содержит конфигурационные значения, используемые остальным приложением во многом аналогично файлу config.js, создававшемуся мной в прошлых статьях этой рубрики. В основном вы будете иметь дело в подкаталогом api.

В api вы найдете три подкаталога: speaker (только что созданный вами), user (специально для моделирования пользователей) и thing (автоматически генерируемый за вас генератором в качестве шаблона или образца, которому вы должны следовать). В каждом из этих подкаталогов каталога api вы найдете набор файлов с «двойным расширением»: thing.controller.js, thing.events.js, thing.model.js и т. д. Кроме того, там будет файл index.js, который служит своего рода единой точкой входа для всего подкаталога (он объединяет все остальные файлы, чтобы вам было проще ссылаться на них из остального содержимого каталога), и файл index.spec.js, используемый специально для проверки кода, найденного в этом каталоге.

Например, если вы хотите указать имя и фамилию докладчиков, а также список тем, по которым они предпочитают выступать, то можете открыть файл speaker.model.js и смоделировать его, используя стандартные средства Mongoose (я рассказывал о них в одной из прошлых рубрик), как показано на рис. 3.

Рис. 3. Mongoose-схема для объекта speaker

'use strict';

import mongoose from 'mongoose';

var SpeakerSchema = new mongoose.Schema({
  firstName: {
    type: String,
    required: true
  },
  lastName: {
    type: String,
    required: true
  },
  topics: [String],
  active: Boolean,
  created: {
    type: Date,
    default: Date.now
  },
  updated: Date
});

SpeakerSchema
  .pre('save', function(next) {
    this.updated = new Date();
    next();
  });

export default mongoose.model('Speaker', SpeakerSchema);

(Обратите внимание на использование ключевого слова export — это новинка в ECMAScript 2015, о которой я рассказывал в своей статье, см. msdn.com/magazine/mt422588.) Однако теперь, когда вы изменили модель для Speaker, вам нужно обновить тесты (в файле speaker.integration.js), а иначе тесты провалятся при попытке их запуска. Это упражнение я оставлю для вас как способ исследования кода; запускайте тесты командой gulp test:server, чтобы избежать запуска тестов клиентской стороны. Конечно, всегда можно исследовать API, используя curl (curl localhost:3000/api/speakers). Там будет пусто, пока вы не вставите нескольких докладчиков через POST по этой конечной точке или напрямую в MongoDB. Заметьте, что генераторы подвергаются постоянной доработке, поэтому будущие версии этого генератора будут задавать по умолчанию другой порт или URL.

Заключение

В этой статье было совсем немного кода, тем не менее вы только что перезагрузили все приложение, получили целую тонну функциональности и, по сути, вывели приложение на тот же уровень (и даже выше), до которого вы дошли за прошедший год или около того. Я обожаю скаффолдинг! Еще важнее, что последовательное создание вручную всех частей до запуска скаффолдинга значительно облегчает понимание кода в целом и того, что и где происходит. Например, routes.js будет выглядеть похожим на таблицу маршрутизации, которую вы создали ранее вручную, а package.json (в корне каталога проекта) будет больше, хотя в основном он останется тем же, что и использовавшийся вами.

Фактически, помимо применения самой утилиты Yeoman, единственная новая вещь — введение утилиты сборки всех релевантных частей воедино в правильном месте, и именно об этом мы поговорим в следующий раз. Ну а тем временем… удачи в кодировании!


Тэд Ньюард (Ted Neward) — глава фирмы Neward & Associates, предоставляющей консалтинговые услуги по самым разнообразным технологиям. Автор и соавтор многочисленных книг, в том числе «Professional F# 2.0» (Wrox, 2010), более сотни статей, часто выступает на многих конференциях по всему миру; кроме того, имеет звание Microsoft MVP в области F#. С ним можно связаться по адресу ted@tedneward.com или почитать его блог blogs.tedneward.com.

Выражаю благодарность за рецензирование статьи эксперту Шону Уайлдермуту (Shawn Wildermuth).