Construyendo una biblioteca de componentes con Styled Components

SL

Autor: Lee Robinson

Traducción: Sergio Lozano

June 12, 2020––– visitas

Lectura 7 min

Construyendo una biblioteca de componentes con Styled Components

No te repitas. Es un principio que todos los ingenieros se esfuerzan en seguir para — prevenir duplicar el código abstrayendo funcionalidades que se compartan entre sí.

En Hy-Vee, llegamos al punto en el que estábamos haciendo rotar nuevos equipos excesivamente rápido y necesitábamos mantener consistencia entre todos nuestros productos. ¿Cómo podríamos asegurarnos de que cada vez que una persona creará un botón, este fuese igual y funcionase de la misma forma en todos nuestros medios digitales?

Nuestro primer para abordar el problema fue hacer que el equipo de UI/UX definiera una guía de estilo que todos los consumidores deberían seguir e implementar. Necesitábamos dar un enfoque sencillo para asegurarnos de que la adaptación de los consumidores a nuestra guía de estilo y set de componentes compartidos pudiera usarse sin tener que preocuparse por el estilo.

Desarrollando un plan#

Decidimos construir una biblioteca UI de componentes reutilizables que se consumiría en todas nuestras aplicaciones de cara al cliente. En este proyecto había varios objetivos principales:

  1. Crear coherencia en toda la organización

    • Todas las propiedades digitales deben verse y sentirse iguales, implementando la guía de estilo acordada.
  2. Mejorar la calidad general del código base

    • Tener un grupo compartido de componentes UI significa menor cantidad de código propio por parte de los consumidores.
    • Asegurarnos de que todos los componentes cumplen con nuestros requisitos de accesibilidad.
    • Los componentes se vuelven más consistentes con múltiples equipos contribuyendo en la corrección de errores y mejoras.
  3. Aumentar las competencias de los desarrolladores

    • Los desarrolladores no especializados en CSS no tienen que preocuparse por las peculiaridades del CSS o los problemas de compatibilidad entre navegadores.
    • Nos permite lanzar nuevos productos y reescribir productos preexistentes más rápido.
    • Disminuye la cantidad de tiempo que los nuevos empleados tardan en construir de forma correcta las interfaces de usuario.

Para lograr estos objetivos, elegimos utilizar styled-components como la base de nuestra librería. styled-components utiliza plantillas de etiquetado ES6 y CSS que te permite escribir código CSS dentro de los componentes utilizando objetos de JavaScript. Styled-components se utiliza en empresas como Bloomberg, Atlassian, Reddit, Patreon, Target, Coinbase, y más. Existe una gran variedad de soluciones para CSS en JS, brevemente descritas aquí. Tras revisar este listado y leer la documentación de styled-components, parecía algo sencillo de implementar acorde con nuestro caso de uso. Algunos de nuestros grandes logros:

  • El parecido de escribir CSS tradicional en comparación a escribir objetos de JavaScript
  • Soporte para React y React Native
  • Pre-marcado automático en los estilos
  • Estilos directos que eliminan conflictos de CSS globales

Construyendo la biblioteca#

Vamos a utilizar un ejemplo sencillo: un botón.

const BaseButton = styled.button`
  border-radius: 4px;
  cursor: pointer;
  font-size: 1rem;
  padding: 8px 32px;
`;

Si te es familiar, es porque debería serlo. Se trata de CSS, puro, sin extras añadidos. Utilizando la plantilla en string, se invoca la función para el styled.button y este envía el CSS escrito. Este botón es extremadamente fácil de implementar (ver ejemplo debajo).

<BaseButton>{'Hello World!'}</BaseButton>

Una biblioteca de componentes no tiene un único tipo de botón, sin embargo, vamos a explorar cómo podemos extender el componente BaseButton.

const Button = styled(BaseButton)`
  background: #e21c11;
  border: none;
  color: #fff;

  :hover,
  :focus {
    background: #af0000;
  }
`;

Podemos utilizar el componente BaseButton dentro de styled para crear un botón con el color primario de nuestra marca.

Utilizando Propiedades#

Hacer extensiones de un componente base no es la única forma de modificarlo. Podemos añadir modificaciones condicionadas a las propiedades que se envían al componente. Vamos a probar añadiendo el estado disabled (deshabilitado) a nuestro componente Button.

${(props) => props.disabled && css`
    opacity: 0.25;
    cursor: not-allowed;
`}

Ahora, podemos pasar disabled como atributo cuando invocamos el componente.

<Button disabled>{'Hello World!'}</Button>

Utilizando JavaScript y React#

Podemos hacer muchas más cosas con los componentes.

