Uso de Storybook y RSC para crear y probar aplicaciones de forma aislada

Con el lanzamiento de Storybook 8, Storybook ahora es compatible (experimentalmente) con los Componentes de Servidor React (RSC), entre otras novedades. La implementación de esta función se realiza exclusivamente en el lado del cliente, lo que significa que es compatible con todo el ecosistema de complementos e integraciones de Storybook.
En este artículo, analizaremos la compatibilidad de Storybook 8 con los RSC. También exploraremos las posibilidades que ofrece para el desarrollo y las pruebas basadas en componentes en este panorama cambiante.
Este artículo espera que comprendas el concepto de historias en Storybook. Si no es así, aquí tienes un breve resumen de cómo funcionan para que te pongas al día.
Por qué es importante la actualización de Storybook 8
Como aplicación cliente pura, Storybook solía gestionar compilaciones estáticas en HTML, CSS y JavaScript, ya que supone que los componentes se renderizan en el navegador. Sin embargo, dado que los RSC se renderizan exclusivamente en el servidor, la dinámica cambia por completo.
Explorando alternativas a Heroku para implementar aplicaciones Node.jsEntonces, ¿por qué es importante esta actualización? Primero, debemos comprender la dinámica entre la naturaleza centrada en el cliente de Storybook y los componentes renderizados en el servidor.
Este plantea contrastantes interrogantes sobre el desarrollo de componentes de forma aislada y su prueba en entornos de servidor. ¿Qué implicaciones tiene para los desarrolladores acostumbrados a trabajar con componentes renderizados por navegador? Analicémoslo.
La naturaleza de los componentes del servidor React.
Los RSC representan una evolución significativa en las capacidades de renderizado de React. Puedes consultar esta guía completa sobre RSC o ver mi breve resumen de los puntos relevantes a continuación.
A diferencia de los componentes React tradicionales, que se renderizan completamente en el lado del cliente, los RSC permiten que ciertos componentes se rendericen en el servidor. Esto significa que, cuando un usuario solicita una página, el HTML inicial se renderiza en el servidor y luego se envía al cliente, mejorando así el tiempo hasta el primer byte (TTFB) y el rendimiento percibido.
Usando Mountaineer para desarrollar una aplicación React con PythonAl renderizar previamente los componentes en el servidor, los RSC pueden reducir significativamente el tiempo de interactividad de una página porque el servidor envía un documento HTML ya generado.
En otras palabras, cuando el cliente recibe el documento HTML, puede renderizar la página más rápido porque no tiene que esperar a que se ejecute JavaScript para generar el contenido. El único inconveniente potencial es la latencia de la red, o cuando la respuesta del servidor tarda mucho en llegar al cliente debido a problemas de red.
Con los RSC, los usuarios experimentan tiempos de carga más rápidos e interacciones más fluidas, lo que resulta en una experiencia de usuario más atractiva. Los componentes de servidor React ofrecen una solución potente para mejorar el rendimiento, el SEO, la accesibilidad y la experiencia del usuario en general.
Desafíos en la integración de Storybook con RSC
Al crear un componente del lado del cliente, como Button
con Storybook, se crea un entorno de pruebas donde se puede visualizar e interactuar con él en diversos estados y configuraciones. Su funcionamiento habitual es el siguiente:
- Aislamiento: Aísle el
Button
componente del resto de la aplicación para que no dependa de ningún otro componente o servicio. Puede visualizar y probar elButton
componente de forma aislada, lo que facilita centrarse en su diseño y comportamiento sin interferencias de otras partes de la aplicación. - Variantes y estados: Puede crear historias para diferentes variantes y estados del
Button
componente. Por ejemplo, puede tener historias para un botón principal, un botón secundario, un botón desactivado, un botón con un icono, etc. Cada historia representa una configuración o estado diferente delButton
componente, lo que le permite probar su comportamiento en diversas condiciones. - Pruebas interactivas: Storybook ofrece un entorno interactivo donde puedes interactuar con el
Button
componente y ver cómo responde a las interacciones del usuario, como clics, desplazamientos y eventos del teclado. Esto te permite probar exhaustivamente la funcionalidad delButton
componente y asegurar su correcto funcionamiento en diferentes escenarios.
Los RSC, por otro lado, suelen depender de datos dinámicos o del contexto proporcionado por el servidor durante la renderización. A diferencia de los componentes cliente, pueden requerir recursos del servidor para una renderización correcta. A continuación, explico a qué me refiero.
Supongamos que estamos creando la página de inicio de un blog con varias funciones. Por ejemplo, necesitamos mostrar una lista de blogs. Esto significa que la página de inicio puede tener diferentes estados (como cargando, error, vacío y predeterminado) según la respuesta de la API.
Storybook, al estar diseñado principalmente para la representación estática de componentes, puede tener dificultades para gestionar la naturaleza dinámica de los RSC. Esta limitación dificulta la representación precisa del comportamiento de los RSC en el entorno de Storybook.
Pero con Storybook 8, ahora puedes crear, probar y documentar aplicaciones de servidor Next.js de forma aislada. Ten en cuenta que aquí se especificó Next.js: Storybook 8 solo ofrece compatibilidad con componentes de servidor React para Next.js, por lo que se considera experimental por ahora.
Cómo integrar WunderGraph con su aplicación frontendAprovechar Storybook con RSC en Next.js
Vamos a crear una página de demostración para un sitio web de comercio electrónico donde simplemente listamos los diferentes productos que ofrece la tienda. Simulamos estos diferentes estados en Storybook:
- Predeterminado: cómo se ve la página cuando se enumeran todos los elementos
- Cargando: Cómo se ve la página cuando se obtienen los elementos
- Vacío: cómo se ve la página cuando no hay elementos para mostrar
- Error: Cómo se ve la página cuando hay un error al recuperar elementos
Tenga en cuenta que esta página se procesa en el servidor, por lo que utilizaremos el soporte experimental de Storybook para RSC junto con el complemento Mock Service Worker (MSW) de Storybook para simular aplicaciones REST o GraphQL dentro de nuestra historia.
Comenzaremos configurando Storybook en un proyecto Next.js para que funcione con RSC. Después, crearemos historias para la página de la tienda en diferentes estados. ¡Aquí tienes el repositorio del proyecto para que puedas seguirlo fácilmente!
Primero, instala Storybook en tu proyecto Next.js:
libro de cuentos npx@next init
Configurar el archivo de Storybook para apuntar a las nuevas historias y habilitar la función experimental RSC:main.ts
// main.tsconst config : StorybookConfig = { historias : [ '../app/**/*.stories.tsx' ], características : { experimentalRSC : verdadero } }
Tendremos dos componentes en nuestro proyecto: un Product
componente único y un Products
componente que enumera todos los productos de nuestra tienda.
Aquí está el código del Product
componente:
// producto.tsx importa { FC } de 'react'; exportar interfaz ProductProps { id : cadena ; título: cadena; precio : cadena ; descripción: cadena; } exportar const Producto : FC ProductProps = ({ id , título , precio , descripción , }) = { return ( div className = 'border min-w-[200px] max-w-[200px] p-4 rounded-lg flex flex-col gap-2' p { título }/ pp { precio }/ pp { descripción }/ p / div ); };
Y así es como Product
se ve un componente de ejemplo:
Aquí está el código del Products
componente:
importar { FC } de "react" importar { Producto , ProductProps } de "./product" exportar const Productos : FC { productos : Array ProductProps } = ({ productos }) = { return ( div className = "flex gap-2 flex-wrap" { productos . length 0 ? ( productos . map (( artículo , índice ) = ( Clave de producto = { artículo . título + índice } {... artículo } / )) ): ( p ¡ Ups ! Parece que estamos todos agotados / p ) } / div ) }
Y así es como Products
se ve el componente:
A continuación, traeremos el Products
componente a nuestro HomePage
, que es un componente de servidor que se encarga de obtener datos de nuestra API y pasarlos al Products
componente:
importar { Productos } de "@/components/products" ; importar fetchData de "@/lib/fetch-data"; exportar función asíncrona predeterminada Inicio () { const productos = await fetchData () return ( main className = "flex flex-col gap-6 min-h-screen p-8" h1 className = "text-3xl font-bold" Listado de productos / h1 Productos productos ={ productos } // main ); }
La lista de productos resultantes debería verse así cuando se representen todos los productos:
Así es como fetchData
se ve la función:
importar { caché } desde 'react' const fetchData = caché ( async() = { const res = await fetch ( "https://fakestoreapi.com/products" , { next : { revalidate : 10 } } ) if (res . status !== 200 ) { lanzar nuevo Error (`Estado $ { res . status }`) } const productos = await res . json () devolver productos }); exportar predeterminado fetchData ;
Tenga en cuenta que estamos utilizando una API de productos gratuitos de FakeStore API.
Escribe historias para los componentes de la página de inicio.
A continuación, crearemos historias para el componente de la página de inicio que simulan los diferentes estados: predeterminado, error, cargando y vacío. Empecemos simulando el estado predeterminado de la página de inicio.
Dado que obtenemos datos de una API de red, simularemos sus solicitudes con MSW. Cree una historia con datos simulados para la página de inicio:
// app/homepage/page.stories.tsx importa tipo { Meta , StoryObj } de '@storybook/react'; importar Inicio desde './page' ; const Wrapper = ({ productCount }: { productCount : número }) = ( Inicio / ) const meta : Meta = { título : 'app/HomePage' , componente : Wrapper , }; exportar meta predeterminada; tipo Historia = StoryObj tipo de meta; export const APIMocked = { parámetros : { msw : { controladores : [ http . get ( 'https://api.example.com/products' , () = { return HttpResponse . json ([{ id : "1" , precio : "10" , título : "Botas Maison Margiela" , descripción : "Botas de gamuza negras" }]); }), ], }, }, };
Este es solo un ejemplo para mostrar cómo manejarías la obtención de datos de una API y la escritura de una historia que representa el estado de la página en ese momento (en este caso, mientras se obtiene una lista de productos).
Si quisiéramos más productos, podríamos simplemente agregarlos a la lista, pero codificar respuestas de API como esto es tedioso. Por lo tanto, podemos generar los datos nosotros mismos creando una base de datos en memoria simplificada con la biblioteca de fábrica de datos de MSW.
Desde esta biblioteca, podemos leer datos y generar la respuesta de red deseada. Posteriormente, podemos escribir historias para alimentar la base de datos con casos de prueba.
Simulación de datos con Mock Service Worker
Veamos cómo usar MSW en Storybook para simular solicitudes de obtención de productos. Primero, instale el complemento MSW Storybook e inicialícelo:
npm i msw msw - storybook - complemento@2.0.0 -- canario.122.06f0c92.0 - D npx msw init público /
Tenga en cuenta que, aunque MSW tiene problemas de compatibilidad con los aspectos del lado del servidor del nuevo directorio de aplicaciones de Next.js, funciona perfectamente cuando lo usamos en el navegador.
Esto se debe a que Storybook opera completamente del lado del cliente, por lo que puede usar MSW para simular aplicaciones de red sin problemas. Podemos probar componentes de la interfaz de usuario e interacciones de red de manera efectiva en Storybook sin preocuparnos por problemas de compatibilidad.
A continuación, necesitamos inicializar MSW con la onUnhandledRequest
opción en :.storybook/preview.tsx
// .storybook/preview.tsximportar { inicializar , mswLoader } desde 'msw-storybook-addon' ; inicializar ({onUnhandledRequest: 'anunciar' }); vista previa const = { cargadores : [ mswLoader ], }
Escribiendo historias con fábricas de datos de RSU
A continuación, construimos una base de datos en memoria con la biblioteca de fábrica de datos de MSW. Cree controladores de MSW que lean de la base de datos y generen respuestas de red:
// data.mock.tsimport { faker } de '@faker-js/faker';import { drop, factory, primaryKey } de '@mswjs/data';let _id = 1;const db = factory({ producto: { id: primaryKey(() = _id++), título: faker.commerce.productName, precio: () = faker.commerce.price({ mín.: 100, máx.: 200, dec.: 0, símbolo: '$' }), descripción: faker.commerce.productDescription }});export const reset = () = drop(db);export const generateProducts = (count: number): number[] = { return Array.from({ length: count }, (_, i) = i); };export const createProduct = (producto = {}) = db.product.create(producto);export const getProducts = () = { const productos = db.product.getAll(); return productos;};
Luego, actualice el .storybook/preview.tsx
archivo para usar los controladores MSW para leer desde la base de datos:
// .storybook/preview.tsximport tipo { Vista previa } de "@storybook/react"; importar { inicializar, mswLoader } de 'msw-storybook-addon'; importar "../src/app/globals.css" importar { http, HttpResponse } de 'msw' importar { obtenerProductos } de "../src/lib/mock" inicializar ({ onUnhandledRequest: 'warn' }); vista previa constante: Vista previa = { parámetros: { msw: { controladores: [ http.get('https://fakestoreapi.com/products', () = { productos constantes = getProducts(); devolver HttpResponse.json(productos); }) ] }, }, cargadores: [mswLoader]}; exportar vista previa predeterminada;
Con esta configuración, Storybook utilizará MSW para simular las respuestas de la API, utilizando la base de datos en memoria para proporcionar datos de prueba realistas para sus componentes.
Ahora que hemos terminado con nuestra configuración, podemos continuar y simular tantos datos como queramos, utilizando las funciones que creamos y probar diferentes estados de nuestra aplicación:
// app/homepage/page.stories.tsximport tipo { Meta, StoryObj } de '@storybook/react';importar { createProduct, generateProducts, reset } de '../../../lib/data.mock';importar Home de './page';const meta: Meta = { title: 'app/HomePage', component: HomePage,};exportar meta predeterminado;tipo Story = StoryObjtypeof meta;exportar const Predeterminado: Story = { args: { productCount: 30, }, cargadores: [({ args: { productCount } }) = { reset(); generateProducts(productCount).map(() = createPost()) }],};exportar const Error = { render: () = ErrorPage /};exportar const Vacío: Story = { cargadores: [ () = { reset() } ],};
Ahora, dependiendo del estado de la página, lo que ves en laListado de productosLa página cambiará. Así Empty
debería verse el estado que simulamos:
Conclusión
La compatibilidad experimental de Storybook 8 con RSC en Next.js permite a los desarrolladores crear historias para RSC y aprovechar al máximo el amplio ecosistema de complementos de Storybook. Los RSC ofrecen un rendimiento y una experiencia de usuario mejorada al renderizar componentes en el servidor.
Si bien la integración de Storybook con RSC presenta desafíos, la nueva versión permite construir, probar y documentar componentes de servidor de forma aislada, como hemos demostrado. ¡Diviértete experimentando con esta función! ¡Saludos!
Si quieres conocer otros artículos parecidos a Uso de Storybook y RSC para crear y probar aplicaciones de forma aislada puedes visitar la categoría Aplicaciones.
Entradas Relacionadas