Qual é a diferença entre Bower e npm?

1763

Qual é a diferença fundamental entre bowere npm? Só quero algo claro e simples. Eu vi alguns dos meus colegas uso bowere npmalternadamente em seus projetos.

Jogos Brainiac
fonte
7
Resposta relacionada stackoverflow.com/a/21199026/1310070
sachinjain024 /
4
possível duplicação do gerenciamento de dependência
anotherdave
7
A resposta a esta pergunta parece desatualizada. Alguém pode nos dizer o que fazer em 2016 se usarmos o npm 3 que suporta dependência plana? Qual é a diferença wince npm3 e bower e qual é a melhor prática no momento?
Amdev 5/10
2
Bottom line, @amdev: bower agora está obsoleto. npm (ou Yarn, que é apenas uma pequena diferença) é onde está. Não conheço nenhuma alternativa viável.
XML

Respostas:

1914

Todos os gerenciadores de pacotes têm muitas desvantagens. Você apenas tem que escolher com quem você pode conviver.

História

O npm começou a gerenciar os módulos node.js (é por isso que os pacotes entram node_modulespor padrão), mas também funciona para o front-end quando combinado com o Browserify ou o webpack .

O Bower é criado exclusivamente para o front-end e é otimizado com isso em mente.

Tamanho do repo

O npm é muito, muito maior que o caramanchão, incluindo JavaScript de uso geral (como country-datainformações de país ou sortsfunções de classificação que podem ser usadas no front-end ou no back-end).

O Bower possui uma quantidade muito menor de pacotes.

Manipulação de estilos etc

O Bower inclui estilos etc.

O npm é focado em JavaScript. Os estilos são baixados separadamente ou exigidos por algo como npm-sassou sass-npm.

Manipulação de Dependências

A maior diferença é que o npm faz dependências aninhadas (mas é simples por padrão) enquanto o Bower requer uma árvore de dependências simples (coloca o ônus da resolução de dependências no usuário) .

Uma árvore de dependência aninhada significa que suas dependências podem ter suas próprias dependências, que podem ter suas próprias, e assim por diante. Isso permite que dois módulos exijam versões diferentes da mesma dependência e ainda funcionem. Observe que desde o npm v3, a árvore de dependências, por padrão, fica plana (economizando espaço) e apenas aninhar quando necessário, por exemplo, se duas dependências precisarem de sua própria versão do Underscore.

Alguns projetos usam os dois: usam o Bower para pacotes front-end e o npm para ferramentas de desenvolvedor como Yeoman, Grunt, Gulp, JSHint, CoffeeScript, etc.


Recursos

Sindre Sorhus
fonte
37
Por que uma árvore de dependência aninhada não se sai bem no front-end?
Lars Nyström
24
Um pacote npm de front-end não poderia ser uma árvore de dependência simples também? Estou enfrentando o "por que precisamos de 2 gerenciadores de pacotes?" dilema.
Steven Vachon
38
O que você quer dizer com "árvore de dependência plana"? Árvore plana é o que - uma lista? Não é uma árvore então.
Mvmn 17/10/2014
14
Na verdade, um caminho também é uma árvore. É apenas um caso especial. Da WikiPedia: "Na matemática, e mais especificamente na teoria dos grafos, uma árvore é um gráfico não direcionado no qual quaisquer dois vértices são conectados por exatamente um caminho".
Jørgen Fogh
42
O npm 3 agora suporta uma árvore de dependência simples.
vasa
361

Esta resposta é uma adição à resposta de Sindre Sorhus. A principal diferença entre npm e Bower é a maneira como eles tratam dependências recursivas. Observe que eles podem ser usados ​​juntos em um único projeto.

Nas perguntas frequentes do npm : (link archive.org de 6 de setembro de 2015)

É muito mais difícil evitar conflitos de dependência sem aninhar dependências. Isso é fundamental para a maneira como o npm funciona e provou ser uma abordagem extremamente bem-sucedida.

Na página inicial do Bower :

O Bower é otimizado para o front-end. O Bower usa uma árvore de dependência simples, exigindo apenas uma versão para cada pacote, reduzindo o carregamento da página ao mínimo.

Em resumo, o npm visa à estabilidade. O Bower visa uma carga mínima de recursos. Se você desenhar a estrutura de dependência, verá o seguinte:

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

