Складальник проектів на Angular і RequireJS і деякі думки по збірці

Що саме незручне в збирачах проекту? Правильно! Те, що потрібно збірку писати самому. Вивчати grunt/gulp/webpack, шаманити з плагінами, думати, як розбити конфіг на модулі, коли він зростає до кількох сотень рядків, потім кілька місяців радіти, що все працює, а коли в проекті з'являється критичне зміна, знову лізти в це болото.

Мені теж все це набридло, тому написав складальник, позбавлений цих недоліків. Його gulpfile.js виглядає так:

var gulp = require('gulp');
var arjs = require('arjs-builder')();

gulp.task('build', arjs.build);
gulp.task('test', arjs.test);
gulp.task('default', arjs.run);

Скопіювали собі проект, і більше ніколи туди не лізете, і назавжди забуваєте що таке збірка.
Єдине, що доведеться вивчити, — це три команди:

gulp #компилит, піднімає локальні сервери
gulp build #билдит проект
gulp test #запускає тести

Відкриваєте localhost:7000 і насолоджуєтеся локальною версією сайту, а в папці

build
вже лежить сбилженная версія.

— А як же темплейти, їх же треба в js впроваджувати?
— Звичайно! Всі впроваджено як годиться.
— А я стилі пишу на less, sass, stylus, їх же треба компилить?
— Пишіть як писали, все чудесним чином буде працювати.
— А картинки в CSS инклудить?
— Так давно у CSS. All included як у п'ятизірковому готелі.
— А розбити сбилженный файл на модулі?
— Перевірте папку build. Все по модулям? З унікальними іменами, заснованими на вміст файлу? Ось, а ви хвилювалися!
— А ось ще там щось…
— І це теж працює.

Але як таке можливо? Це ми й розглянемо у статті. А в кінці ще розповім, чому все-таки RequireJS

Структура проекту
Завжди чимось доводиться жертвувати. У нашому випадку це обмеження, що накладаються на структуру проекту і безпосередньо результат складання. Але тут не плакати, а радіти треба, тому що ми пожертвували таким злом, як «мені потрібна максимальна гнучкість та контроль, я все напишу сам». Озирнімося довкола і поклавши руку на серце прийдемо до висновку, що більшість розробників слабо представляють архітектуру фронтенда сингл-пейдж програми, не кажучи вже про те, як його правильно збирати (в один файл за модулями, синхронно вантажити, асинхронно, швидкодія ніхто не заміряв, ніхто нічого не аналізував). Та й чи потрібно це веб-розробнику? Заради цього він влаштовувався на роботу?

Ближче до теми. Складальник призначений для проектів, заснованих на RequireJS і AngularJS. Втім, він працює з проектами і на чистому JS і теоретично з будь-якими іншими фреймворками.

Робоча директорія c вашим додатком буде мати таку структуру:
projects/
├──project1/
├──project2/
├──project3/
├──files/
├──vendor/
├──compiled/
├──build/
├──index.html
├──lib.js
└──lib.css
.bowerrc
bower.json
package.json
gulpfile.js

project1..3
— папки з проектами. Проект описує окремий розділ сайту або окремий сайт. Проекти можуть бути написані на різних фреймворках або без них. Для проектів може використовуватися як загальний index.html так і власний. У додатку середнього рівня буде мінімум три проекти:
  • main
    — основний сайт
  • admin
    — адмінка
  • old-browser
    — заглушка для старих браузерів, написана на самому примітивному JS
У великих програмах може з'явитися проект
lib
в якому будуть зібрані основні модулі, що використовуються в інших проектах (роутинг, авторизація, робота з ресурсами...).

В окремі проекти варто виносити нову версію сайту (щоб організувати плавний перехід), збірки для A/B-тестування, тимчасові лендінгем-пейджи і т. п.

В
files
кладуться файли, які не будуть вставлятися в CSS (кандидати на перенесення на файловий сервер). Решта — будуть перетворені в base64 і вставлені в стилі, навіть якщо це 2ГБ відео. Тому що проект описує тільки інтерфейс, контент повинен братися з інших місць.
В
vendor
копіюються бібліотеки з bower.
В
compiled
складаються тимчасові файли для локальної роботи (стилі, вендорные бібліотеки).
В
build
зібрані проекти, готові для заливки на сервер.

