Bower: зачем фронтенду нужен менеджер пакетов
Статья написана в 2014-м году, во времена npm 2, который был не очень популярен среди фронтендеров
Статья впервые была опубликована в майском номере журнала Хакер. В журнал вошла сильно сокращённая версия; ниже — полная.
Менеджеры пакетов упрощают установку и обновление зависимостей проекта, то есть сторонних библиотек, которые он использует: jQuery, Fotorama, всё, что используется на вашем сайте и написано не вами.
Хождение по сайтам библиотек, скачивание и распаковка архивов, копирование файлов в проект — всё это заменяется парой команд в терминале.
У многих языков программирования есть стандартные менеджеры пакетов, которыми разработчики пользуются для установки всех библиотек: gem у Руби, pip у Питона и другие. У серверного Яваскрипта есть npm (почему он не подходит для клиентского — ниже), а у клиентского яваскрипта до недавнего времени ничего не было. Было множество разных пакетных менеджеров (Jam, Component, Volo, Ender), но большинство из них так и не стали популярными, а от менеджера пакетов, которым не поставишь нужных библиотек, толку мало.
Бовер — не стандартный менеджер пакетов для клиентского Яваскрипта, но самый популярный: сейчас там больше 11 тысяч пакетов.
Бовер не навязывает пользователю свою систему сборки, а разработчику пакетов — метод подключения библиотеки (AMD, CommonJS и другие). Всё, что делает Бовер — устанавливает нужные проекту пакеты подходящих версий вместе с их зависимостями. Другими словами: просто загружает файлы нужных библиотек и всё, что нужно для их работы в специальную папку. Остальное остаётся на усмотрение разработчика.
Почему не npm
Главное отличие npm и Бовера — подход к установке зависимостей пакетов. npm устанавливает зависимости для каждого пакета отдельно, в итоге получается большое дерево пакетов (nodemodules/grunt/nodemodules/glob/nodemodules/…), где может быть несколько версий одного и того же пакета. В клиентском Яваскрипте это недопустимо: нельзя подключить на страницу две версии jQuery или любой другой библиотеки. В Бовере каждый пакет устанавливается один раз (jQuery всегда будет в папке bowercomponents/jquery, сколько бы пакетов от него не зависело) и в случае конфликта зависимостей, Бовер просто не станет устанавливать пакет, не совместимый с уже установленными.
Установка Бовера
Для работы с Бовером вам потребуются Node и Git. Установка:
npm install -g bower
Работа с пакетами
Попробуем что-нибудь установить, например, jQuery:
bower install --save jquery # Или bower i -S jquery
Эта команда скачает jQuery последней версии в папку bower_components/jquery
.
Флаг --save
говорит Боверу, что он должен сохранить имя пакета и его версию в файл-манифест — bower.json
. В этом файле хранится список всех зависимостей проекта (пакетов, установленных через Бовер) и другие метаданные, нужные для создания своих пакетов (об этом в конце статьи). Вместе с именами пакетов можно указать версии, с которыми ваш проект гарантированно будет работать.
У нас такого файла ещё нет, о чём и говорит строчка «No bower.json file to save to, use bower init to create one» в логе. Создадим его:
bower init
Бовер будет задавать много вопросов, но до тех пор пока мы не захотим зарегистрировать свой пакет, ответы на большинство из них не имеют значения, можно просто нажимать Enter.
На вопрос «set currently installed components as dependencies?» нужно ответить «Yes» — все ранее установленные компоненты (в нашем случае это jQuery) автоматически попадут в созданный JSON-файл. А на вопрос «would you like to mark this package as private which prevents it from being accidentally published to the registry?» — тоже «Yes» — это предотвратит случайную регистрацию пакета в реестре Бовере.
Поставим ещё несколько пакетов:
bower install --save social-likes jquery-icheck fotorama
И посмотрим, что у нас получилось:
bower list
bower check-new Checking for new versions of the project dependencies..
bowertest#0.0.0 /Users/admin/bowertest
├─┬ fotorama#4.5.1
│ └── jquery#2.1.0 (2.1.1-beta1 available)
├── jquery#2.1.0 (2.1.1-beta1 available)
├─┬ jquery-icheck#1.0.2
│ └── jquery#2.1.0 (2.1.1-beta1 available)
└─┬ social-likes#3.0.2
└── jquery#2.1.0
Команда bower list
показывает список всех установленных пакетов. Тут мы видим, что все пакеты зависят от jQuery, и что Бовер смог найти подходящую всем версию — jQuery 2.1.0.
На файловой системе это выглядит вот так:
tree -L 2
.
├── bower.json
└── bower_components
├── fotorama
├── jquery
├── jquery-icheck
└── social-likes
5 directories, 1 file
Каждый пакет устанавливается в свою папку, вложенных пакетов нет, jQuery встречается только один раз. В корне проекта лежит созданный командой bower init
файл bower.json
, но теперь там перечисленны уже все пакеты, которые показывает bower list
, а не только jQuery.
Для удаления пакетов используется команда bower uninstall
:
bower uninstall --save jquery-icheck # Или bower un -S jquery-icheck
Вы можете спокойно удалять папку bower_components
или добавить её в ваш .gitignore
. Команда bower install
(без дополнительных параметров) вернёт всё как было:
bower install
Развёртывание проекта
Есть два подхода к развёртыванию проектов:
- В репозиторий добавляется только файл-манифест и все пакеты устанавливаются во время развёртывания проекта. Так в репозитории не хранится ничего лишнего, но если во время развёртывания упадёт Гитхаб или другой сервер, с которого устанавливаются пакеты, будут проблемы.
- В репозиторий добавляется не только
bower.json
, но папкаbower_components
. Так развёртывание не зависит от внешних серверов, но репозиторий раздувается десятками (а то и сотнями) лишних файлов.
Семантические версии (semver)
Semver — это,
А
При установке с флагом --save
версии пакетов добавляются в bower.json
в виде ~1.0.1
. Тильда в начале говорит о том, что при установке будет выбрана версия 1.0.1 или с большим последним числом (ПАТЧ), если она есть. Таким образом будет установлена версия с последними исправлениями ошибок, но полностью совместимая с той, что указана в файле-манифесте.
Обновление зависимостей
В Бовере есть команда bower update
, но она обновляет пакеты с учётом требований файла-манифеста. Например, если там указан jQuery ~2.0.0
, то Бовер сможет обновить jQuery до версии, скажем, 2.0.9, но 2.1.0 уже не поставит, потому что эта версия не соответствует формуле ~2.0.0
.
Для обновления пакетов (и bower.json
) до действительно последних версий можно воспользоваться утилитой bower-update. Устанавливаем:
npm install -g bower-update
Запускаем:
bower-update
Поиск пакетов
Есть два способа найти пакет в Бовере: гиковский и обычный.
Гиковский:
bower search jquery
Search results:
jquery git://github.com/jquery/jquery.git
jquery-ui git://github.com/components/jqueryui
...
Обычный: открыть в браузере bower.io/search.
Автоматическая сборка
Бовер перекладывает проблемы сборки установленных пакетов на плечи разработчика. Самый простой способ — просто склеить JS-файлы Грантом, Галпом или любой другой системой сборки, которой вы пользуетесь.
Я пользуюсь Грантом, поэтому расскажу, как склеивать пакеты Грантом. О том как пользоваться Грантом была большая статья в июльском номере прошлого года, поэтому покажу сразу конфиг плагина grunt-contrib-concat
:
concat: {
main: {
src: [
'bower_components/jquery/jquery.min.js',
'bower_components/fotorama/….js',
'bower_components/jquery-icheck/….js',
'bower_components/social-likes/social-likes.min.js’,
'scripts/*.js' // Скрипты вашего сайта
],
dest: 'build/scripts.js'
}
}
У этого способа есть много недостатков: вам нужно смотреть имена файлов для каждого пакета; следить, чтобы файлы собирались в правильном порядке (например, jQuery должен быть выше, чем скрипты, зависящие от него). Плагин grunt-bower-concat может делать это сам: он автоматически склеивает все установленные зависимости в правильном порядке в один файл:
bower_concat: {
all: {
dest: 'build/_bower.js', // Склеенный файл
exclude: [ // Пакеты, которые нужно исключить из сборки
'jquery', // Если jQuery подключается с CDN Гугла
'modernizr' // Если подключаем скрипты в конце страницы; Modernizr нужно подключать в <head>
]
}
},
concat: {
main: {
src: [
'build/_bower.js',
'scripts/*.js' // Скрипты вашего сайта
],
dest: 'build/scripts.js'
}
}
Регистрация своих пакетов
Чтобы ваша библиотека стала доступна для установки через Бовер, её нужно зарегистрировать. Для этого:
— В корне проекта должен лежать файл-манифест bower.json
.
— У проекта должен быть гит-репозиторий (например, на Гитхабе).
— Проект должен использовать семантические версии и в репозитории должен быть гит-тег для последней версии.
Для создания файла файла-манифеста снова воспользуемся командой bower init
:
bower init
[?] name: awesomelib
[?] version: 0.0.1
[?] description: My awesome jQuery plugin.
[?] main file: jquery.awesomeplugin
[?] keywords: jquery awesome yay
[?] authors: Artem Sapegin <artem@sapegin.ru>
[?] license: MIT
[?] homepage: https://github.com/sapegn/jquery.awesomeplugin.js
[?] set currently installed components as dependencies? Yes
[?] add commonly ignored files to ignore list? Yes
[?] would you like to mark this package as private which prevents it from being accidentally published to the registry? No
{
name: 'awesomelib',
version: '0.0.1',
description: 'My awesome jQuery plugin.',
main: 'jquery.awesomeplugin.js',
keywords: [
'jquery',
'awesome',
'yay'
],
authors: [
'Artem Sapegin <artem@sapegin.ru>'
],
license: 'MIT',
homepage: 'https://github.com/sapegn/jquery.awesomeplugin',
ignore: [
'**/.*',
'node_modules',
'bower_components',
'test',
'tests'
],
"dependencies": {
"jquery": "~2.1.0"
}
}
[?] Looks good? Yes
И хотя обязательно нужно заполнить только имя пакета (поле name
), остальные поля тоже очень полезны:
— description
и keywords
помогут пользователям найти вашу библиотеку через интерфейс поиска пакетов.
— main
определяет главный файл пакета. Это поле может быть использовано автоматическими сборщиками, такими как grunt-bower-concat.
— license
— всегда указывайте лицензию: она говорит потенциальному пользователю вашего пакета, сможет ли он использовать его в своём проекте. Например, лицензия GPL требует, чтобы любой использующий её проект тоже распространялся по этой лицензии, что не всегда возможно.
— ignore
— по умолчанию Бовер скачивает весь репозиторий, что, dependencies
— все пакеты, от которых зависит ваш пакет.
Теперь нужно закоммитить bower.json
, создать гит-тег с последней версией и запушить всё в удалённый репозиторий:
git add bower.json
git commit -m "Add bower.json."
git tag "v0.0.1"
git push origin --tags
Вот теперь можно регистрировать пакет:
bower register jquery-awesomeplugin git://github.com/sapegin/jquery-awesomeplugin.git
Дальше Бовер сам будет проверять обновления пакета, главное не забывать создавать гит-тег для каждой новой версии.
Для облегчения обновления своих пакетов можно воспользоваться такими инструментами, как grunt-bump или mversion.