Como você pode ver, instala algumas dependências recursivamente. A dependência A possui três instâncias instaladas!

Bower:

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

Aqui você vê que todas as dependências exclusivas estão no mesmo nível.

Então, por que se preocupar em usar o npm?

Talvez a dependência B exija uma versão diferente da dependência A que a dependência C. O npm instala as duas versões dessa dependência para que funcione de qualquer maneira, mas o Bower fornecerá um conflito porque não gosta de duplicação (porque carregar o mesmo recurso em uma página da web é muito ineficiente e caro, também pode dar alguns erros sérios). Você terá que escolher manualmente qual versão deseja instalar. Isso pode ter o efeito de que uma das dependências será interrompida, mas isso é algo que você precisará corrigir de qualquer maneira.

Portanto, o uso comum é o Bower para os pacotes que você deseja publicar em suas páginas da web (por exemplo , tempo de execução , onde você evita duplicação) e usa o npm para outras coisas, como teste, construção, otimização, verificação etc. ( tempo de desenvolvimento, por exemplo) , onde a duplicação é menos preocupante).

Atualização para npm 3:

A NPM 3 ainda faz as coisas de maneira diferente em comparação com a Bower. Ele instalará as dependências globalmente, mas apenas para a primeira versão que encontrar. As outras versões são instaladas na árvore (o módulo pai e, em seguida, node_modules).

  • [node_modules]
    • dep A v1.0
    • dep B v1.0
      • dep A v1.0 (usa versão raiz)
    • dep C v1.0
      • dep A v2.0 (esta versão é diferente da versão raiz, portanto, será uma instalação aninhada)

Para obter mais informações, sugiro ler os documentos da npm 3

Justus Romijn
fonte
4
É quase um clichê agora que "o desenvolvimento de software tem tudo a ver com trade-offs". Este é um bom exemplo. É preciso escolher uma maior estabilidade npm ou uma carga mínima de recursos bower.
Jfmercer
6
@ Shrek, afirmo implicitamente que você realmente pode usar os dois. Eles têm finalidades diferentes, como afirmo no parágrafo final. Não é uma troca aos meus olhos.
Justus Romijn
Ahh, vejo que te entendi mal. Ou não li com atenção suficiente. Obrigado pelo esclarecimento. :-) É bom que ambos possam ser usados ​​sem compromisso.
Jfmercer
4
@AlexAngas Adicionei uma atualização para o npm3. Ainda tem algumas diferenças importantes em comparação com o Bower. O npm provavelmente sempre suportará várias versões de dependências, enquanto o Bower não.
Justus Romijn
npm 3 se aproximando do caramanchão;)
ni3 21/03
269

TL; DR: A maior diferença no uso diário não é dependências aninhadas ... é a diferença entre módulos e globais.

Eu acho que os pôsteres anteriores cobriram bem algumas das distinções básicas. (o uso do NPM de dependências aninhadas é realmente muito útil no gerenciamento de aplicativos grandes e complexos, embora eu não ache que seja a distinção mais importante.)

Surpreende-me, no entanto, que ninguém tenha explicitamente explicado uma das distinções mais fundamentais entre Bower e npm. Se você ler as respostas acima, verá a palavra 'módulos' frequentemente usada no contexto de npm. Mas é mencionado casualmente, como se pudesse ser apenas uma diferença de sintaxe.

Mas essa distinção entre módulos e globais (ou módulos versus 'scripts') é possivelmente a diferença mais importante entre Bower e npm. A abordagem npm de colocar tudo em módulos exige que você altere a maneira como escreve Javascript para o navegador, quase certamente para melhor.

A abordagem Bower: recursos globais, como <script>tags

Na raiz, o Bower trata de carregar arquivos de script antigos. O que quer que esses arquivos de script contenham, o Bower os carregará. Que basicamente significa que Bower é como incluindo todos os seus scripts na planície de idade <script>está no <head>do seu HTML.

Portanto, a mesma abordagem básica à qual você está acostumado, mas você obtém algumas conveniências agradáveis ​​de automação:

  • Você costumava incluir dependências JS no repositório do projeto (durante o desenvolvimento) ou obtê-las via CDN. Agora, você pode pular esse peso extra de download no repositório e alguém pode fazer um rápido bower installe instantaneamente ter o que precisa, localmente.
  • Se uma dependência do Bower especificar suas próprias dependências bower.json, elas também serão baixadas para você.

