DEV Community

Klaus Kazlauskas
Klaus Kazlauskas

Posted on • Edited on

14 4

Como criar uma biblioteca de componentes com Angular e Storybook

Se você já tentou criar uma biblioteca de componentes pro seu sistema, você com toda certeza já alterou um componente que quebrou várias páginas e quando te perguntaram quem foi...

Um fantoche de macaco olha de canto de olho pra tela, e depois olha pra frente como se não tivesse visto nada

Pra eliminar esse e outros problemas, como não saber se um componente existe, como funciona ou em que página você pode ver um exemplo dele funcionando; existe o Storybook.

Logo do Storybook

O Storybook se denomina como "Um explorador de componentes UI para desenvolvedores front-end". Isso quer dizer que ele serve para gerar várias histórias dos nossos componentes, assim como a documentação deles, para facilitar a exploração visual dos nossos componentes.

Vídeo de exemplo do Storybook

Então, vamos criar passo-a-passo essa biblioteca de componentes.


Preparação

Na época que esse guia foi preparado, foram usadas as seguintes tecnologias:

tecnologia versão instalação
Node.js 11.6.0 como instalar
NPM 6.13.4 Já vem com o Node.js
Angular CLI 8.3.21 como instalar

Todo o código desse projeto está no GitHub, então, caso você se perca em qualquer parte, pode fazer uma comparação direta:

GitHub logo klauskpm / angular-storybook

Repositório para ensinar a usar Storybook com Angular.

⚠️ Caso você já saiba gerar uma biblioteca, você pode pular para a sessão Instalando o Storybook ⚠️

Gerando o projeto

Usando o Angular CLI, vamos criar um projeto chamado angular-storybook e uma biblioteca chamada storybook-ui:

ng new angular-storybook

# dentro do projeto angular-storybook
ng g lib storybook-ui --prefix ui # versão curta de ng generate library
Enter fullscreen mode Exit fullscreen mode

Já temos o projeto para usar nossos componentes, e temos a biblioteca onde vamos desenvolver eles. A biblioteca já vem com um componente pronto, mas não vamos usar ele. Então, vamos até a pasta /projects/storybook-ui/src/lib/ e deletamos tudo de lá. Nessa mesma pasta vamos criar o módulo e componente simple-button.

# dentro da pasta /projects/storybook/src/lib

ng g m simple-button # versão curta de ng generate module

ng g c simple-button --export # versão curta de ng generate componente
Enter fullscreen mode Exit fullscreen mode

E vamos dar uma cara de botão para o nosso componente:

import { Component, Input } from '@angular/core';

@Component({
  selector: 'ui-simple-button',
  template: `
    <button>{{text}}</button>
  `,
  styles: [``]
})
export class SimpleButtonComponent {

  @Input() text = 'clique aqui';
}
Enter fullscreen mode Exit fullscreen mode

Agora, vamos no arquivo /projects/storybook/src/public_api.ts e substituir todo o conteúdo desse arquivo por:

export * from './lib/simple-button/simple-button.component';
export * from './lib/simple-button/simple-button.module';
Enter fullscreen mode Exit fullscreen mode

Para usar esse componente precisamos gerar o arquivo final da biblioteca:

ng b storybook-ui # versão curta de ng build
Enter fullscreen mode Exit fullscreen mode

Reescrever o /src/app/app.component.html:

Ola Mundo!
<ui-simple-button></ui-simple-button>
Enter fullscreen mode Exit fullscreen mode

E adicionar o SimpleButtonModule ao /src/app/app.module.ts:

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { SimpleButtonModule } from 'storybook-ui';

import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    SimpleButtonModule // modificado
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }
Enter fullscreen mode Exit fullscreen mode

Por último, vamos servir nossa aplicação e ver como ela está no http://localhost:4200 :

ng s # versão curta de ng serve angular-storybook
Enter fullscreen mode Exit fullscreen mode

Projeto de Angular rodando na porta 4200, com o texto

Pode comparar o seu progresso com a tag v1.2 do repositório