Приклад
index.html
можна знайти на тут. Він, так само як gulpfile.js не змінюється ніколи.
— А як же мені додати туди свій скрипт або підключити аналітику?
— Через масив scripts в конфіги або у відповідному модулі у проекті. демо-додаток спеціально додав приклад з аналітикою і мета-тегами.
Абстрактне маркетингове агентство просить додати Яндекс.Метрику, googleAnalitycs, googleTagManager, лічильники вконтакте, mailru, doubleClick..., і кожному потрібно помістити свій скрипт в індекс, і щоб вище інших, щоб він там створив свій гівно-айфрейм або гівно-картинку в один піксель. А не офігіли ви, панове? Думаєте просто так срати в індекс? Тепер всі ці вискочки укладені в окремий модуль і підключаються, тільки якщо в конфіги варто дозвіл. Ми ж не хочемо спостерігати купу лівих запитів при розробці локальної?
В
lib.js
знаходяться микрофреймфорк найнеобхідніші методи, які повинні бути доступні до завантаження основного фреймворка. Такі як: визначення браузера, локалі користувача, завантаження скриптів та ін. По ідеї, не повинно бути необхідності змінювати цей файл, але поки не настільки його отладил, щоб гарантувати це.

Тепер розглянемо спрощену структуру окремого проекту:
_config/
├──default.yaml
├──dev.yaml
└──production.yaml
module1/
├──_tests
├──someFolder1/
│ ├──some.js
│ ├──style.sass
│ └──template.html
├──someFolder2/
└──config.js
module2/
module3/
bootstrap.js
requireconfig.js

Підемо до кінця.
requireconfig.js
— підключає бібліотечні файли до проекту
bootstrap.js
— підключає файли проекту. Стандартна схема роботи require.js
module1..3
— модулі проекту. Під час складання кожен модуль збирається в окремий файл
В
_tests
лежать тести, що відносяться до файлів у поточній папці. В якості тестів розглядаються файли, що закінчуються на
spec.js
.
В
config.js
описуються залежності відповідного модуля
someFolder
може мати будь-яку структуру (головне, щоб всі залежно були описані)
Якщо поряд з файлом скрипта лежить template.html або style.сѕѕ/.sass/.scss/.less/.stylus, то вони будуть додані в кеш шаблонів або скомпиленый файл стилів. Дуже просте правило. Складальник не тягне що попало, а бере тільки те, що відноситься до файлу скрипта в тій послідовності, в якій завантажуються скрипти.

Найцікавіше —
_config

Тут зберігаються конфігурації для різних середовищ. Підтримуються формати json, json5, hjson, cson, yaml. Як тільки IDE почнуть підтримувати json5, переведу все приклади на нього і залишу єдиним підтримуваним форматом. В
default
описуються загальні для всіх оточень налаштування. Інші конфіги намерживаются на дефолтний.

Щоб зібрати проект з потрібним конфіг потрібно вказати його ім'я першим параметром
gulp --qa
gulp build --production

За замовчуванням береться
dev
.

Структура конфігураційного файлу:
{
public: { ... }, //параметри, доступні в додатку через project.config
localhost: {
webserver: { ... }, //налаштування локальних веб-серверів
manifest: { ... } //підключаються ресурси для локальної роботи
},
build: {
/* загальні налаштування для всіх модулів */
...
manifest: { ... }, //підключаються ресурси для зібраного проекту
modules: { ... }, //індивідуальні налаштування для кожного модуля, наприклад щоб vendor стискалося з параметром mangle: true, а стилі основного модуля завантажувалися б окремим файлом
copy: { ... } //скопіювати в білд якісь файли, наприклад robots.txt
},
vendor: { ... }, //установки для збірки вендорів. Наприклад, можна зібрати bootstrap або angularStrap зі своїм набором компонентів
}

Конфіг, певно, найскладніше, що є у збирача. Щоб його представити, краще подивитися приклади додатків складніше, простіше і документацію.

Чому все таки RequireJS?
Звичайно, щоб модулі завантажувалися по мірі необхідності, а не всі разом… Скаже хтось. Але немає.

Зібраний проект має таку структуру:
vendor-f8acc4024d.js #800КБ
vendor-9dcd7dad8d.css #100КБ
common-95dafc6502.js #200КБ
homepage-2979ff1937.js #30КБ
news-ebf043aeac.js #10КБ
...

