В чем разница между Bower и npm?

1763

В чем принципиальная разница между bowerи npm? Просто хочу что-то простое и понятное. Я видел, как некоторые из моих коллег использовали bowerи npmвзаимозаменяемо в своих проектах.

Игры Brainiac
источник
7
Соответствующий ответ stackoverflow.com/a/21199026/1310070
sachinjain024
4
Возможный дубликат управления зависимостями Javascript: npm против bower против volo?
anotherdave
7
Ответ на этот вопрос кажется устаревшим. Может кто-нибудь сказать нам, что делать в 2016 году, если мы используем npm 3, который поддерживает плоскую зависимость? Какая разница между npm3 и bower, и какая сейчас лучшая практика?
amdev
2
Итог, @amdev: беседка теперь устарела. Npm (или пряжа, которая является лишь небольшой разницей) - это то, где он находится. Я не знаю каких-либо жизнеспособных альтернатив.
XML

Ответы:

1914

У всех менеджеров пакетов есть много минусов. Вам просто нужно выбрать, с чем вы можете жить.

история

npm начал управлять модулями node.js (поэтому пакеты включаютсяnode_modules по умолчанию), но он работает и для внешнего интерфейса в сочетании с Browserify или webpack .

Bower создан исключительно для внешнего интерфейса и оптимизирован с учетом этого.

Размер репо

npm намного, намного больше, чем bower, включая JavaScript общего назначения (например, country-dataдля информации о стране или sortsдля функций сортировки, которые можно использовать на переднем или заднем конце).

Бауэр имеет гораздо меньшее количество пакетов.

Обработка стилей и т. Д.

Бауэр включает в себя стили и т. Д.

Npm ориентирован на JavaScript. Стили либо загружаются отдельно, либо требуются чем-то вроде npm-sassили sass-npm.

Обработка зависимостей

Самым большим отличием является то, что npm выполняет вложенные зависимости (но является плоской по умолчанию), в то время как Bower требует плоского дерева зависимостей (накладывает бремя разрешения зависимостей на пользователя) .

Вложенное дерево зависимостей означает, что ваши зависимости могут иметь свои собственные зависимости, которые могут иметь свои собственные, и так далее. Это позволяет двум модулям требовать разные версии одной и той же зависимости и все еще работать. Обратите внимание, что начиная с npm v3, дерево зависимостей по умолчанию будет плоским (экономия места) и будет гнездиться только там, где это необходимо, например, если двум зависимостям требуется собственная версия Underscore.

В некоторых проектах используется то, что они используют Bower для интерфейсных пакетов и npm для инструментов разработчика, таких как Yeoman, Grunt, Gulp, JSHint, CoffeeScript и т. Д.


Ресурсы

Синдре Сорхус
источник
37
Почему вложенное дерево зависимостей не работает так хорошо на внешнем интерфейсе?
Ларс Нистрем
24
Может ли интерфейсный пакет npm не быть плоским деревом зависимостей? Я сталкиваюсь с вопросом "зачем нам 2 менеджера пакетов?" дилемма.
Стивен Вачон
38
Что вы подразумеваете под "плоским деревом зависимостей"? Плоское дерево - это что - список? Это не дерево тогда.
mvmn
14
На самом деле путь - это тоже дерево. Это просто особый случай. Из WikiPedia: «В математике, а точнее в теории графов, дерево - это неориентированный граф, в котором любые две вершины соединены ровно одним путем».
Йорген Фог,
42
npm 3 теперь поддерживает плоское дерево зависимостей.
Васа
361

Этот ответ является дополнением к ответу Синдре Сорхуса. Основное различие между npm и Bower заключается в том, как они обрабатывают рекурсивные зависимости. Обратите внимание, что они могут быть использованы вместе в одном проекте.

Часто задаваемые вопросы о npm : (ссылка на archive.org от 6 сентября 2015 г.)

Гораздо сложнее избежать конфликтов зависимостей без вложенных зависимостей. Это имеет фундаментальное значение для работы npm и оказалось чрезвычайно успешным подходом.

На домашней странице Bower :

Бауэр оптимизирован для внешнего интерфейса. Bower использует плоское дерево зависимостей, для которого требуется только одна версия для каждого пакета, что снижает загрузку страницы до минимума.

