O Dart possui um sistema de gerenciamento de pacotes e dependências muito robusto, e a forma de lidar com import é bem definida. Veja abaixo como usar o pub e o import de forma flexível, com muitos exemplos para testar.
O Dart utiliza uma ferramenta de linha de comando chamada pub para gerenciar pacotes. Ele é o equivalente ao npm para Node.js/JavaScript, pip para Python, ou Maven/Gradle para Java.
Principais Características do pub:
Todo projeto Dart que utiliza pacotes (o que é praticamente todos, especialmente os projetos Flutter) tem um arquivo chamado pubspec.yaml na raiz do projeto. Este arquivo é escrito em YAML (YAML Ain't Markup Language) e define metadados sobre o seu projeto, como nome, descrição, versão, e, o mais importante, suas dependências.
Exemplo de um pubspec.yaml (parte de dependências):
name: meu_app_dart
description: Um aplicativo Dart incrível.
version: 1.0.0
# homepage: https://www.example.com
environment:
sdk: '>=3.0.0 <4.0.0' # Define a faixa de versões do SDK Dart compatíveis
dependencies:
# Pacotes dos quais seu projeto depende diretamente
http: ^1.2.0 # Pacote 'http' na versão 1.2.0 ou superior, mas menor que 2.0.0
intl: ^0.19.0 # Pacote 'intl' para internacionalização
path: any # Qualquer versão do pacote 'path' (geralmente não recomendado para produção)
# Dependências específicas do Flutter (se for um projeto Flutter)
flutter:
sdk: flutter
cupertino_icons: ^1.0.2
dev_dependencies:
# Pacotes usados apenas para desenvolvimento e testes
lints: ^3.0.0
test: ^1.24.0
build_runner: ^2.4.0 # Se você usar geração de código
A grande maioria dos pacotes Dart de código aberto está hospedada no pub.dev. É um repositório central onde você pode pesquisar, encontrar e publicar pacotes.
Em projetos Flutter, você geralmente usa flutter pub <comando> em vez de apenas pub <comando>, pois o Flutter gerencia sua própria versão do Dart SDK e pub).
dart pub get ou flutter pub get:
Este é o comando mais fundamental. Ele lê o arquivo pubspec.yaml, baixa as dependências listadas (e suas dependências transitivas) do pub.dev (ou de outras fontes especificadas, como um caminho local ou um repositório git) e as armazena em um diretório .dart_tool/ e .pub-cache/. Ele também cria (ou atualiza) o arquivo pubspec.lock, que registra as versões exatas de cada pacote que foram resolvidas. Isso garante builds consistentes em diferentes máquinas e momentos.
dart pub upgrade ou flutter pub upgrade:
Tenta atualizar os pacotes para as versões mais recentes permitidas pelas restrições de versão no seu pubspec.yaml. Ele também atualiza o pubspec.lock.
dart pub outdated ou flutter pub outdated:
Lista as dependências que estão desatualizadas e as versões mais recentes disponíveis.
dart pub add <nome_do_pacote> ou flutter pub add <nome_do_pacote>:
Adiciona um pacote como dependência ao seu pubspec.yaml e executa pub get automaticamente, por exemplo:
flutter pub add http
dart pub remove <nome_do_pacote> ou flutter pub remove <nome_do_pacote>:
Remove um pacote do seu pubspec.yaml e executa pub get.
dart pub publish ou flutter pub publish:
Usado para publicar seu próprio pacote no pub.dev.
O pub usa o versionamento semântico (SemVer). As restrições de versão no pubspec.yaml são flexíveis:
any → Qualquer versão (geralmente não recomendado).
1.2.3 → Exatamente a versão 1.2.3.
^1.2.3 → (Caret syntax) Permite qualquer versão compatível com 1.2.3. Significa >=1.2.3 <2.0.0. Esta é a forma mais comum e recomendada.
'>=1.2.0 <2.0.0' → Intervalo de versões explícito.
Uma vez que os pacotes estão listados no pubspec.yaml e baixados com pub get, você pode usar as classes, funções e constantes desses pacotes no seu código Dart usando a diretiva import.
Vamos ver a sintaxe e os tipos de import:
Para usar as bibliotecas que vêm com o SDK do Dart (como dart:math para funções matemáticas, dart:io para entrada/saída, dart:convert para conversão de JSON, etc.), você usa o esquema dart:.
import 'dart:math'; // Importa a biblioteca matemática
import 'dart:io'; // Importa a biblioteca de I/O
void main() {
print(pi); // Constante 'pi' da biblioteca dart:math
print('Digite algo:');
String? input = stdin.readLineSync(); // stdin e readLineSync de dart:io
print('Você digitou: $input');
}
Para usar bibliotecas que você adicionou ao seu pubspec.yaml, você usa o esquema package:. O pub resolve esses caminhos para os arquivos corretos dentro do diretório .dart_tool/packages/ (que por sua vez aponta para o cache global ou local).
// Supondo que você tenha 'http: ^1.2.0' no seu pubspec.yaml
import 'package:http/http.dart' as http; // 'as http' é um prefixo, veja abaixo
void main() async {
var url = Uri.parse('https://jsonplaceholder.typicode.com/todos/1');
var response = await http.get(url);
print('Status da resposta: ${response.statusCode}');
print('Corpo da resposta: ${response.body}');
}
Para importar outros arquivos Dart dentro do seu próprio projeto/pacote, você usa caminhos relativos.
// Supondo que você tenha um arquivo 'utils.dart' na mesma pasta
// import 'utils.dart';
// Ou em uma subpasta 'src'
import 'src/utils.dart';
// Ou em uma pasta irmã
// import '../models/user.dart';
void main() {
// umaFuncaoDoUtils(); // Se 'utils.dart' definir essa função
}
as (Prefixos):
Se você importar duas bibliotecas que têm classes ou funções com o mesmo nome, ou se quiser tornar mais claro de onde um identificador vem, você pode usar um prefixo com a palavra-chave as.
import 'package:meu_pacote_legal/meu_pacote_legal.dart' as legal;
import 'package:outro_pacote_bacana/outro_pacote_bacana.dart' as bacana;
void main() {
var itemLegal = legal.Item();
var itemBacana = bacana.Item(); // Sem conflito de nome 'Item'
}
show (Mostrar Apenas Partes):
Se você só precisa de alguns identificadores de uma biblioteca grande, pode usar show para importar apenas eles. Isso pode ajudar a evitar poluir o namespace e, em alguns casos, melhorar a performance de compilação (especialmente para web com tree shaking).
import 'dart:math' show Random, pi; // Importa apenas Random e pi
void main() {
var gerador = Random();
print(pi * gerador.nextDouble());
// print(sqrt(4)); // Erro: sqrt não foi importado
}
hide (Esconder Partes):
O oposto de show. Importa tudo da biblioteca, exceto os identificadores especificados. Útil se houver um conflito de nome específico que você quer evitar.
// Suponha que lib1.dart e lib2.dart ambas definem uma classe Foo.
// import 'lib1.dart';
// import 'lib2.dart' hide Foo; // Esconde Foo de lib2.dart
// void main() {
// var f = Foo(); // Usará Foo de lib1.dart
// }
deferred as (Carregamento Adiado - Lazy Loading):
Usado para carregar uma biblioteca apenas quando ela é realmente necessária. Isso pode reduzir o tempo de inicialização do seu aplicativo, especialmente útil para aplicações web grandes. O código da biblioteca adiada só é carregado na primeira vez que você chama uma função ou acessa uma variável dessa biblioteca (após chamar um método loadLibrary() no prefixo).
import 'package:minha_lib_pesada/minha_lib_pesada.dart' deferred as pesada;
Future<void> carregarEUsarLibPesada() async {
print('Antes de carregar a lib pesada.');
await pesada.loadLibrary(); // Carrega a biblioteca
print('Lib pesada carregada.');
pesada.fazerAlgoPesado();
}
void main() {
print('Iniciando app...');
// A lib pesada ainda não foi carregada
carregarEUsarLibPesada(); // Eventualmente a carregará e usará
}
Em resumo, o Dart tem um ecossistema de pacotes maduro com pub e pub.dev, e um sistema de import flexível e poderoso para organizar seu código e utilizar bibliotecas externas e nativas.
Na sequência, proponho um pacote de exercícios. Siga o link abaixo!