Conhecendo o NPM 1.0
No dia primeiro deste mês, foi lançado a versão 1.0 do NPM (Node Package Manager). Pra quem não sabe, o NPM é o gerenciador de pacotes oficial do Node.JS. É com ele que criamos e baixamos bibliotecas para desenvolver nossas aplicações em Node.JS.
Não vou explicar aqui como funcionava até a versão 0.3.18 (a última antes das pré 1.0) para não ficar um artigo grande (já vai ficar), mas a explicação sobre o funcionamento da versão 1.0 deve ser suficiente para você conseguir migrar.
Instalando
Existem algumas instruções de instalação, mas basicamente a melhor forma é instalar limpando as coisas velhas. Digo isso porque agora que chegou na 1.0 e quase todas as libs já atualizaram para essa versão e novo modelo, não faz sentido manter libs, a não ser que você tenha alguma lib muito específica. Execute o seguinte:
$ curl http://npmjs.org/install.sh | clean=yes sh
Certifique que você tem permissão para escrever no diretório /usr/local.
Isso vai instalar o NPM 1.0.6 (versão do momento que escrevo o artigo) e limpar suas libs antigas). Se preferir, desinstale antes seu NPM antigo (npm uninstall npm) e apague o diretório ~/.npm. Novidades da instalação:
/usr/local/bin/npm #executável /usr/local/lib/node_modules/ #pacotes globais
Desde a versão 0.4.x do Node.JS, o diretório node_modules passa a ser o diretório de armazenamento de pacotes, sempre contextualmente ao diretório do projeto que você está trabalhando. Tanto isso é verdade que as bibliotecas instaladas em /usr/local/lib/node_modules/ não ficam automaticamente visíveis para você dar require nelas. Falarei mais sobre isso adiante.
Sendo assim, a nova forma de trabalhar com o NPM é a seguinte:
- Pacotes que contém executáveis (nodeunit, express, etc) instale com npm install pacote -g
- Pacotes sem executáveis instale com npm install pacote
Qual a diferença?
A diferença é que a instalação utilizando -g deve ser utilizada primariamente para pacotes que contém executáveis, pois os executáveis já ficam visíveis no path. Outro uso é quando você quer compartilhar algum pacote com diversos projetos. Isso é feito criando um link, que falaei adiante. A instalação local limita o pacote ao escopo do projeto/diretório que foi instalado, ou seja, somente dentro desse diretório e seus subdiretórios esse pacote estará disponível para require.
Para listar os pacotes instalados localmente, basta executar o seguinte comando:
$ npm list [email protected] /Users/emerson.leite/Pet/node-database-cleaner ├─┬ [email protected] │ ├── [email protected] │ └─┬ [email protected] │ └── [email protected] ├── [email protected] ├── [email protected] └── [email protected]
Esse comando lista apenas os pacotes instalados no diretório node_modules dentro do diretório que aparece logo abaixo do comando npm list (ou npm ls)
Para listar os pacotes globais basta executar:
$ npm ls -g /usr/local/lib ├─┬ [email protected] │ ├── [email protected] │ └── [email protected] ├── [email protected] └─┬ [email protected] ├── [email protected] ├── [email protected] ├── [email protected] └── [email protected]
Repare que a lista é bem diferente. Nenhum desses pacotes podem ser utilizados sem que sejam linkados. Vamos fazer isso agora para que eles fiquem disponíveis localmente.
$ npm link connect ./node_modules/connect -> /usr/local/lib/node_modules/connect
E agora veremos novamente nossos pacotes locais:
$ npm ls [email protected] /Users/emerson.leite/Pet/node-database-cleaner ├─┬ [email protected] -> /usr/local/lib/node_modules/connect extraneous │ ├── [email protected] │ └── [email protected] ├─┬ [email protected] │ ├── [email protected] │ └─┬ [email protected] │ └── [email protected] ├── [email protected] ├── [email protected] └── [email protected]
Repare que o pacote connect aponta para um diretório na instalação global. Com esse link, é possível utilizar o pacote no projeto/diretório atual.
Alguns desenvolvedores utilizam a variável de ambiente NODE_PATH apontando para /usr/local/lib/node_modules/ porque seus projetos não estão enxergando os pacotes globais. De fato isso funciona, mas não é a maneira adequada, pois se você instalar um pacote local e outro global utilizando essa configuração, o pacote global vai prevalecer sobre o local, o que não deveria ser o comportamento esperado.
É importante entender que o escopo local é definido tão somente pelo diretório que você está. Se você voltar um diretório e listar novamente os pacotes perceberá que não tem nada instalado ou a lista de pacotes instalados é diferente (no caso de você ter instalado algo nesse diretório). Vejamos:
$ cd .. $ npm ls /Users/emerson.leite/Pet (empty)
Voltemos para o diretório anterior e vamos remover o link ao pacote connect.
$ cd - /Users/emerson.leite/Pet/node-database-cleaner $ npm unlink connect $ npm ls [email protected] /Users/emerson.leite/Pet/node-database-cleaner ├─┬ [email protected] │ ├── [email protected] │ └─┬ [email protected] │ └── [email protected] ├── [email protected] ├── [email protected] └── [email protected]
Nesse momento não temos mais o link para o pacote connect e portanto não podemos mais fazer um require dele.
Utilizando o package.json para gerenciar suas dependências
O arquivo package.json é um arquivo que descreve um pacote NPM. Nesse arquivo também pode/deve ser utilizado para especificar os pacotes que seu projeto depende. Dessa forma, basta estar no diretório e executar npm install que o NPM já instalará as dependências necessárias. Vejamos um exemplo:
{ "name" : "database-cleaner", "description" : "Database Cleaner for node.js", "keywords" : [ "database", "cleaner", "mongodb", "redis", "couchdb", "tests", "package.json" ], "version" : "0.3.2", "author" : "Emerson Macedo ", "repository" : { "type" : "git", "url" : "git://github.com/emerleite/node-database-cleaner.git" }, "dependencies" : { "mongoose" : "1.0.10", "redis" : ">=0.5.7", "cradle" : ">=0.5.x" }, "main": "index", "engines" : { "node" : ">=0.2.5" } }
Vamos limpar o diretório e instalar novamente as dependências para ver como funciona. Primeiro vou apagar o diretório node_modules, listar para mostrar que está vazio e instalar as dependências.
$ rm -fr node_modules/ $ npm ls npm WARN cradle >=0.5.x Unmet dependency in /Users/emerson.leite/Pet/node-database-cleaner npm WARN mongoose 1.0.10 Unmet dependency in /Users/emerson.leite/Pet/node-database-cleaner npm WARN redis >=0.5.7 Unmet dependency in /Users/emerson.leite/Pet/node-database-cleaner [email protected] /Users/emerson.leite/Pet/node-database-cleaner ├── UNMET DEPENDENCY cradle >=0.5.x ├── UNMET DEPENDENCY mongoose 1.0.10 └── UNMET DEPENDENCY redis >=0.5.7
A resposta mostra que as dependências não estão instaladas, o que vamos resolver agora:
$ npm install [email protected] ./node_modules/redis [email protected] ./node_modules/mongoose [email protected] ./node_modules/cradle/node_modules/vargs [email protected] ./node_modules/cradle/node_modules/vows/node_modules/eyes [email protected] ./node_modules/cradle/node_modules/vows [email protected] ./node_modules/cradle
Agora vamos listar apenas para conferir.
$ npm ls [email protected] /Users/emerson.leite/Pet/node-database-cleaner ├─┬ [email protected] │ ├── [email protected] │ └─┬ [email protected] │ └── [email protected] ├── [email protected] └── [email protected]
Pra fechar
O NPM tem uma série de outros recursos que vou tentar destacar em outros artigos, mas vejo que muita gente não estava entendendo bem a forma mais adequada de usar a versão 1.0, inclusive apelando para o uso inadequado da variável de ambiente NODE_PATH. Espero que este artigo possa ajudar a explicar um pouco do NPM 1.0.