Pular para o conteúdo principal

Organize o código Dart com pacotes e bibliotecas

Aprenda a organizar seu código Dart em bibliotecas e pacotes reutilizáveis.

Assistir no YouTube em uma nova aba: "The Dart platform"

Neste capítulo, você vai evoluir da sintaxe básica do Dart para criar aplicações de linha de comando "do jeito Dart", seguindo boas práticas. Você vai aprender a refatorar seu código em componentes reutilizáveis criando um pacote dedicado para tratar os argumentos de linha de comando.

Este passo prepara você para construir uma aplicação de linha de comando mais avançada nos próximos capítulos, que vão integrar pacotes especializados para a lógica da Wikipédia e um framework command_runner robusto. Este capítulo ajuda você a entender bibliotecas do Dart, instruções export e como estruturar seu projeto para melhor organização e manutenibilidade.

O que você vai realizar

Crie um pacote Dart reutilizável
Use exports para definir uma API pública
Adicione dependências de caminho local

Pré-requisitos

#
  • Conclusão do Capítulo 3, que abordou programação assíncrona e requisições HTTP.

Tarefas

#

Neste capítulo, você vai refatorar a aplicação de linha de comando dartpedia existente, extraindo a lógica de análise de argumentos para um pacote separado chamado command_runner. Isso vai melhorar a estrutura do projeto, tornando-o mais modular e fácil de manter.

Tarefa 1: Crie o pacote command_runner

#

Primeiro, crie um novo pacote Dart para abrigar a lógica de análise de argumentos de linha de comando.

  1. Acesse o diretório raiz do seu projeto (/dartpedia).

  2. Execute o comando a seguir no seu terminal:

    bash
    dart create -t package command_runner
    

    Esse comando cria um novo diretório chamado command_runner com a estrutura básica de um pacote Dart. Agora você deve ver uma nova pasta command_runner na raiz do projeto, ao lado do seu pacote cli.

Tarefa 2: Implemente a classe CommandRunner

#

Agora que você criou o pacote command_runner, adicione uma classe provisória que, no futuro, vai tratar a lógica de análise de argumentos de linha de comando.

  1. Abra o arquivo command_runner/lib/command_runner.dart. Remova qualquer código provisório existente e adicione o seguinte:

    command_runner/lib/command_runner.dart
    dart
    /// A simple command runner to handle command-line arguments.
    ///
    /// More extensive documentation for this library goes here.
    library;
    ​
    export 'src/command_runner_base.dart';
    // TODO: Export any other libraries intended for clients of this package.
    

    Destaques do código anterior:

    • library; declara este arquivo como uma biblioteca, que define os limites e a interface pública de uma unidade reutilizável de código Dart.
    • export 'src/command_runner_base.dart'; é uma linha crucial que torna as declarações de command_runner_base.dart disponíveis para outros pacotes que importam o pacote command_runner. Sem essa instrução export, as classes e funções dentro de command_runner_base.dart seriam privadas ao pacote command_runner, e você não conseguiria usá-las na sua aplicação dartpedia.
  2. Abra o arquivo command_runner/lib/src/command_runner_base.dart.

  3. Remova qualquer código provisório existente e adicione a seguinte classe CommandRunner em command_runner/lib/src/command_runner_base.dart:

    command_runner/lib/src/command_runner_base.dart
    dart
    class CommandRunner {
      /// Runs the command-line application logic with the given arguments.
      Future<void> run(List<String> input) async {
        print('CommandRunner received arguments: $input');
      }
    }
    

    Destaques do código anterior:

    • CommandRunner é uma classe que, por enquanto, serve como uma versão simplificada. Seu método run apenas imprime os argumentos que recebe. Nos próximos capítulos, você vai expandir essa classe para tratar análises de comandos complexas e configuráveis.
    • Future<void> é um tipo de retorno que indica que este método pode executar operações assíncronas, mas não retorna um valor.

Tarefa 3: Adicione command_runner como dependência

#