Короче говоря, npm стремится к стабильности. Бауэр стремится к минимальной нагрузке на ресурсы. Если вы нарисуете структуру зависимостей, вы увидите это:

NPM:

project root
[node_modules] // default directory for dependencies
 -> dependency A
 -> dependency B
    [node_modules]
    -> dependency A

 -> dependency C
    [node_modules]
    -> dependency B
      [node_modules]
       -> dependency A 
    -> dependency D

Как вы видите, он устанавливает некоторые зависимости рекурсивно. Зависимость А имеет три установленных экземпляра!

Беседка:

project root
[bower_components] // default directory for dependencies
 -> dependency A
 -> dependency B // needs A
 -> dependency C // needs B and D
 -> dependency D

Здесь вы видите, что все уникальные зависимости находятся на одном уровне.

Итак, зачем использовать npm?

Возможно, для зависимости B требуется другая версия зависимости A, чем для зависимости C. npm устанавливает обе версии этой зависимости, поэтому она все равно будет работать, но Bower создаст вам конфликт, потому что не любит дублирование (поскольку загрузка одного и того же ресурса на веб-странице очень неэффективно и дорого, а также может привести к серьезным ошибкам). Вам нужно будет вручную выбрать, какую версию вы хотите установить. Это может привести к тому, что одна из зависимостей будет нарушена, но это нужно исправить в любом случае.

Таким образом, обычно используется Bower для пакетов, которые вы хотите опубликовать на своих веб-страницах (например, во время выполнения , где вы избегаете дублирования), и использовать npm для других вещей, таких как тестирование, сборка, оптимизация, проверка и т. Д. (Например, время разработки где дублирование менее важно).

Обновление для npm 3:

Npm 3 по-прежнему работает по-другому по сравнению с Bower. Он установит зависимости глобально, но только для первой версии, с которой он столкнется. Другие версии устанавливаются в дереве (родительский модуль, затем node_modules).

  • [Node_modules]
    • Dep A v1.0
    • Dep B v1.0
      • Dep A v1.0 (использует корневую версию)
    • Dep C v1.0
      • dep A v2.0 (эта версия отличается от корневой версии, поэтому это будет вложенная установка)

Для получения дополнительной информации, я предлагаю прочитать документы npm 3

Юстус Ромейн
источник
4
Это почти клише, когда «разработка программного обеспечения - это компромиссы». Это хороший пример. Нужно выбрать либо стабильность больше с npm или минимальную нагрузку ресурсов с bower.
Jfmercer
6
@ Шрек Я безоговорочно заявляю, что вы на самом деле можете использовать оба. У них разные цели, как я утверждаю в последнем абзаце. Это не компромисс в моих глазах.
Юстус Ромийн
Ааа, я вижу, я вас неправильно понял. Или я недостаточно внимательно прочитал. Благодарю за разъяснение. :-) Хорошо, что оба могут быть использованы без компромисса.
jfmercer
4
@AlexAngas Я добавил обновление для npm3. У этого все еще есть некоторые главные различия по сравнению с Бауэром. npm, вероятно, всегда будет поддерживать несколько версий зависимостей, а Bower - нет.
Юстус Ромийн
npm 3 становится ближе к беседке;)
ni3
269

TL; DR: самая большая разница в повседневном использовании - это не вложенные зависимости ... это разница между модулями и глобальными переменными.

Я думаю, что предыдущие плакаты хорошо освещали некоторые основные различия. (Использование npm вложенных зависимостей действительно очень полезно для управления большими и сложными приложениями, хотя я не думаю, что это самое важное различие.)

Я удивлен, однако, что никто явно не объяснил одно из самых фундаментальных различий между Bower и npm. Если вы прочитаете ответы выше, вы увидите слово «модули», часто используемое в контексте npm. Но это упоминается случайно, как будто это может быть просто разница в синтаксисе.

Но это различие между модулями и глобальными (или модулями и «скриптами»), возможно, является наиболее важным отличием между Bower и npm. Подход npm для помещения всего в модули требует, чтобы вы изменили способ написания Javascript для браузера, почти наверняка в лучшую сторону.

Бауэр подход: глобальные ресурсы, как <script>теги

В корне Bower о загрузке простых старых файлов сценариев. Что бы ни содержали эти файлы скриптов, Бауэр загрузит их. Что в основном означает, что Bower - это то же самое, что включить все ваши скрипты в простой старый <script>в <head>ваш HTML.