Instalando o Storybook

O Storybook tem um guia de como fazer a instalação em um projeto Angular e o jeito mais fácil é só usando uma única linha:

npx -p @storybook/cli sb init --type angular
Enter fullscreen mode Exit fullscreen mode

Executando essa linha no seu projeto, ele:

  • instala todas as dependências necessárias
  • adiciona os scripts storybook e build-storybook no seu package.json
  • cria os arquivos de configuração pro Storybook
  • cria as histórias de exemplo no seu projeto principal

Para ver o Storybook em ação, é só rodar o comando:

npm run storybook
Enter fullscreen mode Exit fullscreen mode

Página do Storybook rodando em localhost:6006, exibindo a história ˜with some emoji and action

Tudo bonito, tudo rodando. Mas, a configuração do Storybook está apenas pro seu projeto principal, e não para a sua biblioteca. Além disso, você sabe o que foi adicionado e para que? Então vamos voltar no tempo e seguir de forma manual.

Fazendo a instalação manualmente

1) Instale as dependências

npm install @storybook/angular babel-loader @babel/core --save-dev
Enter fullscreen mode Exit fullscreen mode

2) Adicione os scripts de npm

{
  "scripts": {
    "storybook": "start-storybook -p 6006",
    "build-storybook": "build-storybook"
  }
}
Enter fullscreen mode Exit fullscreen mode

O script storybook vai executar o start-storybook para exibir nossas histórias no http://localhost:6006. O build-storybook vai executar o build-storybook que vai gerar os arquivos estáticos do Storybook na pasta storybook-static.

Você pode definir o diretório final mudando o comando build-storybook por build-storybook -o /dist/storybook, colocando os arquivos estáticos no mesmo diretório que os builds gerados pelo seu projeto.

3) Crie o arquivo de configuração

É esse o arquivo que o Storybook vai usar para saber onde ele pode procurar as nossas histórias e como identificar os arquivos. No caso, vamos procurar arquivos com .stories.ts neles, dentro das pastas src e projects.

Crie o arquivo .storybook/config.js com o seguinte conteúdo:

import { configure } from '@storybook/angular';

configure([
  require.context('../src', true, /\.stories\.ts$/),
  require.context('../projects', true, /\.stories\.ts$/)
], module);
Enter fullscreen mode Exit fullscreen mode

4) Configure o Storybook para funcionar com TypeScript

Como o @storybook/angular usa o ForkTsCheckerWebpackPlugin, precisamos criar o arquivo .storybook/tsconfig.json:

{
  "extends": "../tsconfig.json",
  "exclude": [
    "../src/test.ts",
    "../src/**/*.spec.ts",
    "../projects/**/*.spec.ts"
  ],
  "include": [
    "../src/**/*",
    "../projects/**/*"
  ]
}
Enter fullscreen mode Exit fullscreen mode

5) Escreva sua história 🎉

Finalmente! Agora vamos criar nossa própria história e ver como ela se comporta.

Dentro da pasta do nosso componente simple-button, vamos criar o arquivo index.stories.ts com o conteúdo a seguir:

import { SimpleButtonComponent } from "./simple-button.component";

export default {
  title: 'UI | Button'
};

export const withDefaultValues = () => ({
  component: SimpleButtonComponent
});

export const withText = () => {

  return {
    component: SimpleButtonComponent,
    props: {
      text: 'Ola'
    }
  }
};
Enter fullscreen mode Exit fullscreen mode

Essa é uma das formas que podemos escrever as histórias. Ela é chamada de CSF (Component Story Format). Também temos a StoriesOf API e o MDX Syntax, que está por vir. Como o CSF é um adição nova no Storybook, boa parte dos exemplos da internet vão estar usando o StoriesOf API.

Dessa forma estamos falando que temos o componente Button, dentro do agrupador UI, com as histórias "With Default Values" e "With Text".

UI
└── Button
    ├── With Default Values
    ├── With Text

Enter fullscreen mode Exit fullscreen mode

6) Rode o projeto