Além disso, o Bower não muda a maneira como escrevemos javascript . Nada sobre o que está dentro dos arquivos carregados pelo Bower precisa mudar. Em particular, isso significa que os recursos fornecidos nos scripts carregados pelo Bower (normalmente, mas nem sempre) ainda serão definidos como variáveis ​​globais , disponíveis em qualquer lugar do contexto de execução do navegador.

A abordagem npm: módulos JS comuns, injeção explícita de dependência

Todo o código no nó Node (e, portanto, todo o código carregado via npm) é estruturado como módulos (especificamente, como uma implementação do formato do módulo CommonJS , ou agora, como um módulo ES6). Portanto, se você usar o NPM para lidar com dependências do lado do navegador (via Browserify ou qualquer outra coisa que faça o mesmo trabalho), estruture seu código da mesma forma que o Node.

Pessoas mais inteligentes do que eu já abordamos a pergunta 'Por que módulos?', Mas aqui está um resumo da cápsula:

  • Qualquer coisa dentro de um módulo está efetivamente no namespace , o que significa que não é mais uma variável global e você não pode fazer referência acidental a ela sem a intenção.
  • Qualquer coisa dentro de um módulo deve ser injetada intencionalmente em um contexto específico (geralmente outro módulo) para fazer uso dele
  • Isso significa que você pode ter várias versões da mesma dependência externa (lodash, digamos) em várias partes do seu aplicativo e elas não colidirão / entrarão em conflito. (Isso acontece surpreendentemente com frequência, porque seu próprio código deseja usar uma versão de uma dependência, mas uma de suas dependências externas especifica outra que entra em conflito. Ou você tem duas dependências externas que cada uma deseja uma versão diferente.)
  • Como todas as dependências são injetadas manualmente em um módulo específico, é muito fácil argumentar sobre elas. Você sabe de fato: "O único código que preciso considerar ao trabalhar nisso é o que escolhi intencionalmente para injetar aqui" .
  • Como até o conteúdo dos módulos injetados está encapsulado atrás da variável que você atribui e todo o código é executado dentro de um escopo limitado, surpresas e colisões se tornam muito improváveis. É muito, muito menos provável que algo de uma de suas dependências redefina acidentalmente uma variável global sem que você perceba ou faça isso. (Isso pode acontecer, mas você geralmente precisa se esforçar para fazê-lo, com algo parecido window.variable. O único acidente que ainda tende a ocorrer é atribuir this.variable, sem perceber que isso thisestá realmente windowno contexto atual.)
  • Quando você deseja testar um módulo individual, é capaz de saber com muita facilidade: exatamente o que mais (dependências) está afetando o código que é executado dentro do módulo? E, como você está injetando tudo explicitamente, pode facilmente zombar dessas dependências.

Para mim, o uso de módulos para código front-end se resume a: trabalhar em um contexto muito mais restrito, mais fácil de raciocinar e testar, e ter maior certeza sobre o que está acontecendo.


Leva apenas 30 segundos para aprender como usar a sintaxe do módulo CommonJS / Node. Dentro de um determinado arquivo JS, que será um módulo, primeiro você declara quaisquer dependências externas que deseja usar, como este:

var React = require('react');

Dentro do arquivo / módulo, você faz o que normalmente faria e cria algum objeto ou função que deseja expor a usuários externos, talvez chamando isso myModule.

No final de um arquivo, você exporta o que quiser compartilhar com o mundo, desta forma:

module.exports = myModule;

Em seguida, para usar um fluxo de trabalho baseado em CommonJS no navegador, você usará ferramentas como o Browserify para capturar todos os arquivos individuais do módulo, encapsular seu conteúdo em tempo de execução e injetar um no outro, conforme necessário.

E, como os módulos ES6 (que você provavelmente transpilará para o ES5 com Babel ou similar) estão ganhando ampla aceitação e funcionam tanto no navegador quanto no Nó 4.0, também devemos mencionar uma boa visão geral deles.

Mais sobre padrões para trabalhar com módulos neste deck .


EDIT (fevereiro de 2017): O Yarn do Facebook é um substituto / suplemento potencial muito importante para o npm atualmente: gerenciamento de pacotes offline, rápido e determinístico, que se baseia no que o npm oferece. Vale a pena dar uma olhada em qualquer projeto JS, principalmente porque é muito fácil trocá-lo.


