Documentando componentes Angular: Storybook

Compartir esta publicación

Share on facebook
Share on linkedin
Share on twitter
Share on email

Como desarrolladores, en nuestro trabajo diario nos gusta encontrar una buena documentación de las librerías y tecnologías que utilizamos. Es, por tanto, nuestra responsabilidad dejar bien documentado nuestro trabajo. Los que vengan detrás nuestro a utilizarlo y/o continuarlo lo van a agradecer. Y en Apiumhub somos muy fans de documentar nuestros proyectos.

Existen muchas herramientas que nos permiten escribir documentación en formato Markdown (.md), y algunas otras que, además, nos permiten documentar nuestros componentes de UI. La mayoría de ellas están escritas y enfocadas para React. Qué pasa entonces si queremos documentar los componentes de nuestro proyecto Angular?

Una de las herramientas más populares para documentar nuestros componentes UI es Storybook. Es una herramienta a priori ideal para crear nuestra librería de UI de forma independiente y reutilizable. Además es de las pocas que nos permiten interacción con los componentes. Y aunque sus creadores aseguran que está enfocada a múltiples frameworks que siguen una arquitectura basada en componentes (Component Driven Architecture), en los que se incluye Angular, lo cierto es que al estar basado en JSX, usar Stories de componentes Angular en archivos .mdx (el formato que combina Markdown y JSX) no es tan sencillo como aseguran, algunas características no funcionan, la propia documentación de Storybook para Angular tiene incluso algunos ejemplos escritos en React y, si hacemos una rápida consulta por la red, nos daremos cuenta que muchos desarrolladores Angular se encuentran con problemas comunes: confusión y falta de soluciones.

Usando Storybook

Vamos a intentar mostrar algunos ejemplos que pueden ayudarnos a entender cómo funciona:

Instalamos Storybook desde el root de nuestro proyecto Angular con el comando:

npx sb init

Si todo ha ido bien, el comando npm run storybook debería arrancar nuestro Storybook. También veremos que se ha creado una carpeta .storybook en la raíz del proyecto con varios archivos de configuración dentro. La versión de Storybook utilizada en el momento de escribir este artículo es la v6.4.9. Esta versión ya instala y configura automáticamente Compodocs, una herramienta que analiza nuestro proyecto y genera una documentación automática que luego podremos adaptar y utilizar. Esto que no ocurría en versiones anteriores y lo teníamos que hacer a mano.

Una Story es la captura de un estado de un componente. Esto significa que crearemos tantas stories como estados de un componente queramos mostrar. Storybook ya nos prové de algunos ejemplos una vez lo instalamos. Trabajaremos sobre el ejemplo de botón primario:

import { Story, Meta } from '@storybook/angular/types-6-0';
import Button from './button.component';

export default {
 title: 'Components/UI/CSF Stories',
 component: Button,
 argTypes: {
   backgroundColor: { control: 'color' },
 },
} as Meta;

const Template: Story<Button> = (args: Button) => ({
 props: args,
});

export const Primary = Template.bind({});
Primary.args = {
 primary: true,
 label: 'Button',
};

Primary sería nuestra primera Story y se mostrará en el menú izquierdo bajo la ruta indicada en el parámetro title. La pestaña Canvas nos muestra el componente en el estado indicado y en la pestaña Docs, las diferentes propiedades, editables en tiempo real para cambiar el estado actual. Algo interesante es que nos muestra el código para usar el componente en el estado actual.

Ahora vamos con lo interesante: podemos escribir código Markdown en formato MDX e incrustar las stories en el momento que nos convenga. Tenemos 2 maneras de hacerlo:

  • Crear las Stories previamente en el formato CSF (Component Story Format) como hemos visto antes y luego crear los archivos MDX que llamarán a cada Story cuando nos convenga. Si escribimos los Markdown de esta forma, tendremos en el menú izquierdo los CSF por un lado y los MDX por otro.
import { Meta, Story } from '@storybook/addon-docs';

<Meta title="Components/UI/Embedded stories" />

# Embedded Stories

Lorem ipsum

## Primary button
<Story id='components-ui-csf-stories--primary'></Story>

