Utilizando caminhos absolutos para imports no React Native

Duas formas para não precisar mais utilizar caminhos relativos

Uma das principais dores que você provavelmente vai sentir ao iniciar um projeto com React Native são os caminhos dos imports. Nesse post vou ensinar duas formas de definir uma pasta como root do seu projeto para que então todos imports partam dessa raiz e você não precise mais utilizar caminhos relativos com vários ../../../

1. Utilizando um arquivo package.json

Essa maneira de definir um root é a mais comum e fácil de criar. Basta você criar um arquivo package.json na pasta que você quer definir como raiz e definir uma propriedade name com o nome da pasta. Dessa forma, o babel passa a olhar para esse diretório como root do seu projeto. Seu arquivo deve ficar mais ou menos assim (pensando que você quer que a pasta src seja a raiz):

// projeto/src/package.json
{
"name": "src"
}

A partir de agora, você pode importar, através de qualquer outro arquivo em qualquer profundidade da seguinte forma:

// Arquivo: projeto/src/Componente.js
import Componente from 'src/Componente';

Desvantagens

Eu utilizava esse padrão para definir minha pasta root do projeto até começar a utilizar ESLint. Com o uso do lint, você provavelmente vai sofrer com esse padrão já que seu projeto agora possui dois arquivos package.json e o ESLint não vai conseguir utilizar os dois para encontrar os módulos. Se você pretende utilizar o ESLint, recomendo que você siga para a segunda forma.

2. Utilizando o plugin module-resolver do Babel

Utilizando o plugin module-resolver do Babel sua vida vai ficar bem mais fácil, principalmente se você utilizar o ESLint. Para configurar o plugin vamos começar instalando o plugin e adicionando-o às nossas configurações do babel no arquivo .babelrc

yarn add babel-plugin-module-resolver --dev
// Utilize o npm install --save-dev se preferir

Agora no nosso arquivo .babelrc vamos adicionar as instruções para definir um novo root ao projeto com a propriedade plugins. Seu arquivo deve ficar assim:

{
"presets": ["react-native"],
"plugins": [
[
"module-resolver",
{
"root": ["./src"],
"extensions": [".js", ".ios.js", ".android.js"]
}
]
]
}

Estamos dizendo para o babel procurar por todos arquivos JS dentro da pasta src do nosso projeto na hora que importamos um novo módulo. Dessa forma, ao importar um módulo em qualquer lugar do código podemos definir o caminho a partir da pasta src :

// Arquivo: projeto/src/Componente.js
import Componente from 'Componente'

Lembre de reiniciar seu emulador depois de instalar o module-resolver, para que o React Native processe seu arquivo .babelrc novamente.

Configurando ESLint

Mesmo com esse plugin do babel instalado, o ESLint retornará erros pois ele não sabe dessa nova configuração. Para funcionar corretamente, vamos instalar dois módulos do ESLint, o eslint-plugin-import e o eslint-import-resolver-babel-module:

yarn add eslint-plugin-import eslint-import-resolver-babel-module --dev
// Utilize o npm install --save-dev se preferir

Agora em seu arquivo .eslintrc na propriedade de plugins (crie se não existir), adicione o plugin import:

"plugins": [
"import"
]

E na propriedade settings vamos adicionar a referência ao módulo do babel:

"settings": {
"import/resolver": {
"babel-module": {}
}
}

Seu arquivo .eslintrc vai ficar mais ou menos parecido com esse:

{
"parser": "babel-eslint",
"env": {
"browser": true
},
"plugins": [
"react-native",
"jsx-a11y",
"import"
],
"extends": [
"plugin:react-native/all"
],
"rules": {},
"settings": {
"import/resolver": {
"babel-module": {}
}
}
}

Pronto, agora seu ESLint não vai mais reclamar dos módulos não encontrados na hora de criar os imports e você já pode ser feliz.

Um problema que encontrei

Utilizando o module-resolver, percebi que algumas vezes o React Packager se perde e acaba não encontrando os módulos, retornando uma tela parecida com essa (apenas em ambiente de desenvolvimento):

Erro do module-resolver no iOS

Para solucionar esse problema, basta ir até o seu terminal, onde o React Packager está sendo executado e parar o processo com ctrl-c e reiniciar o packager pela pasta do seu projeto com o comando npm start -- --reset-cache

Após receber a mensagem Loading dependency graph, done. você já pode atualizar a aplicação e continuar utilizando.

Conclusão

Então basicamente entre as duas formas, eu prefiro a segunda, acho mais escalável e como utilizo ESLint em todos meus projetos, fica difícil ir pela primeira opção. Mas se você está apenas criando um projeto simples para estudar sem ESLint, utilize a primeira opção, muito fácil e rápida de ser configurada.