Итак, тот же базовый подход, к которому вы привыкли, но вы получаете некоторые удобные возможности автоматизации:

  • Раньше вам приходилось включать JS-зависимости в репозиторий проекта (при разработке) или получать их через CDN. Теперь вы можете пропустить этот дополнительный вес загрузки в репо, и кто-то может быстро bower installи мгновенно получить то, что ему нужно, локально.
  • Если зависимость Bower затем указывает свои собственные зависимости bower.json, они также будут загружены для вас.

Но кроме этого, Бауэр не меняет то, как мы пишем JavaScript . Ничего из того, что происходит внутри файлов, загружаемых Bower, вообще не должно меняться. В частности, это означает, что ресурсы, предоставляемые в скриптах, загружаемых Bower, будут (обычно, но не всегда) по-прежнему определяться как глобальные переменные , доступные из любого места в контексте выполнения браузера.

Подход npm: общие JS-модули, явное внедрение зависимостей

Весь код в Node land (и, следовательно, весь код, загружаемый через npm) структурирован как модули (в частности, как реализация формата модуля CommonJS , или теперь как модуль ES6). Итак, если вы используете NPM для обработки зависимостей на стороне браузера (через Browserify или что-то еще, что делает ту же работу), вы будете структурировать свой код так же, как это делает Node.

Более умные люди, чем я, взялись за вопрос «Почему модули?», Но вот краткая сводка:

  • Все, что находится внутри модуля, фактически является пространством имен , что означает, что оно больше не является глобальной переменной, и вы не можете случайно ссылаться на него, не намереваясь.
  • Все, что находится внутри модуля, должно быть намеренно введено в конкретный контекст (обычно в другой модуль), чтобы использовать его
  • Это означает, что вы можете иметь несколько версий одной и той же внешней зависимости (скажем, lodash) в разных частях вашего приложения, и они не будут конфликтовать / конфликтовать. (Это происходит на удивление часто, потому что ваш собственный код хочет использовать одну версию зависимости, но одна из ваших внешних зависимостей задает другую, которая конфликтует. Или у вас есть две внешние зависимости, каждая из которых требует своей версии.)
  • Поскольку все зависимости вводятся вручную в конкретный модуль, их очень легко рассуждать. Вы точно знаете: «Единственный код, который мне нужно учитывать при работе над этим, - это то, что я намеренно выбрал для внедрения здесь» .
  • Поскольку даже содержимое внедренных модулей инкапсулировано за переменной, которой вы назначаете его, и весь код выполняется в ограниченной области, неожиданности и коллизии становятся очень маловероятными. Гораздо менее вероятно, что что-то из одной из ваших зависимостей будет случайно переопределять глобальную переменную без вашего понимания или того, что вы это сделаете. (Это может случиться, но вам, как правило, приходится делать все возможное, чтобы сделать это, с чем-то вроде window.variable. Единственная авария, которая все еще имеет тенденцию происходить, это присвоение this.variable, а не осознание того, что thisна самом деле находится windowв текущем контексте.)
  • Когда вы хотите протестировать отдельный модуль, вы можете очень легко узнать: что еще (зависимости) влияет на код, который выполняется внутри модуля? И, поскольку вы явно вводите все, вы можете легко высмеивать эти зависимости.

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


Это займет всего около 30 секунд, чтобы научиться использовать синтаксис модуля CommonJS / Node. Внутри данного файла JS, который будет модулем, вы сначала объявляете любые внешние зависимости, которые хотите использовать, например так:

var React = require('react');

Внутри файла / модуля вы делаете все, что обычно делаете, и создаете какой-либо объект или функцию, которую вы хотите предоставить внешним пользователям, возможно, вызывая ее myModule.

В конце файла вы экспортируете все, что хотите поделиться с миром, например так:

module.exports = myModule;

Затем, чтобы использовать основанный на CommonJS рабочий процесс в браузере, вы будете использовать такие инструменты, как Browserify, чтобы захватывать все эти отдельные файлы модулей, инкапсулировать их содержимое во время выполнения и вставлять их друг в друга по мере необходимости.

И, поскольку модули ES6 (которые вы, скорее всего, перенесете в ES5 с Babel или аналогичными), получают широкое признание и работают как в браузере, так и в Node 4.0, мы должны упомянуть и их хороший обзор .

