Hoje no fluig abordamos um assunto bastante interessante, que é a criação e distribuição de componentes Angular. Criamos uma aplicação do 0 utilizando o @angular/cli, e com a ajuda do ng-packagr empacotamos nosso módulo para em seguida publicá-lo no NPM. Segue abaixo um pequeno passo-a-passo:
___
Instalando o @angular/cli
Primeiramente vamos instalar o @angular/cli globalmente (a versão mais recente, e utilizada neste tutorial foi a 1.7.4):
npm install -g @angular/cli
Gerando o código da aplicação
Com o @angular/cli já instalado, vamos gerar nossa aplicação de sandbox:
ng new meu-modulo-compartilhado
Pronto! Com este comando, criamos uma aplicação inteira com todo o processo de build já configurado e todas as dependências necessárias já instaladas. Vamos agora entrar no diretório criado e rodar a aplicação pra ver se está tudo certo:
cd meu-modulo-compartilhado/ npm start
Você verá uma mensagem dizendo que a aplicação foi compilada com sucesso, e está disponível na porta 4200. Vamos acessá-la então no navegador pelo endereço http://localhost:4200.
Show! Já podemos começar a criar nossos componentes que serão distribuídos!
___
Para este exemplo, eu vou criar um componente que é uma tabela de carros. Ela vai receber um array de objetos, e exibir cada objeto em uma linha da tabela.
Mas você pode criar o componente que você quiser, daí vai da sua criatividade/necessidade.
___
Gerando o código do componente
Vamos aproveitar que já temos o @angular/cli instalado, e utilizá-lo para gerar o módulo que irá comportar nosso componente compartilhado:
ng generate module modules/car-table
Se você reparou bem, eu criei meu módulo dentro de um diretório ‘modules’. Esta pasta será criada pelo @angular/cli, mas em si não é um módulo. É só uma pasta mesmo, que vai comportar nosso(s) módulo(s) compartilhado(s).
Então após executar este comando, nossa estrutura de pastas deve estar assim:
Vamos criar agora o componente em si:
ng generate component modules/car-table
E agora nossa estrutura de pastas deve estar assim:
Exportando nosso componente
Se você reparar na saída do comando anterior, o @angular/cli já atualizou nosso car-table.module.ts, com a declaração do componente criado. Aqui nós aproveitamos, e já exportamos o componente também, por meio do exports, logo abaixo do declarations, para que ele fique acessível no módulo que o importar.
... import { CarTableComponent } from './car-table.component'; @NgModule({ ... declarations: [CarTableComponent], exports: [CarTableComponent] }) export class CarTableModule { }
Como já estamos em uma aplicação Angular, vamos testar nosso módulo por aqui mesmo antes de distribuí-lo. Basta importar o módulo recém criado em seu app.module.ts:
... import { CarTableModule } from './modules/car-table/car-table.module'; @NgModule({ ... imports: [ ... CarTableModule ] export class AppModule { }
e alterar o app.component.html:
<app-car-table></app-car-table>
e voilá:
___
Código do nosso exemplo
Lembra que nosso exemplo é uma tabela de carros, que recebe um array de objetos? Vamos criar o código do nosso componente então:
car-table.component.ts:
... export class CarTableComponent { @Input() cars; }
car-table.component.html:
<table> <thead> <tr> <th>Marca</th> <th>Modelo</th> <th>Ano</th> </tr> </thead> <tbody> <tr *ngFor="let car of cars"> <td>{{ car.brand }}</td> <td>{{ car.model }}</td> <td>{{ car.year }}</td> </tr> </tbody> </table>
Tá. E aí, e os carros? Bom, a aplicação que for consumir nosso componente é que vai passar a lista de carros que ela quer exibir. Como já estamos em uma aplicação Angular, vamos passar alguns carros por aqui mesmo e testar, antes de distribuir o componente.
Vamos atualizar nosso app.component.html, adicionando a input property cars que recém colocamos no componente da tabela:
<app-car-table [cars]="myCars"></app-car-table>
E vamos declarar a varável myCars no app.component.ts:
... export class AppComponent { myCars = [ { brand: 'VW', model: 'Fusca', year: 1978 }, { brand: 'Ford', model: 'Belina', year: 1983 }, { brand: 'Chevrolet', model: 'Chevette', year: 1985 }, { brand: 'Fiat', model: 'Spazio', year: 1986 }, ]; }
Pronto! Nosso componente está pronto para ser consumido. Precisamos agora prepará-lo para ser distribuído.
NPM login
Você vai precisar criar uma conta no NPM caso ainda não tenha feito, e realizar o login no seu terminal:
npm login
package.json
A primeira coisa que vamos fazer é dar um nome ao nosso pacote. Para não ter problemas de colisão de nome, vamos dar um escopo à ele. No meu caso, o meu username no NPM é lucasvst, e o nome que eu quero dar pra esse pacote é car-table, então vai ficar @lucasvst/car-table.
Outra coisa a se fazer, é alterar nosso pacote para ser público, então vamos deixar nosso package.json assim:
{
“name”: “@lucasvst/car-table”,
…
“private”: false,
…
}
ng-packagr
Vamos utilizar o ng-packagr para empacotar nosso módulo. Se quiser saber mais dá uma olhada aqui, vale a pena. Vamos instalá-lo como uma dependência de desenvolvimento:
npm install --save-dev ng-packagr
Primeiro vamos criar na raiz do projeto o ng-package.json:
{
“$schema”: “./node_modules/ng-packagr/ng-package.schema.json”,
“lib”: {
“entryFile”: “./src/public_api.ts”
},
“whitelistedNonPeerDependencies”: [“.”]
}
Depois, dentro de /src, vamos criar o arquivo public_api.ts. Esse é o cara que vai expor todos os módulos que você quiser compartilhar:
export * from './app/modules/car-table/car-table.module';
E vamos inserir um script a mais em nosso package.json, para invocar o ng-packagr:
…
“scripts”: {
…
“packagr”: “./node_modules/.bin/ng-packagr -p ng-package.json”
}
Agora podemos chamar a tarefa de empacotamento pelo NPM:
npm run packagr
___
Se sua saída for parecida com a acima, parabéns!
Você acaba de criar um componente que já pode ser importado por outra aplicação Angular!
___
Deverá ter sido criado uma pasta dist/, e dentro dela alguns arquivos:
Entre na pasta dist/, e execute o seguinte comando:
npm publish --access public
___
Como este pacote tem um escopo, você precisa definir o acesso como public. Caso você tenha uma conta paga no NPM, você poderá também definir o acesso como restricted.
___
E se tudo ocorreu bem, seu pacote já estará disponível para ser baixado pelo NPM:
Pausa pro café
Vamos dar uma pausa aqui, e criar uma outra aplicação. Precisamos consumir nossa tabela de carros, em uma aplicação de verdade agora, fora da sandbox que criamos anteriormente.
Vou chamar essa aplicação de classificados-do-teles:
___
lembre-se, essa aplicação deverá ser criada fora da aplicação anteriormente criada. São 2 aplicações diferentes, portanto, se você ainda estiver com seu terminal na aplicação anterior, saia dela para executar o comando abaixo.
___
ng new classificados-do-teles
Com a aplicação gerada, a primeira coisa que vamos fazer é instalar nosso pacote recém publicado:
cd classificados-do-teles npm install --save @lucasvst/car-table
Para implementar nossa tabela de carros, o app.component.html deverá ter o mesmo conteúdo que o da aplicação anterior:
<app-car-table [cars]="myCars"></app-car-table>
Nosso app.component.ts, também será parecido, com a diferença que agora eu quero exibir outros carros:
... export class AppComponent { myCars = [ { brand: 'BMW', model: 'X5', year: 2004 }, { brand: 'Mercedes', model: 'CLASS ML', year: 2006 }, { brand: 'Mitsubishi', model: 'Lancer', year: 2008 }, { brand: 'Honda', model: 'Accord', year: 2012 }, ]; }
Feito isso, precisamos agora importar o módulo CarTableModule, do pacote @lucasvst/car-table em nosso app.module.ts
... import { CarTableModule } from '@lucasvst/car-table'; @NgModule({ ... imports: [ ... CarTableModule, ] }) export class AppModule { }
E olha quem apareceu de novo!
Compilou, passou!
É isso aí pessoal. Se você empacar em algum ponto, com algum erro, verifique o passo-a-passo novamente, verifique se as versões de dependências utilizadas neste artigo são as mesmas que você instalou, e caso tudo pareça bem, mas não funcione, pode me chamar!
Abraços e até a próxima!