Agora que você criou o pacote command_runner e adicionou a classe provisória CommandRunner, precisa informar à sua aplicação cli que ela depende do command_runner. Como o pacote command_runner está localizado localmente no seu projeto, você pode usar uma dependência de caminho.

  1. Abra o arquivo cli/pubspec.yaml.

  2. Como o pacote cli é um pacote de aplicação e não deve ser publicado no pub.dev, adicione publish_to: none logo após o campo name. Isso ajuda a evitar publicações acidentais e impede avisos do analisador sobre a adição de dependências de caminho.

    cli/pubspec.yaml
    yaml
    name: cli
    publish_to: none
    # ...
    
  3. Localize a seção dependencies. Adicione as linhas a seguir:

    cli/pubspec.yaml
    yaml
    dependencies:
      http: ^1.3.0 # Keep your existing http dependency
      command_runner:
        path: ../command_runner # Points to your local command_runner package
    

    Esta seção informa à aplicação cli que ela depende do pacote command_runner e especifica que o pacote está no diretório ../command_runner (relativo ao diretório cli).

  4. Execute dart pub get no diretório /dartpedia/cli do seu terminal para baixar a nova dependência.

Tarefa 4: Importe e use o pacote command_runner

#

Agora que você adicionou command_runner como dependência, pode importá-lo na sua aplicação cli e substituir a lógica atual de tratamento de argumentos pela nova classe CommandRunner.

  1. Abra o arquivo cli/bin/cli.dart.

  2. Adicione a instrução de importação a seguir no topo do arquivo, junto com as outras importações:

    cli/bin/cli.dart
    dart
    import 'package:command_runner/command_runner.dart';
    

    Esta instrução importa o pacote command_runner, tornando a classe CommandRunner disponível para uso.

  3. Refatore a função main e remova a lógica antiga: Atualmente, sua função main do Capítulo 3 trata diretamente comandos como version, help e wikipedia, e depois chama searchWikipedia. Agora você vai substituir toda essa lógica de tratamento de comandos por uma única chamada à nova classe CommandRunner.

    O seu arquivo cli/bin/cli.dart (do Capítulo 3) deve estar assim neste momento:

    cli/bin/cli.dart
    dart
    import 'dart:io';
    import 'package:http/http.dart' as http;
    import 'package:command_runner/command_runner.dart';
    ​
    const version = '0.0.1';
    ​
    void main(List<String> arguments) {
      if (arguments.isEmpty || arguments.first == 'help') {
        printUsage();
      } else if (arguments.first == 'version') {
        print('Dartpedia CLI version $version');
      } else if (arguments.first == 'wikipedia') {
        final inputArgs = arguments.length > 1 ? arguments.sublist(1) : null;
        searchWikipedia(inputArgs);
      } else {
        printUsage();
      }
    }
    ​
    void searchWikipedia(List<String>? arguments) async { /* ... existing logic ... */ }
    void printUsage() { /* ... existing logic ... */ }
    Future<String> getWikipediaArticle(String articleTitle) async { /* ... existing logic ... */ }
    

    Agora, substitua todo o conteúdo de cli/bin/cli.dart (exceto a importação de http) pela versão atualizada a seguir:

    cli/bin/cli.dart
    dart
    import 'dart:io';
    import 'package:http/http.dart' as http;
    import 'package:command_runner/command_runner.dart';
    ​
    void main(List<String> arguments) async { // main is now async and awaits the runner
      var runner = CommandRunner(); // Create an instance of your new CommandRunner
      await runner.run(arguments); // Call its run method, awaiting its Future<void>
    }
    

    Destaques do código anterior:

    • Declarar main como async permite usar await. Como runner.run() retorna um Future, aguardá-lo faz com que main espere explicitamente a conclusão do runner, garantindo uma ordem lógica clara e melhorando a propagação de erros.
    • var runner = CommandRunner(); cria uma instância da classe CommandRunner do seu novo pacote command_runner.
    • await runner.run(arguments); chama o método run da instância de CommandRunner, passando os argumentos de linha de comando.

    Funções removidas:

    • As funções printUsage, searchWikipedia e getWikipediaArticle agora foram completamente removidas de cli/bin/cli.dart. A lógica delas será redesenhada e movida para o pacote command_runner nos próximos capítulos, como parte da construção do framework completo de linha de comando.

Tarefa 5: Execute a aplicação

#

Agora que você refatorou o código e atualizou a aplicação cli para usar o pacote command_runner, execute a aplicação para verificar se tudo está funcionando corretamente nesta etapa.

  1. Abra o terminal e acesse o diretório cli.

  2. Execute o comando wikipedia:

    bash
    dart run bin/cli.dart wikipedia Computer_programming
    
  3. Confirme que a aplicação agora executa sem erros e imprime os argumentos no console, demonstrando que o controle foi transferido com sucesso para o seu novo pacote command_runner.

    bash
    CommandRunner received arguments: [wikipedia, Computer_programming]
    

Revisão

#

O que você realizou

Aqui está um resumo do que você construiu e aprendeu nesta lição.
Criou um pacote Dart reutilizável