Подробнее о шаблонах для работы с модулями в этой колоде .


РЕДАКТИРОВАТЬ (февраль 2017 г.): пряжа Facebook является очень важной потенциальной заменой / дополнением для npm в наши дни: быстрое, детерминистическое, автономное управление пакетами, основанное на том, что дает npm. Это стоит посмотреть на любой проект JS, особенно потому, что его так легко поменять местами.


РЕДАКТИРОВАТЬ (май 2019) "Бауэр, наконец, устарела . Конец истории". (h / t: @DanDascalescu, ниже, для краткого изложения.)

И, несмотря на то, что Yarn все еще активен , большая часть импульса вернулась к npm, как только он принял некоторые из ключевых функций Yarn.

XML
источник
13
Рад, что этот ответ был здесь, другие популярные ответы не упоминают эту деталь. npm заставляет вас писать модульный код.
Хуан Мендес
Я извиняюсь от людей, которые очень мало заботятся о неясности паролей в javascript, но так происходит, что у них есть бизнес, использующий небольшое веб-приложение. Недавно был вынужден попробовать npm от использования bower с инструментарием, который мы используем для разработки проклятых веб-приложений. Я могу сказать вам, что самая большая разница в времени ожидания, npm занимает много времени. Помните, что компиляция мультфильма xkcd с парнями, играющими в мечах, выкрикивая «компиляцию» своему боссу; это в значительной степени то, что npm добавил к беседке.
Педро Родригес
129

Обновление 2017-октябрь

Бауэр наконец-то устарела . Конец истории.

Старый ответ

От Маттиаса Петтера Йоханссона, разработчика JavaScript в Spotify :

Почти во всех случаях более целесообразно использовать Browserify и npm over Bower. Это просто лучшее упаковочное решение для интерфейсных приложений, чем Bower. В Spotify мы используем npm для упаковки целых веб-модулей (html, css, js), и это работает очень хорошо.

Бауэр позиционирует себя как менеджер пакетов для Интернета. Было бы замечательно, если бы это было правдой - менеджер пакетов, который сделал мою жизнь лучше, как фронтенд-разработчик, был бы потрясающим. Проблема в том, что Bower не предлагает специального инструмента для этой цели. Он не предлагает никаких инструментов, которые я знаю о том, чего нет в npm, и особенно тех, которые особенно полезны для разработчиков переднего плана. Для разработчика переднего плана просто нет смысла использовать Bower вместо npm.

Мы должны прекратить использовать беседку и консолидироваться около нпм. К счастью, вот что происходит :

Количество модулей - bower против npm

С помощью browserify или webpack становится очень легко объединить все ваши модули в большие миниатюрные файлы, что является потрясающим по производительности, особенно для мобильных устройств. Не так с Бауэром, который потребует значительно больше труда, чтобы получить тот же эффект.

npm также предлагает вам возможность использовать несколько версий модулей одновременно. Если вы не занимались разработкой приложений, это может показаться плохим, но как только вы пройдете через несколько адских адептов зависимости, вы поймете, что иметь возможность иметь несколько версий одного модуля - это чертовски круто. отличная особенность. Обратите внимание, что npm включает в себя очень удобный инструмент дедупликации, который автоматически гарантирует, что вы используете только две версии модуля, если вам это действительно нужно - если два модуля могут использовать одну и ту же версию одного модуля, они это сделают. Но если они не могут , у вас есть очень удобный.

(Обратите внимание, что Webpack и накопительный пакет, по общему мнению, лучше, чем Browserify по состоянию на август 2016 года.)

Дан Дакалеску
источник
7
<sarcasm> Пожалуйста, имейте в виду, что даже для проекта npm «Здравствуй, мир!» для запуска требуется более 300 модулей ... </ sarcasm>: O
Mariusz Jamro
1
Я не согласен с тем, что «большие минимизированные файлы» являются «потрясающими по производительности, особенно для мобильных устройств». Скорее наоборот: ограниченная пропускная способность требует небольших файлов, загружаемых по требованию.
Майкл
Не очень хороший совет. Большинство пакетов npm являются только бэкэндом nodejs. Если вы не используете javascript в бэкэнде или у вас нет модульной системы, количество пакетов не имеет значения, потому что Bower будет гораздо лучше соответствовать вашим потребностям
Герардо Гриньоли,
4
@GerardoGrignoli: беседка выходит .
Дан Даскалеску
45

