Caminhos relativos no NodeJS

Sabe quando você precisa dar require em um módulo que você criou, mas ele está em uma estrutura de diretórios bem longe do arquivo que você precisa incluir, e você tem que usar um milhão de ../../../ para chegar até o diretório certo do seu módulo?

Se você não entendeu, vou exemplificar. Digamos que você tem a seguinte estrutura de diretórios no seu projeto:

1
2
3
4
5
6
7
8
9
.
├── /controllers
| ├── /home
| | ├── homeController.js
├── /services
| ├── /home
| | ├── homeService.js
├── /routes
└── app.js

Imagine que nos services você controla todas as regras de negócio e passa para o seu controller. No controller, você precisa então “requisitar” o service específico, chamando ele dessa forma no arquivo homeController.js:

1
var homeService = require( '../../services/home/homeService' );

Como o arquivo homeController.js está dentro do diretório controllers/home, você precisa voltar dois níveis para então chegar no diretório services, entrar ali e chamar o homeService.js.

Agora imagine você fazendo isso em um projeto que começa pequeno, mas vai escalando até ficar gigantesco! Se você resolver refatorar alguma coisa mudando algo de lugar, imagine o trabalho de ficar modificando manualmente essas estruturas de diretórios!

Chato não?!

Mas felizmente, o Node nos dá algumas maneiras de resolver isso. Você pode usar o método resolve() do módulo path, - que é nativo do Node - que vai resolver a sua URL com o caminho absoluto, até onde a aplicação está rodando. Então você pode fazer a chamada assim no seu homeController.js:

1
2
var path = require( 'path' );
var homeService = require( path.resolve( 'services/home/homeService' ) );

O path vai, a partir do caminho absoluto da sua aplicação, concatenar com o parâmetro passado para o método resolve(). Simples não?

Mas é ruim ter que ficar adicionando mais uma linha em todo arquivo que eu precisar fazer um require. Por isso eu criei um módulo marotinho chamado getmodule, que facilita isso pra você!

O getmodule usa o recurso do path.resolve() para gerar o caminho corretamente, mas ele exporta uma variável global chamada getmodule para que você possa substituir o require por ele.

O módulo é só isso:

1
2
3
4
global.getmodule = function getmodule( modulePath ) {
var path = require( 'path' );
return require( path.resolve( modulePath ) );
}

E para usá-lo, é bem simples. Primeiro instale o módulo no seu projeto:

1
npm i --save getmodule

Depois, adicione ele na primeira linha do arquivo principal da sua aplicação. No caso do nosso exemplo, é o app.js:

1
require( 'getmodule' );

E pronto! Agora, no nosso homeController.js, podemos simplesmente chamar o service dessa forma:

1
var homeService = getmodule( 'services/home/homeService' );

Que toda a parte verbosa vai ficar por conta do módulo :D

Ae você me pergunta: É vantagem usar um módulo só pra isso?

Eu penso que sim. Senão você vai ter que ficar criando “helpers” no seu projeto pra fazer isso. Vai acabar deixando o negócio meio desorganizado ou com coisas desnecessárias. Como estamos usando um módulo, ele fica no diretório node_modules e se tiver alguma atualização para ele, pode ser feito via npm update. Muito mais prático trabalhar assim com módulos genéricos.

Existem algumas outras formas de resolver esse problema, que foram discutidas nesse link no grupo NodeJS Brasil, no Facebook.

Bom, por hoje é só! Gostou da dica? Achou ridículo? Comenta aí :)

Até a próxima :D

Sobre o #1postperday: https://blog.da2k.com.br/2014/12/31/um-post-por-dia/