EDIT (maio de 2019) "O Bower finalmente foi preterido . Fim da história." (h / t: @DanDascalescu, abaixo, para obter um resumo conciso.)

E, enquanto o Yarn ainda está ativo , grande parte do momento mudou para npm depois de adotar algumas das principais características do Yarn.

XML
fonte
13
Ainda bem que esta resposta foi aqui, as outras respostas populares não mencionam esse detalhe. O npm obriga a escrever código modular.
Juan Mendes
Sinto muito, de um povo que se preocupa muito pouco com toda a confusão nas áreas de javascript, mas acontece que ele administra uma empresa que faz uso de um pequeno aplicativo da web. Recentemente, fomos forçados a experimentar o npm, usando o bower com o kit de ferramentas que usamos para desenvolver a maldita coisa da web. Posso dizer-lhe que a maior diferença é o tempo de espera, npm leva idades. Lembre-se de que está compilando o xkcd cartoon com os caras jogando brigas de espada gritando 'compilando' para o chefe deles; isso é praticamente o que o npm adicionou ao caramanchão.
Pedro Rodrigues
129

Atualização de outubro de 2017

Bower finalmente foi preterido . Fim da história.

Resposta mais antiga

De Mattias Petter Johansson, desenvolvedor JavaScript no Spotify :

Em quase todos os casos, é mais apropriado usar o Browserify e o npm no Bower. É simplesmente uma solução de empacotamento melhor para aplicativos front-end do que o Bower. No Spotify, usamos o npm para empacotar módulos da Web inteiros (html, css, js) e funciona muito bem.

Bower se autodenomina gerente de pacotes da web. Seria incrível se isso fosse verdade - um gerenciador de pacotes que tornasse minha vida melhor como desenvolvedor front-end seria incrível. O problema é que o Bower não oferece ferramentas especializadas para esse fim. Ele NÃO oferece ferramentas que eu saiba que o npm não oferece, e especialmente nenhuma que seja especificamente útil para desenvolvedores front-end. Simplesmente não há benefício para um desenvolvedor front-end usar o Bower acima da npm.

Deveríamos parar de usar o pavilhão e consolidar em torno das npm. Felizmente, é isso que está acontecendo :

Contagens de módulos - caramanchão vs. npm

Com o browserify ou o webpack, fica super fácil concatenar todos os seus módulos em grandes arquivos compactados, o que é incrível para desempenho, especialmente para dispositivos móveis. O mesmo não acontece com Bower, que exigirá muito mais trabalho para obter o mesmo efeito.

O npm também oferece a capacidade de usar várias versões de módulos simultaneamente. Se você não desenvolveu muito o desenvolvimento de aplicativos, isso pode parecer uma coisa ruim inicialmente, mas depois de passar por alguns episódios do inferno da Dependência, você perceberá que ter a capacidade de ter várias versões de um módulo é um absurdo. ótimo recurso. Observe que o npm inclui uma ferramenta de desduplicação muito útil que garante automaticamente que você use apenas duas versões de um módulo se você realmente precisar - se dois módulos puderem usar a mesma versão de um módulo, eles o usarão. Mas se não puderem , você tem uma solução muito útil.

(Observe que o Webpack e o rollup são considerados melhores que o Browserify a partir de agosto de 2016.)

Dan Dascalescu
fonte
7
<sarcasm> Lembre-se de que mesmo o projeto 'hello world' npm precisa de mais de 300 módulos para rodar ... </sarcasm>: O
Mariusz Jamro 11/16/16
1
Não concordo que "grandes arquivos compactados" sejam "impressionantes para desempenho, especialmente para dispositivos móveis". Muito pelo contrário: a largura de banda restrita requer arquivos pequenos, carregados sob demanda.
Michael Franzl
Não é um conselho muito bom. A maioria dos pacotes npm é apenas back-end do nodejs. Se você não está fazendo javascript no backend, ou você não tem um sistema de módulos no lugar, o número de pacotes é irrelevante porque Bower vai atender às suas necessidades muito melhor
Gerardo Grignoli
4
@ GerardoGrignoli: o caramanchão está saindo .
Dan Dascalescu
45

O Bower mantém uma única versão dos módulos, apenas tenta ajudá-lo a selecionar a melhor / correta para você.

Gerenciamento de dependência de Javascript: npm vs bower vs volo?