Você usou dart create -t package command_runner para criar a estrutura de um novo pacote de biblioteca, feito para ser usado em outros pacotes. Pacotes de biblioteca são a forma padrão de organizar e compartilhar bibliotecas Dart reutilizáveis, tanto dentro de um workspace de projeto quanto publicadas no pub.dev.

Usou exports para definir uma API pública

Você adicionou instruções export no arquivo da biblioteca para expor bibliotecas específicas e suas definições aos consumidores. Se não forem exportados a partir dos arquivos na raiz lib, os códigos em lib/src/ continuam privados ao pacote. Isso permite criar cuidadosamente uma API pública para outros, mantendo controle total sobre os detalhes de implementação.

Adicionou dependências de caminho local

Você configurou o pubspec.yaml para depender de um pacote local usando uma dependência de caminho. Isso possibilita projetos com múltiplos pacotes que podem evoluir juntos antes de serem publicados separadamente.

Quiz

#

Check your understanding

1 / 3
Qual é a finalidade da instrução export em uma biblioteca Dart?
  1. Tornar declarações de outros arquivos disponíveis pela API pública da sua biblioteca.

    Isso mesmo!

    export permite reexpor declarações. Por exemplo, export 'src/command.dart'; torna Command acessível para qualquer pessoa que importe o seu pacote.

  2. Ocultar detalhes de implementação de outras bibliotecas.

    Não exatamente.

    A instrução export faz o oposto de ocultar. Para ocultar membros usados apenas na implementação, não os inclua em nenhuma instrução export.

  3. Importar várias bibliotecas com uma única instrução.

    Não exatamente.

    import e export têm finalidades diferentes. import disponibiliza código para a sua biblioteca, enquanto export faz algo para quem consome a sua biblioteca.

  4. Especificar quais versões do SDK do Dart o seu pacote suporta.

    Não exatamente.

    Restrições de SDK ficam no pubspec.yaml, e não no código Dart. export é um recurso da linguagem Dart, não uma opção de configuração.

Como você adiciona um pacote local (um que está no seu sistema de arquivos) como dependência?
  1. Use uma dependência de path, como command_runner: {path: ../command_runner}.

    Isso mesmo!

    Dependências de path apontam para um diretório local. Isso é ideal para projetos com vários pacotes ou para desenvolver pacotes antes de publicá-los.

  2. Use uma restrição de versão, como command_runner: ^1.0.0.

    Não exatamente.

    Restrições de versão são para pacotes publicados no pub.dev. Pacotes locais exigem outro tipo de especificação de dependência.

  3. Copie a pasta do pacote para o diretório lib/ do seu projeto.

    Não exatamente.

    Copiar cria duplicação e problemas de versionamento. O Dart oferece uma forma de referenciar pacotes pela localização sem copiá-los.

  4. Execute dart pub add command_runner --local

    Não exatamente.

    Não existe a flag --local para dart pub add. Você precisa especificar a localização de outra forma no pubspec.yaml ou passando um descritor de pacote para dart pub add.

Um pacote tem código em lib/src/parser.dart. Por que você pode criar lib/parser.dart que contém apenas export 'src/parser.dart';?
  1. Para permitir que os usuários importem por um caminho limpo enquanto os arquivos de implementação ficam organizados em src/.

    Isso mesmo!

    Os usuários podem escrever import 'package:mylib/parser.dart'; em vez de acessar src/ diretamente. Isso separa a sua API pública da organização interna.

  2. Para o código rodar mais rápido, reduzindo a profundidade dos imports.

    Não exatamente.

    export não afeta o desempenho em tempo de execução. O número de diretórios em um caminho de import não tem impacto na velocidade de execução do código.

  3. Porque o Dart exige que todos os arquivos públicos fiquem na raiz de lib/.

    Não exatamente.

    O Dart não exige essa estrutura. É uma convenção, e não um requisito da linguagem.

  4. Para impedir que outros pacotes importem os arquivos de src/ diretamente.

    Não exatamente.

    Arquivos em src/ ainda podem, tecnicamente, ser importados diretamente. As boas práticas do Dart desencorajam isso, mas não impedem.

Próxima lição

#

O próximo capítulo aborda os conceitos de programação orientada a objetos (POO) em Dart. Crie classes, construtores e getters, e use enums para modelar os argumentos de linha de comando dentro do pacote command_runner.

Encontrou essa página sem tradução ou que precisa de correção? Abra uma issue e nos ajude a manter esse site em PT-BR para ajudar pessoas como você.