Bower поддерживает единственную версию модулей, она только пытается помочь вам выбрать правильный / лучший для вас.

Управление зависимостями Javascript: npm против bower против volo?

NPM лучше подходит для узловых модулей, потому что есть модульная система, и вы работаете локально. Bower хорош для браузера, потому что в настоящее время существует только глобальная область действия, и вы хотите быть очень избирательными в отношении версии, с которой вы работаете.

Sagivf
источник
4
Я чувствую, что Синдре упоминает об этом, когда говорит о вложенной зависимости.
Игры Brainiac
5
@GamesBrainiac, ты прав, просто подумал, что я бы сказал это своими словами.
Сагивф
1
@Sagivf Это НЕ ваши собственные слова, если только вы не являетесь тем, кто предоставил оригинальный ответ здесь
dayuloli
4
@Sagivf Нет ничего плохого в том, чтобы копировать ** соответствующие части ответов других, если они сами не предоставили здесь ответ. Это меня немного напрягло, когда ты сказал: «Просто подумал, что я выразил это своими словами». Кредит должен идти туда, где кредит должен.
Dayuloli
2
Я не знаю, почему вы так много выбрали для этого ответа. В этом ответе есть действительно новая информация / перспектива.
Кальвин
33

Моя команда переехала из Бауэра и переехала в npm, потому что:

  • Программное использование было болезненным
  • Интерфейс Бауэра постоянно менялся
  • Некоторые функции, такие как сокращение URL, полностью не работают
  • Использование Bower и npm в одном проекте - это больно
  • Поддерживать синхронизацию поля версии bower.json с тегами git
  • Контроль версий! = Управление пакетами
  • Поддержка CommonJS не проста

Для получения дополнительной информации см. «Почему моя команда использует npm вместо bower» .

Ник Хейнер
источник
17

Нашел это полезное объяснение на http://ng-learn.org/2013/11/Bower-vs-npm/

С одной стороны, npm был создан для установки модулей, используемых в среде node.js, или инструментов разработки, созданных с использованием node.js, таких как Karma, lint, minifiers и так далее. npm может устанавливать модули локально в проекте (по умолчанию в node_modules) или глобально для использования несколькими проектами. В больших проектах способ указания зависимостей заключается в создании файла с именем package.json, который содержит список зависимостей. Этот список распознается npm, когда вы запускаете npm install, которая затем загружает и устанавливает их для вас.

С другой стороны, bower был создан для управления вашими внешними зависимостями. Такие библиотеки, как jQuery, AngularJS, подчеркивание и т. Д. Как и в npm, в нем есть файл, в котором вы можете указать список зависимостей, называемый bower.json. В этом случае ваши зависимости от внешнего интерфейса устанавливаются с помощью команды bower install, которая по умолчанию устанавливает их в папку с именем bower_components.

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

Генри Нео
источник
1
С появлением npm dedupe, это немного устарело. Смотрите ответ Маттиаса .
Дан Даскалеску
7

Для многих людей, работающих с node.js, основным преимуществом bower является управление зависимостями, которые вообще не являются javascript. Если они работают с языками, которые компилируются в javascript, npm может использоваться для управления некоторыми из их зависимостей. однако не все их зависимости будут модулями node.js. Некоторые из тех, которые компилируются в javascript, могут иметь странное искажение, специфичное для исходного языка, что делает передачу их скомпилированным в javascript неэлегичной опцией, когда пользователи ожидают исходный код.

Не все в пакете npm должно быть ориентированным на пользователя javascript, но для пакетов библиотеки npm, по крайней мере, некоторые из них должны быть.

jessopher
источник
В этом посте npmjs говорится: «Ваш пакет может содержать что угодно, будь то ES6, JS на стороне клиента или даже HTML и CSS. Это вещи, которые естественным образом появляются вместе с JavaScript, поэтому поместите их туда».
Дан Даскалеску
1
Существует разница между может содержать и должен включать . Конечно, они могут содержать все что угодно, но в целом они должны включать в себя какой-то интерфейс к commonJS. В конце концов, это «менеджер пакетов узлов». Часть о Это вещи, которые естественно появляются вместе с Javascript , важна. Есть много вещей, которые тангенциально связаны с javascript, которые не появляются рядом с ним.
Джессофер