Якщо розкинути мізками, то можна прийти до висновку, що в будь-якому проекті vendor (модуль з бібліотечними компонентами) буде мати найбільший вагу близько 1МБ (ніяк не менше 500КБ). При цьому ліниву завантаження організувати не вийде, оскільки всі бібліотеки мають бути завантажені до старту проекту. Звичайно, можна його розбити на файли для кожної бібліотеки, але тоді їх завантаження заб'є всі потоки браузера і відкладе завантаження решти файлів проекту, що не принесе значного виграшу. Рятує те, що з усіх модулів vendor змінюється рідше, тому майже завжди він буде братися з кеша.

Наступний за розміром — головний модуль, де описана загальна логіка і загальні стилі для всього проекту. Він так само змінюється досить рідко.

Слідом ідуть 10-20 модулів для розділів і різної бізнес-логіки. Вони змінюються часто, але важать копійки. Більш того, в сумі їх вага порівняємо з вагою усіх бібліотек.

Для прискорення завантаження і швидкого відображення елементів має сенс винести стильові файли з вендора і головного модуля в окремі модулі (збірка дозволяє налаштувати включення CSS в JS і порядок завантаження індивідуально для кожного модуля). У прикладі на малюнку нижче можна було б винести стилі модуля payment, т. к. в них включені важкі іконки платіжних систем.

А тепер подивимося, як буде відбуватися перша завантаження проекту (файли мають невелику вагу т. к. включено gzip):
network

Добре помітно, що поки вантажиться vendor, встигають завантажитися майже всі ресурси проекту. Тобто в ледачою завантаження модулів немає ніякого сенсу. Більш того, це сповільнить роботу сайту, т. к. доведеться чекати завантаження якогось 10КБ-го файла, якщо користувач перейде в інший розділ. Іншими словами, ні для великих ні для маленьких проектів RequireJS НЕ ПОТРІБЕН!

Так навіщо ж він використовується? Виключно для розробки.

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

Другорядне перевага в тому, що для локальної роботи не потрібен складальник (тільки запущений сервер). Скрипти не компилятся. Результат доступний моментально, а у великих проектах це багато чого коштує. А як же Babel, ES6, Coffee, TypeScript? А ніяк. Збірка створювалася для використання у великих і середніх проектів в продакшені. Якщо у вас університетська дослідницька робота або домашня сторінка, навіщо вам взагалі збірка? А якщо все це в серйозному проекті, та в продакшені… Покладемо ще раз руку на серце, ви просто вивчаєте нові технології за рахунок роботодавця. З тієї ж причини не підтримуються ніякі html-препроцессоры (хоча це зробити досить просто). JS і HTML знають будь-які веб-розробники, на відміну від інших технологій, які сьогодні популярні, а завтра про них всі забули.

Так як же все це запустити?
Встановлюєте глобально bower і gulp:
npm i -g bower
npm i -g gulp

Завантажуєте спрощений або повноцінний демо проект, набираєте в його папці команди:
npm i
bower i
gulp

Відкриваєте localhost:7000, Милуєтеся.

Набираєте:
gulp build --production
gulp

Відкриваєте localhost:7200, Милуєтесь зібраної версією для продакшену, яка з'явиться у папці build

щось не запрацювало?
Значить npm не завантажив або кострубато завантажив модулі. Якщо проблема з Karma, переконайтеся, що вона і всі її плагіни знаходяться в одній папці node_modules. Якщо не знаходить node-sass, швидше за все ви нещодавно оновили ноду — перевстановіть всі плагіни. Немає прав на зміну папки — спробуйте іншу консоль. При установці суцільні помилки, але все працює/не працює — у вас Вінда.

Плани на майбутнє
  • Збирати білд можна буде зовсім без RequireJS. Зараз зайві 17КБ терпимі (в порівнянні з вагою всього проекту).
  • Спрощення АПІ.
  • Підтримка інших фреймворків (не поодинці).
  • Швидкодія… Хоча і зараз всі процеси відбуваються в оперативній пам'яті, а livereload компилит стилі змінився модуля.
  • Підтримка багатомовних проектів.
  • Генерація документації з коду.
  • Написати статтю про архітектуру проекту на AngularJS. Зараз була порушена лише загальна структура, яка не пояснює які модулі повинні бути в проекті і як вони повинні бути написані.
  • Взагалі, все переписати на C++, позбувшись від гульпа та ін. (ймовірно, не в цьому житті)
Спасибі за увагу, готовий вислухати критику.

Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.