O NPM é melhor para os módulos do nó, porque existe um sistema de módulos e você está trabalhando localmente. O Bower é bom para o navegador, porque atualmente existe apenas o escopo global e você deseja ser muito seletivo quanto à versão com a qual trabalha.

Sagivf
fonte
4
Eu sinto que Sindre menciona isso quando ele fala sobre dependência aninhada.
Games Brainiac
5
@GamesBrainiac seu correto, apenas pensei em colocá-lo em minhas próprias palavras.
Sagivf
1
@Sagivf Estes são NÃO suas próprias palavras, a menos que você também é wheresrhys que forneceu a resposta original aqui
dayuloli
4
@ Sagivf Não há nada de errado em copiar ** partes relevantes das respostas de outras pessoas se elas não fornecerem uma resposta aqui. Isso me incomodou um pouco, você disse "apenas pensei em colocar isso com minhas próprias palavras". O crédito deve ir para onde é devido.
dayuloli
2
Não sei por que vocês escolheram tanto essa resposta. De fato, há novas informações / perspectivas nesta resposta para mim.
Calvin
33

Minha equipe se afastou do Bower e migrou para o npm porque:

  • O uso programático foi doloroso
  • A interface do Bower continuou mudando
  • Alguns recursos, como a abreviação do URL, são totalmente quebrados
  • Usar Bower e npm no mesmo projeto é doloroso
  • Manter o campo da versão bower.json sincronizado com as tags git é doloroso
  • Source control! = Gerenciamento de pacotes
  • O suporte ao CommonJS não é direto

Para mais detalhes, consulte "Por que minha equipe usa npm em vez de bower" .

Nick Heiner
fonte
17

Encontrei esta explicação útil em http://ng-learn.org/2013/11/Bower-vs-npm/

Por um lado, o npm foi criado para instalar módulos usados ​​em um ambiente node.js. ou ferramentas de desenvolvimento criadas usando o node.j, como Karma, lint, minifiers e assim por diante. O npm pode instalar módulos localmente em um projeto (por padrão em node_modules) ou globalmente para serem usados ​​por vários projetos. Em projetos grandes, a maneira de especificar dependências é criando um arquivo chamado package.json, que contém uma lista de dependências. Essa lista é reconhecida pelo npm quando você executa o npm install, que os baixa e instala para você.

Por outro lado, o caramanchão foi criado para gerenciar suas dependências de front-end. Bibliotecas como jQuery, AngularJS, sublinhado, etc. Semelhante ao npm, ele possui um arquivo no qual você pode especificar uma lista de dependências chamada bower.json. Nesse caso, suas dependências de front-end são instaladas executando o bower install, que por padrão as instala em uma pasta chamada bower_components.

Como você pode ver, embora eles executem uma tarefa semelhante, eles são direcionados para um conjunto muito diferente de bibliotecas.

Henry Neo
fonte
1
Com o advento de npm dedupe, isso está um pouco desatualizado. Veja a resposta de Mattias .
Dan Dascalescu
7

Para muitas pessoas que trabalham com o node.js, um grande benefício do bower é gerenciar dependências que não são javascript. Se eles estiverem trabalhando com idiomas que são compilados em javascript, o npm pode ser usado para gerenciar algumas de suas dependências. no entanto, nem todas as suas dependências serão módulos node.js. Alguns daqueles que são compilados em javascript podem ter erros específicos de idioma de origem estranhos que fazem com que passá-los compilados em javascript seja uma opção deselegante quando os usuários esperam o código-fonte.

Nem tudo no pacote npm precisa ser javascript voltado para o usuário, mas para os pacotes da biblioteca npm, pelo menos parte deve ser.

jessopher
fonte
Esta postagem do blog do npmjs declara "Seu pacote pode conter qualquer coisa, seja ES6, JS do lado do cliente ou até HTML e CSS. São coisas que naturalmente aparecem ao lado do JavaScript, então coloque-as lá".
Dan Dascalescu
1
Há uma diferença entre pode conter e deve incluir . É claro que eles podem conter qualquer coisa, mas, em geral, devem incluir algum tipo de interface para o commonJS. Afinal, é o 'gerenciador de pacotes do nó'. A parte sobre Essas são coisas que aparecem naturalmente ao lado do Javascript é importante. Há muitas coisas relacionadas ao javascript tangencialmente que não aparecem naturalmente ao lado dele.
jessopher