JavaScript: Eliminando Dependências Circulares
Tags: javascript, webdev, ptbr, webpack
Published: 2019-04-04 09:33:46

Dependências circulares (também conhecidas como dependências cíclicas) ocorrem quando dois ou mais módulos fazem referência um ao outro.

Esta poderia ser uma referência direta **(A -> B -> A)**:

```js
// arquivo a.ts
import { b } from 'b';
...
export a;

// arquivo b.ts
import { a } from 'a';
...
export b;
```

ou indireta **( A -> B -> C -> A)**:

```js
// arquivo a.ts
import { b } from 'b';
...
export a;

// arquivo b.ts
import { c } from 'c';
...
export b;

// arquivo c.ts
import { a } from 'a';
...
export c;
```

Embora as dependências circulares não resultam diretamente em erros (elas certamente podem), quase sempre terão conseqüências não intencionais. Em nosso projeto, estávamos experimentando lentidão na [verificação de tipos do TypeScript](https://www.typescriptlang.org/) e freqüentes falhas de "falta de memória" do nosso servidor JavaScript.

O [Node.js](https://nodejs.org/en/) suporta instruções circulares `require`/`import` entre os módulos, mas pode ficar confuso rapidamente. Na [documentação do Node.js](https://nodejs.org/api/modules.html#modules_cycles), diz: "É necessário um planejamento cuidadoso para permitir que as dependências do módulo cíclico funcionem corretamente em um aplicativo".

Na minha experiência, a melhor maneira de lidar com dependências circulares é evitá-las completamente. Dependências circulares são geralmente uma indicação de design de código incorreto e devem ser refatoradas e removidas, se possível.

# Verificando Dependências Circulares

Embora existam alguns pacotes de Node que executam a análise estática para procurar por dependências circulares, percebi que eles não funcionam muito bem. Alguns dos pacotes encontraram algumas dependências circulares, enquanto outros erraram completamente todas elas. O melhor verificador de dependência circular que encontrei funciona na camada de empacotamento. O plugin [circular-dependency-plugin](https://github.com/aackerman/circular-dependency-plugin) do webpack foi bastante eficiente e muito simples de usar.

Pegando o [exemplo da documentação do circular-dependency-plugin](https://github.com/aackerman/circular-dependency-plugin#basic-usage):

```js
// webpack.config.js
const CircularDependencyPlugin = require('circular-dependency-plugin')

module.exports = {
  entry: "./src/index",
  plugins: [
    new CircularDependencyPlugin({
      // exclude detection of files based on a RegExp
      exclude: /a\.js|node_modules/,
      // add errors to webpack instead of warnings
      failOnError: true,
      // allow import cycles that include an asyncronous import,
      // e.g. via import(/* webpackMode: "weak" */ './file.js')
      allowAsyncCycles: false,
      // set the current working directory for displaying module paths
      cwd: process.cwd(),
    })
  ]
}
```

Imediatamente, o plugin encontrou todos os tipos de dependências circulares que foram introduzidas durante o projeto:

![Saída do `circular-dependency-plugin`](https://thepracticaldev.s3.amazonaws.com/i/mq8d5mw0oo2corq0low7.png)

# Corrigindo as dependências circulares

Existem algumas opções para se livrar das dependências circulares. Para uma cadeia mais longa **A -> B -> C -> D -> A**, se uma das referências for removida (por exemplo, a referência **D -> A**), o padrão de referência cíclica também será quebrado.

Para padrões mais simples, como **A -> B -> A**, uma refatoração pode ser necessário. Talvez os módulos que vivem em **B** possam ser movidos para **A**. Ou, o código necessário poderia ser extraído para um **C** e tanto **A** e  **B** podem fazer referência. Se os dois módulos executam comportamentos semelhantes, eles também podem ser combinados em um único módulo.

Consertar um grande número de dependências circulares pode ser um compromisso significativo, mas melhora a capacidade de manutenção da base de código e pode reduzir erros no futuro. Ao deixar o plug-in de dependência circular no pipeline do webpack, ele pode ser executado com freqüência e as dependências circulares serão encontradas imediatamente após serem introduzidas.

Da próxima vez que eu estiver iniciando um projeto e configurando as opções do webpack, incluirei esse plug-in no primeiro dia!

# Créditos ⭐️

- [Eliminate Circular Dependencies from Your JavaScript Project](https://spin.atomicobject.com/2018/06/25/circular-dependencies-javascript/), escrito originalmente por [Dan Kelch](https://atomicobject.com/team/dan-kelch)