Parte 1: Criando Bibliotecas Angular
Compartilhando seus Tesouros com o Universo
No mundo do desenvolvimento de software, a reutilização de código é uma prática fundamental que não só economiza tempo como também assegura consistência e qualidade em múltiplos projetos. No contexto do Angular, a criação de bibliotecas é uma estratégia poderosa para alcançar esses objetivos. Se você se depara com a necessidade de resolver o mesmo problema em mais de uma aplicação ou deseja compartilhar sua solução com outros desenvolvedores, provavelmente tem um candidato a biblioteca em suas mãos.
Considere um exemplo simples: um botão que leva os usuários ao site da sua empresa. Essa funcionalidade pode ser incluída em todas as aplicações que sua empresa desenvolve. Nesse caso, encapsular essa funcionalidade em uma biblioteca Angular permite que você a reutilize facilmente em diferentes projetos, mantendo a consistência e reduzindo o esforço de desenvolvimento.
Nesta série de artigos, embarcaremos em uma jornada para explorar a criação de bibliotecas Angular, desde os primeiros passos até a publicação e o gerenciamento de versões.
Começando a Jornada: Criando sua Primeira Biblioteca
O Angular CLI, seu fiel companheiro nesta aventura, torna a criação de bibliotecas uma tarefa simples e intuitiva. Com apenas alguns comandos, você pode gerar a estrutura básica de uma biblioteca e começar a desenvolver seus componentes, serviços e outros recursos reutilizáveis.
Criando um Workspace e uma Biblioteca
- Crie um workspace sem aplicação: Utilize o comando
ng new
com a opção--create-application=false
para criar um workspace vazio, sem uma aplicação inicial.
ng new meu-workspace --create-application=false
2. Navegue até o workspace: Acesse o diretório do workspace recém-criado.
cd meu-workspace
3. Gere a biblioteca: Utilize o comando ng generate library
para criar a estrutura básica da sua biblioteca.
ng generate library minha-lib
Nomeando sua Biblioteca
Ao escolher o nome da sua biblioteca, especialmente se planeja publicá-la em um registro público de pacotes como o npm, é importante ter cuidado. Evite usar um nome prefixado com ng-
, como ng-library
, pois o prefixo ng-
é uma palavra-chave reservada usada pelo Angular framework e suas bibliotecas. O prefixo ngx-
é preferido como uma convenção que denota que a biblioteca é adequada para uso com Angular. Além disso, essa convenção ajuda a diferenciar entre bibliotecas de diferentes frameworks JavaScript.
Explorando a Estrutura da Biblioteca
O comando ng generate library
cria a pasta projects/minha-lib
no seu workspace, contendo um componente e um serviço dentro de um NgModule. Essa estrutura básica fornece um ponto de partida para você começar a desenvolver sua biblioteca.
Ao gerar uma nova biblioteca, o arquivo de configuração do workspace, angular.json
, é atualizado com um projeto do tipo biblioteca.
"projects": {
…
"minha-lib": {
"root": "projects/minha-lib",
"sourceRoot": "projects/minha-lib/src",
"projectType": "library",
"prefix": "lib",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:ng-packagr",
…
Construindo, Testando e Lintando
O Angular CLI oferece comandos para construir, testar e aplicar lint em sua biblioteca:
ng build minha-lib --configuration development
ng test minha-lib
ng lint minha-lib
Observe que o construtor configurado para o projeto de biblioteca é diferente do construtor padrão para projetos de aplicação. Esse construtor garante que a biblioteca seja sempre construída com o compilador AOT, entre outras otimizações.
Definindo a API Pública: A Porta de Entrada para sua Biblioteca
Para que sua biblioteca seja reutilizável, você precisa definir uma API pública, que especifica quais componentes, serviços e outros elementos estarão disponíveis para os usuários da sua biblioteca. Essa API pública é definida no arquivo public-api.ts
dentro da pasta da sua biblioteca.
// projects/minha-lib/src/public-api.ts
export * from './lib/minha-lib.module'; // Exporta o NgModule da biblioteca
export * from './lib/meu-componente/meu-componente.component'; // Exporta um componente
export * from './lib/meu-servico.service'; // Exporta um serviço
Qualquer elemento exportado nesse arquivo se torna público quando sua biblioteca é importada em uma aplicação. Utilize um NgModule
para expor serviços e componentes de forma organizada.
Refatorando Partes de uma Aplicação em uma Biblioteca: Transformando sua Nave em Módulos Reutilizáveis
No universo do desenvolvimento Angular, a capacidade de refatorar partes de uma aplicação em bibliotecas reutilizáveis é uma habilidade valiosa. Imagine que sua nave espacial Angular possui módulos especializados que poderiam ser úteis em outras missões. A refatoração permite que você extraia esses módulos, transformando-os em bibliotecas independentes que podem ser compartilhadas e reutilizadas em diferentes projetos.
O Processo de Refatoração: Desacoplando e Adaptando
Para tornar sua solução reutilizável, você precisa ajustá-la para que não dependa de código específico da aplicação original. Aqui estão alguns pontos a considerar ao migrar funcionalidades de uma aplicação para uma biblioteca:
1. Design de Componentes e Pipes:
Componentes e pipes devem ser projetados para serem sem estado (stateless). Isso significa que eles não devem depender de variáveis externas ou alterá-las. Se você identificar alguma dependência de estado, é crucial avaliar se esse estado pertence à aplicação ou se a biblioteca deveria gerenciá-lo.
2. Gerenciamento de Observables:
Observables aos quais os componentes se inscrevem internamente devem ser gerenciados adequadamente, garantindo que sejam limpos e descartados durante o ciclo de vida desses componentes. Isso evita vazamentos de memória e garante que o aplicativo funcione corretamente em diferentes contextos.
3. Interações através de Inputs e Outputs:
Componentes devem expor suas interações usando inputs para fornecer contexto e outputs para comunicar eventos a outros componentes. Isso assegura que a comunicação entre componentes seja clara e bem definida.
4. Verificação de Dependências Internas:
- Classes e Interfaces Personalizadas: Verifique se as classes ou interfaces personalizadas usadas em componentes ou serviços dependem de classes ou interfaces adicionais que também precisam ser migradas para a biblioteca.
- Dependência de Serviços: Se o código da sua biblioteca depender de um serviço, esse serviço precisa ser incluído na biblioteca.
- Dependências de Outras Bibliotecas: Se o seu código ou seus templates dependem de outras bibliotecas (como Angular Material), você deve configurar sua biblioteca com essas dependências para garantir que funcionem corretamente.
5. Fornecimento de Serviços:
- Providers de Serviços: Serviços devem declarar seus próprios providers, em vez de declarar providers no
NgModule
ou em um componente. Isso torna o serviço tree-shakable, permitindo que o compilador deixe o serviço fora do bundle se ele nunca for injetado na aplicação que importa a biblioteca. Para mais informações, veja Tree-shakable providers. - Design Patterns
forRoot()
eforChild()
: Se você registrar providers de serviços globais ou compartilhar providers entre váriosNgModules
, utilize os padrões de designforRoot()
eforChild()
fornecidos peloRouterModule
. - Tokens Leves para Serviços Opcionais: Se sua biblioteca fornece serviços opcionais que podem não ser usados por todas as aplicações cliente, suporte ao tree-shaking adequado para esse caso, usando o padrão de design de tokens leves (lightweight token design pattern).
Construindo uma Frota Estelar Modular e Eficiente
A refatoração de partes de uma aplicação em bibliotecas reutilizáveis é uma etapa crucial na construção de uma frota estelar Angular modular e eficiente. Ao desacoplar funcionalidades e criar bibliotecas independentes, você promove a reutilização de código, a organização do projeto e a escalabilidade da sua aplicação.
No próximo artigo, exploraremos como integrar sua biblioteca ao Angular CLI usando Schematics de geração de código, facilitando a criação de componentes e outros elementos da sua biblioteca diretamente no projeto do usuário.