Vamos a echar un vistazo a un ejemplo algo más complejo. Queremos construir un componente Input, pero abstrayendo las partes más complejas. Todos los componentes input deberían de tener un label (etiqueta), que referencie al <input> mediante una ID. También vamos a tener que asegurarnos de que el atributo aria-label se añade siempre por características de accesibilidad.

const Input = ({ disabled, id, label, placeholder, required }) => (
  <Container>
    <Label htmlFor={id} required={required}>
      {label}
    </Label>
    <Input
      aria-label={label}
      aria-required={required}
      disabled={disabled}
      id={id}
      placeholder={placeholder}
      type="text"
    />
  </Container>
);

En este momento, es mucho más fácil para nuestros desarrolladores construir formularios accesibles con un estilo correcto y unificado.

<Input
  disabled={false}
  id="first-name"
  label="First Name"
  placeholder="Please enter your name"
  required
/>

Pruebas#

Utilizamos Jest para pruebas con capturas de imágen. Este conjunto funciona especialmente bien con esta biblioteca porque es puramente visual. Las pruebas de imágen buscan las partes visuales (ej. Estilos CSS) se aplican de forma correcta.

Por cada permutación de un componente (ej. Diferentes atributos), realizamos una instantánea, de esta forma comprobamos que todas las condiciones se están probando y ejecutando de forma correcta. Para poder leer mejor el resultado de cada prueba utilizamos jest-styled-components. Para más información, lee Effective testing of styled-components with Jest Snapshots.

Las pruebas de imágen no cubren todos los escenarios, sin embargo, si añadiesemos el atributo onClick a un Button, sería mejor emplear métodos de creación de pruebas tradicionales, para asegurarnos de que todas las acciones se realizan de forma correcta.

Distribución#

Utilizando Babel y Webpack, podemos compilar y generar un dist que podemos publicar en NPM.

Gracias a babel-plugin-styled-components, podemos conseguir esto (y más) de forma gratuita:

  • Los nombres de las clases generadas son establecidas por el nombre de archivo del componente, estos es así para facilitar la experiencia de depuración (debug).
  • React Developer Tools muestra Button en vez de styled.button.

Aquí se encuentra nuestro archivo .babelrc.

.babelrc
{
    "presets": ["@babel/preset-env", "@babel/preset-react"],
    "plugins": ["babel-plugin-styled-components"]
}

Contribuir#

Queríamos facilitar al máximo el poder contribuir dentro de Hy-Vee. Por este motivo el formato y análisis de código y error se mantienen con:

Gracias a husky podemos realizar pre-commits hooks, asegurándonos de que todo el código tiene un formato correcto antes de subirlo a GitHub.

Integrando un Entorno de Desarrollo Integrado (IDE)#

Existen extensiones, que puedes añadir dentro de tu editor favorito, para mejorar la experiencia de escribir CSS dentro de JavaScript. ¡Todo gracias a, styled-components!🎉

Storybook#

Storybook nos proporciona un entorno interactivo para crear y mostrar nuestros componentes. Permite que el desarrollo sea pan comido y a su vez nos permite publicar nuestro Storybook en las páginas de GitHub, utilizando Storybook Deployer. De esta forma cualquiera puede ver los componentes y ver ejemplos de uso sin necesidad de adentrarse en escribir código.

Otra de las ventajas de utilizar Storybook son los add-ons. Another bonus feature of using Storybook are its add-ons. En el panel inferior puedes ver los que hemos decidido utilizar:

  • Story Source para mostrar ejemplos de uso del código.
  • Viewport que nos permite probar en diferentes dispositivos y tamaños de pantalla.
  • a11y para asegurarnos de que nuestros componentes son accesibles.
  • storybook-readme de esta forma la documentación se mantiene alrededor del componente.
  • addon-knobs permite editar los atributos y propiedades del componente de forma dinámica.

Storybook Example

Planes de futuro#

Estamos trabajando para que la librería se añada en todas las webs y aplicaciones de Hy-Vee.

A medida que hemos ido contruyendo esta librería, nos hemos llegado a plantear en profundidad nuestra estrategia y arquitectura de componentes. Estamos trabajando para definir qué conjunto de componentes tiene más sentido utilizar para que todos los consumidores los implementen y a su vez cuáles deberían ser sus propias implementaciones.

Todo esto nos inspira a implementar un Monorepo donde podemos de forma sencilla a desarrollar y publicar un gran número de paquetes.

¿Quieres saber más? Lee el siguiente post donde crearé un mono repositorio con Lerna y Yarn Workspaces.

Suscribete a mi newsletter

Recibe emails sobre desarrollo web, tecnología y acceso anticipado cada vez que publique un nuevo artículo.