Rode o projeto com o npm run storybook e veja o resultado final:

Alt Text

Pode comparar o seu progresso com a tag v1.3 do repositório

Próximos passos - addons

Agora que você aprendeu como configurar o Storybook e escrever uma história, você pode melhorar a qualidade das suas histórias com simples pluggins, chamados de addons.

Por exemplo, com o addon de actions você pode adicionar logs para ações, como clicks, e ouvir o que eles estão enviando. Com o addon de knobs você pode expor @Inputs do seu componente e altera-los na hora.

Pra não ficar só na explicação e sonhos, vamos montar ele agora. É muito fácil.

1) Instale as dependências

Além dos pacotes óbvios do knobs e do actions, precisamos também instalar o pacote do addons, que vai ser responsável por carregar os addons no Storybook.

npm install --save-dev @storybook/addons @storybook/addon-knobs @storybook/addon-actions
Enter fullscreen mode Exit fullscreen mode

2) Crie o arquivo de configuração dos addons

Crie o arquivo .storybook/addons.js com a seguinte configuração:

import '@storybook/addon-knobs/register';
import '@storybook/addon-actions/register';
Enter fullscreen mode Exit fullscreen mode

A ordem que você importa eles é importante. Ela vai dizer a ordem em que esses addons vão aparecer nos paineis

3) Aplique os addons na sua história

No nosso caso, vamos usar o knobs para expor o @Input text e o actions para exibir uma mensagem ao clicar no botão. Como vamos lidar com um evento e não uma propriedade, não podemos mais usar o component na história withText, pois o props só define propriedades e não eventos. Precisamos usar o template, mas para usarmos o template, precisamos definir o módulo com o componente SimpleButtonComponent.

No final das contas, o nosso index.stories.ts do SimpleButtonComponent vai ficar assim:

import { SimpleButtonComponent } from "./simple-button.component";
import { text, withKnobs } from '@storybook/addon-knobs';
import { moduleMetadata } from '@storybook/angular';
import { action } from '@storybook/addon-actions';

export default {
  title: 'UI | Button',
  decorators: [
    withKnobs,
    moduleMetadata({declarations: [SimpleButtonComponent]})
  ],
};

export const withDefaultValues = () => ({
  component: SimpleButtonComponent
});

export const withText = () => {
  return {
    template: `
        <ui-simple-button
          [text]="text"
          (click)="click($event)"
        ></ui-simple-button>
    `,
    props: {
      text: text('Text', 'Ola'),
      click: action('Clicou')
    }
  }
};
Enter fullscreen mode Exit fullscreen mode

E quando rodarmos o Storybook:
História
História

Pode comparar o seu progresso com a tag v1.4 do repositório


Conclusão

Agora, você sabe como...
✅ Instalar e configurar o Storybook
✅ Criar histórias para componentes
✅ Instalar e configurar addons

Você não vai ter mais problemas em relação ao que sua aplicação tem ou não tem, e o desenvolvimento vai seguir com mais confiança e agilidade, por poder testar as mudanças em diversos cenários.

Se você se interessou pelo Storybook e quer saber o que mais ele pode fazer, você pode começar a ver como...
Aprender o que compõe uma história
Exportar e deployar arquivos estáticos das histórias
Tematizar o Storybook
🎉 E muito mais


Se você ❤️ esse artigo, não deixe de me seguir e compartilhar com seus colegas. E se achar que tem algo para mudar no artigo, não deixe de comentar!

Te vejo na próxima! 😬

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more

Top comments (2)

Collapse
 
purigringo profile image
Anderson Christian

Valeu Klaus, ganhou um fã carioca!

Collapse
 
klauskpm profile image
Klaus Kazlauskas

Valeu mano 😬 !

nextjs tutorial video

📺 Youtube Tutorial Series

So you built a Next.js app, but you need a clear view of the entire operation flow to be able to identify performance bottlenecks before you launch. But how do you get started? Get the essentials on tracing for Next.js from @nikolovlazar in this video series 👀

Watch the Youtube series

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay