Yeoman (відомий як yo) є інструментом скаффолдингу — з плагінами, відомими як генератори, Yeoman визначає як генерувати структуру проекту.
Щоб використовувати Yeoman, спочатку його треба встановити. Подібно до всіх пакетів npm ми можемо вибрати, встановити його глобально або в рамках нашого проекту. Але оскільки ми ще не маємо проекту, в цьому випадку має сенс встановити глобально:
<code>$npm install-g yo
Далі, ми встановлюємо генератор — оскільки для налаштування Gulp+Bower ми використовували jQuery та Bootstrap, то можемо скористатися встановленим генератором gulp-webapp .
Знову ж таки, установка здійснюється за допомогою npm:
<code>$npm install-g generator-gulp-webapp
Після встановлення генератора створіть порожню папку в якій буде наш проект і в ній виконайте:
<code>$ cd my-yeoman-project $ yo gulp-webapp
Спершу буде виведений логотип Yeoman намальований символами ASCII, а потім запитають, які бібліотеки крім HTML5 Boilerplate та jQuery ви хотіли б встановити.
За замовчуванням вибрано всі додаткові бібліотеки. Щоб зняти галочку, використовуйте клавіші керування курсором для виділення та натисніть пробіл. Як тільки це зробите, натисніть Enter... і на цьому все.
Тепер Yeoman згенерує gulpfile.js, налаштує Bower з вибраними залежностями та зробить заготівлю нашої програми.
>Після завершення папка нашої програми буде виглядати так:
<code>├── app │ ├── bower_components │ │ ├── bootstrap-sass-official │ │ ├── jquery │ └── modernizr │ ├── images │ ├── scripts │ │ └── main.js │ ├── styles │ │ ├── main.scss │ │ │ │ │ ├── favicon.ico │ ├── index.html │ └── robots.txt ├── dist │ ├── scripts │ └── styles ├── node_modules ├── ├── ─ .gitignore ├── bower.json ├── gulpfile.js └── package.json
З цього моменту ви можете перевірити результат генератора запустивши gulp для побудови всього необхідного, потім gulp serve для запуску веб-сервера на порту 9000.
Зробивши це ви перейдете на http://localhost:9000 і браузер покаже вам щось подібне:
Інші генератори
Все це добре, але що якщо нам потрібно створити новий проект заснований на фреймворку? Або з скаффолдингом користувача?
Спочатку ви повинні перевірити, чи існує генератор, який відповідає вашим потребам. Є ряд офіційно підтримуваних генераторів і більше 800 неофіційних.
Не варто турбуватися, якщо ви створюєте плагін Wordpress або односторінковий додаток за допомогою AngularJS, швидше за все, такий генератор вже зроблено. Якщо ні, то ви створюєте свій власний генератор.
Створення генератора користувача
Давайте зробимо генератор, який дозволить нам створити скелет програми за допомогою Composer для ряду популярних фреймворків.
Для початку потрібно буде використовувати yeoman generator-generator — так, генератор для генерації генераторів (йо, чувак...):
<code>$npm install-g generator-generator
Потім створіть папку для зберігання вашого генератора, вона повинна бути названа generator-<ім'я>, в нашому випадку ми збираємося створити папку з ім'ям generator-php-composer.
Тепер ми можемо використовувати generator-generator для створення скелета нашого генератора:
<code>$ mkdir generator-php-composer $ cd generator-php-composer $ yo generator
Відповідайте на пару запитань (ім'я користувача на GitHub та ім'я генератора) і все. templa tes │ └── index.js ├── node_modules │ ├── chalk │ ├── mocha │ ├── yeoman-generator │ └── yosay ├── test │ │ │ ─ test-load.js ├── README.md └── package.json
Досить стандартний проект Node.js — наша папка додаток містить згенерований код, також є node_modules для пакетів npm з обов'язковим package.json для їх управління, папка test та простий README.md.
Якщо ми перейдемо до файлу app/index.js і відкриємо його, то побачимо, що він досить простий:
- Імпортувати всі необхідні модулі npm;
- Створити об'єкт Generator — PhpComposerGenerator шляхом розширення yeoman.generators.Base;
- Визначити низку методів, які виконують конкретні завдання:
- init: витягнути в package.json та зареєструвати функцію зворотного виклику для запуску bower та npm; завершити після встановлення всіх інших завдань;
- askFor: запитати інформацію у кінцевого користувача;
- app: основні функції скаффолдінга;
- projectFiles: допоміжні функції скаффолдингу;
- Остаточно, експортувати генератор.
Yeoman буде виконувати кожен із заданих методів у порядку їх визначення та їхні імена не несуть сенсового значення.
Для нашого генератора ми не збираємося використовувати Bower або npm, так що оновимо метод init для видалення функції зворотного виклику. Крім того, перенесемо сюди наше вітання: init: function() { //Yeoman вітає користувача. this.log(yosay('Ласкаво просимо до генератора PHP Framework Composer!')); },
Тепер оновимо метод askFor для збору деякої інформації від нашого користувача.
<code data-language="javascript">askFor: function () { var done=this.async(); var prompts=[{ name: "projectName", message: "Ім'я проекту" }, { type: 'list', name: 'skeleton', message: 'Який фреймворк ви хотіли б використовувати?', choices: [ "zendframework/skeleton-application", "symfony/symfony-standard", " laravel/laravel", "silexphp/silex-skeleton", "slim/slim-skeleton" ] }, { name: "dependencies", message: "Додати іншу залежність? (наприклад: vendor/package:version)", }]; this.prompt(prompts, function (props) { this.skeleton=props.skeleton; this.projectName=props.projectName; this.dependencies=props.dependencies; done(); }.bind(this)); },
Тут ми визначаємо три запити:
- projectName — просто просить користувача визначити, де буде створено скелет програми;
- skeleton — попросить користувача вибрати скелет зі списку;
- dependencies — запитає користувача про інші залежності, які слід увімкнути.
Ви могли також помітити першу рядок нашого методу var done=this.async();. Це схоже на Gulp — дозволяє створювати методи одночасно. Як тільки ми будемо готові перейти до наступного завдання, ми викликаємо done().
Наші запити на даний момент дуже примітивні і їм не вистачає який або перевірки. Щоб зробити це, ми просто додамо новий параметр validate який отримує вхідне значення і повертає true, якщо все правильно або повідомлення про помилку, якщо неправильно.
Запит імені проекту потребує перевірки, тому що вхідне значення є допустимим ім'ям папки і вона поки що не існує:
<code data-language="javascript">{ name: "projectName", message: "Ім'я проекту", validate: function(input) { if (!/^[a-zA-Z\-0-9_]+$/.exec(input)) { return "Неправильне ім'я папки!"; } if (fs.existsSync('./' + input)) { return "Папка вже існує!"; } return true; } }
Наш запит залежностей повинен перевірити, що ми отримали правильне ім'я пакета та версію. Крім того, запит дозволяє вказати лише одну залежність, а ми б потенційно хотіли додати багато. Ми можемо переписати перевірку і вона продовжить запитувати, доки користувач не зупиниться. Для цього спочатку додамо порожній масив вгорі нашого методу askFor для зберігання залежностей:
<code data-language="javascript">askFor: function () { var done=this.async(); var dependencies=[]; …
<code data-language="javascript">{ name: "dependencies", message: "Додати іншу залежність? (наприклад: vendor/package:version)", validate: function(input) { if (input.length==0) { return true; } if (!/^(.*)\/(.*):(.*)/.test(input)) { return "Неправильний пакет. Будь ласка, використовуйте формат: vendor/package:version"; } dependencies.push(input); return "Введіть іншу залежність або просто натисніть Enter для продовження"; } }
Код повертає true, якщо користувач нічого не ввів, або перевірятиме рядок з пакетом і поверне помилку, якщо рядок не відповідає вимогам .
Якщо пакет коректний, він буде доданий до нашого масиву залежностей і функція поверне помилку, яка вказує що повинні ввести іншу залежність або натиснути Enter для продовження.
Остаточно встановлюємо this.dependencies в наш масив dependencies замість props .dependencies (який має бути порожнім).
<code data-language="javascript">this.prompt(prompts, function (props) { this.skeleton=props.skeleton; this .projectName=props.projectName; this.dependencies=dependencies; done(); }.bind(this));
Тепер, коли у нас є введення користувача, давайте створимо метод для виклику composer create-project.
Перше, що ми маємо зробити, це імпортувати метод child_process.exec(), щоб могли запустити composer.Як і з усім імпортом , ми додаємо наступний код у верхню частину index.js:
<code data-language="javascript">var exec=require('child_process').exec;
Далі, створимо наш метод:
<code data-language="javascript">composerCreateProject: function() { var done=this.async(); var cmd="composer create-project " + this.skeleton + " " + this.projectName; console.log("[" + chalk.yellow("Composer") + chalk.reset() + "] Створення проекту...") exec(cmd, function (error) { if (error) throw error; console.log("[" + chalk.yellow("Composer") + chalk.reset() + "] Проект створений!"); done(); }); },
Знову ж таки, ми робимо наш метод асинхронним; це тому, що повинні чекати команди завершення, перш ніж зможемо додати додаткові залежності.
Ми виводимо повідомлення про стан користувача за допомогою console.log і використовуємо chalk, щоб зробити це красиво, потім виконуємо composer create-project за допомогою exec().
Наш виклик exec() включає функцію зворотного виклику, яка буде виводити помилки або повідомлення про успіх у консоль (знову використовуємо console.log і chalk), а потім викличе функцію done(), що дозволить генератору рухатися далі.
Наш кінцевий метод буде використовувати composer require для додавання залежностей:
<code data-language="javascript">composerAddDependencies: function() { if (this.dependencies.length > 0) { var dependencies=this .dependencies; console.log("[" + chalk.yellow("Composer") + chalk.reset() + "] Додаються залежності..."); for (var i in dependencies) {this._composerInstallDependency(dependencies[i]); } } }, _composerInstallDependency: function(dependency) { var done=this.async(); exec("composer require " + dependency, {cwd: this.projectName}, function (error) { if (error) throw error; console.log("[" + chalk.yellow("Composer") + chalk.reset() + "] Додано " + dependency);done(); }); }
Цей метод дуже схожий на наш метод composerCreateProject, за винятком того, що ми обходимо масив this .dependencies і запускаємо кілька команд.
Для забезпечення синхронного запуску ми створюємо приватний метод _composerInstallDependency, який щоразу синхронно запускатиме composer require.
Щоб перевірити наш генератор, ми повинні сказати npm де він живе; для цього запускаємо npm link у кореневій папці.
На даний момент наш генератор готовий до запуску:
<code>$ yo php-composer
Ви можете переглянути повний код нашого генератора тут .
Що далі?
Тепер, коли ваш набір інструментів спільно працює з Bower, Gulp і Yeoman, ви незабаром можете почати автоматизувати оточення і розгортання — в цьому, врешті-решт, і весь сенс всього цього.