El id lo encontramos en la url de cada story.

  • Una forma mucho más elegante y poderosa es escribir las Stories directamente en los MDX. De esta forma tendremos un item de menú con el título que indiquemos y, bajo él en forma de submenús, todas las stories que hayamos creado dentro, con el componente con sus opciones bajo la pestaña Canvas. Bajo la pestaña Docs tendremos el contenido del MDX, que será navegable a través del menú. Pura elegancia.
import { Meta, Story, ArgsTable } from '@storybook/addon-docs';
import Button from './button.component';

<Meta title="Components/UI/MDX Stories" component={Button} />

export const Template = (args) => ({ props: args });

# MDX Stories

Lorem ipsum

## Primary button

<Canvas>
 <Story
   name="Primary"
   args={{
     primary: true,
     label: 'Button',
   }}>
   {Template.bind({})}
 </Story>
 <ArgsTable story='Primary' />
</Canvas>

ArgsTable nos sirve para mostrar el cuadro de argumentos que nos permite cambiar el estado del componente y ver el código para usar el componente.

Pero qué tal si vemos ahora un último caso un poco más complejo? Imaginemos que tenemos un componente que implementa un ControlValueAccessor y vamos a necesitar crear un contexto donde necesitamos un wrapper en forma de FormGroup. El componente en cuestión es el clásico switch button, con un parámetro label y un valor controlado por un formControlName. La Story podría ser algo así:

import {moduleMetadata} from "@storybook/angular";
import {FormBuilder, FormControl, FormsModule, ReactiveFormsModule} from "@angular/forms";
import {Story} from "@storybook/angular/types-6-0";
import {SwitchComponent} from "./switch.component";

export default {
 title: 'Switch',
 component: SwitchComponent,
 decorators: [
   moduleMetadata({
     declarations: [SwitchComponent],
     imports: [FormsModule, ReactiveFormsModule],
   })
 ]
};

export const SwitchStory: Story = () => {
 let formGroup = new FormBuilder().group({
   agree: new FormControl()
 });
 const label = 'Switch label';

 return {
   template: `<form [formGroup]="group">
               <switch [label]="label" [formControlName]="controlName"></switch>
              </form>`,
   props: {
     group: formGroup,
     controlName: 'agree',
     label
   }
 }
}

Necesitamos el ModuleMetadata de la librería de @storybook/angular para definir los componentes y módulos que necesitaremos. Una vez tenemos los módulos importados, dentro de la story preparamos el contexto que necesitamos. En nuestro caso, creamos el FormGroup mediante el FormBuilder. Y en el apartado props de la story definiremos las variables que le hemos pasado a nuestro componente y a su wrapper en la propiedad template. Y con esto tenemos nuestro ControlValueAccessor listo para que pueda cambiar de estado.

Para estos ejemplos hemos intentado crear escenarios lo más simples posibles, usando solamente el core de Storybook y omitiendo el uso de addons, pero obviamente éstos pueden ser una herramienta muy poderosa. Los Addons son plugins creados y mantenidos por la comunidad que nos permiten complementar nuestras stories con herramientas de todo tipo, desde decoradores hasta entornos de test. Para profundizar más con el tema de addons, entra aquí.

Como hemos visto, documentando nuestros componentes UI de esta forma y con la posibilidad de complementar con archivos Markdown, con un poco de cariño y dedicación podemos llegar a tener un proyecto de documentación sencillo de usar y muy vistoso, sin necesidad de complejas configuraciones y teniendo los archivos junto a los propios componentes, todo en el mismo proyecto.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Suscríbete a nuestro boletín de noticias

Recibe actualizaciones de los últimos descubrimientos tecnológicos

Acerca de Apiumhub

Apiumhub reúne a una comunidad de desarrolladores y arquitectos de software para ayudarte a transformar tu idea en un producto potente y escalable. Nuestro Tech Hub se especializa en Arquitectura de Software, Desarrollo Web & Desarrollo de Aplicaciones Móviles. Aquí compartimos con usted consejos de la industria & mejores prácticas, basadas en nuestra experiencia.

Posts populares
Descarga Grow Professionally: Inside Apiumhub's Dev Team

¿Estás orientado a Datos?

Construyamos tu éxito juntos.

Contáctanos

¿Tienes un proyecto desafiante?

Podemos trabajar juntos