<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Altaskur</title>
    <description>The latest articles on Forem by Altaskur (@altaskur).</description>
    <link>https://forem.com/altaskur</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1265234%2Fbc06825e-25ca-4bd9-b991-e7bd172c23ae.png</url>
      <title>Forem: Altaskur</title>
      <link>https://forem.com/altaskur</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/altaskur"/>
    <language>en</language>
    <item>
      <title>¿Por dónde empezarías un proyecto? No, no es solo por la lógica</title>
      <dc:creator>Altaskur</dc:creator>
      <pubDate>Mon, 28 Jul 2025 22:20:55 +0000</pubDate>
      <link>https://forem.com/altaskur/por-donde-empezarias-un-proyecto-no-no-es-solo-por-la-logica-1dao</link>
      <guid>https://forem.com/altaskur/por-donde-empezarias-un-proyecto-no-no-es-solo-por-la-logica-1dao</guid>
      <description>&lt;p&gt;Hace unos días lancé una pregunta básica en un directo de Twitch: ¿Por dónde empezarías un proyecto? Me sorprendió la variedad de respuestas, así que decidí llevar la discusión a mis redes sociales para analizarla más a fondo.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Me llevé una amarga sorpresa: prácticamente había unanimidad, y esto no suele ser una buena señal.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Los resultados fueron bastante sorprendentes. De hecho, la mayoría de las respuestas coincidieron en algo que, para mí, fue una alarma.&lt;/p&gt;

&lt;p&gt;✋  Ojo: esto no se trata de decirte que estás haciendo las cosas mal, sino de promover y defender la variedad de ideas y enfoques. Abrir la mente a otras formas de empezar un proyecto es una forma de enriquecer nuestro background y crecer profesionalmente.&lt;/p&gt;

&lt;p&gt;En nuestro sector, nada está escrito en piedra y no hay verdades absolutas, así que ver que no hay confrontación de ideas no es precisamente buena señal.&lt;/p&gt;

&lt;p&gt;Vamos a ver cómo se distribuyen las respuestas:&lt;/p&gt;

&lt;h2&gt;
  
  
  Análisis de la encuesta
&lt;/h2&gt;

&lt;p&gt;La pregunta era sencilla: ¿por dónde empezarías un proyecto? Las respuestas:&lt;/p&gt;

&lt;p&gt;A) Diseño&lt;br&gt;&lt;br&gt;
B) Lógica&lt;br&gt;&lt;br&gt;
C) UX - Experiencia de usuario&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Déjame en comentarios tu respuesta, luego sigues leyendo.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Resultados de Instagram
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg0tsu9to7sobd8ud8p4z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg0tsu9to7sobd8ud8p4z.png" alt="Encuesta en Instagram: Diseño (1 voto, 10%), Lógica / funcionabilidad (8 votos, 80%) y UX (1 voto, 10%). Nota: la palabra 'funcionabilidad' contiene una errata tipográfica." width="800" height="461"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Diseño → 10%&lt;br&gt;&lt;br&gt;
Lógica / funcionalidad → 80%&lt;br&gt;&lt;br&gt;
UX → 10%&lt;/p&gt;

&lt;h3&gt;
  
  
  Resultados de LinkedIn
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuoelnycukbvy10kmi81o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuoelnycukbvy10kmi81o.png" alt="Encuesta en LinkedIn: Diseño (1 voto, 8%), Lógica / funcionalidad (9 votos, 69%) y UX (3 votos, 23%)." width="800" height="565"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Diseño → 8%&lt;br&gt;&lt;br&gt;
Lógica / funcionalidad → 69%&lt;br&gt;&lt;br&gt;
UX → 23%&lt;/p&gt;

&lt;h3&gt;
  
  
  Resultado final
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzokajjj0el9bexgyejtp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzokajjj0el9bexgyejtp.png" alt="Gráfico de barras que muestra el resultado combinado de las encuestas de Instagram y LinkedIn sobre por dónde comenzar un proyecto (total: 23 votos). Diseño obtuvo 2 votos (9%), Lógica / funcionalidad obtuvo 17 votos (74%) y UX obtuvo 4 votos (17%)." width="800" height="452"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Los resultados finales mostraron una clara preferencia por la lógica y funcionalidad, como se puede ver en las encuestas. Pero, ¿por qué? ¿Es esto realmente lo más importante al comenzar un proyecto?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Esto despertó una alarma dentro de mí, esperaba una serie de confrontaciones entre lógica vs UX vs UI.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feek83tkvpsnfoamaw41p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feek83tkvpsnfoamaw41p.png" alt="Captura de pantalla de LinkedIn mostrando información detallada de los seguidores. El 48 % indica no tener experiencia, el 34 % trabaja en desarrollo de software y el 18 % se encuentra en Alicante y alrededores." width="800" height="675"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Decidí investigar un poco más sobre mi audiencia. Gracias a las métricas de LinkedIn, descubrí que más del 48 % son personas sin experiencia, y otro 34 % son junior developers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lo siento, tenemos que hablar
&lt;/h2&gt;

&lt;p&gt;Durante los estudios nos enfocan —y nos enfocamos— en sacar los ejercicios de tal manera que cumplan con la tarea o el examen. Y dado que estamos estudiando y debe poder ser evaluado, esto certifica que tienes esos conocimientos, muchas veces en tiempo récord.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;En el mundo real esto no puede ser así.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Pero en el mundo real esto no es suficiente. Un proyecto no solo debe funcionar, sino también ofrecer una experiencia fluida y accesible para el usuario.&lt;/p&gt;

&lt;p&gt;Y te pongo dos ejemplos de aplicaciones que has utilizado.&lt;br&gt;&lt;br&gt;
Comenzamos con un ejemplo: un juego, y no cualquier juego.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Minecraft&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Ha sido el juego más jugado y vendido durante una década. Y aunque últimamente ha mejorado increíblemente su rendimiento, durante mucho tiempo —en la versión de Java— fue un gran dolor de cabeza por el alto consumo de recursos, FPS completamente inestables, además de que solo usaba un hilo de procesamiento para todo el trabajo y las mecánicas como la redstone pegaban tirones importantes. Esto se aleja mucho de la idea de "primero que funcione", y aun así, el juego ha sido líder.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;¿Y por qué es tan usado si siempre ha funcionado mal y pedía demasiados recursos?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Entre muchas de las cosas que lo han mantenido líder, la que más destaco es su simplicidad y libertad. Puedes hacer lo que quieras, tiene gráficos sencillos que todo el mundo entiende, sin tutorial, incluso durante los inicios sin logros ni misiones. Es tan sencillo, tan fácil, que cualquiera en unos minutos puede empezar. Además, es tan versátil que tienes mil formas de jugar y usarlo. Tanto es así, que se ha utilizado en sectores como ventas y educación.&lt;/p&gt;

&lt;p&gt;¿Te imaginas hacer esto mismo con juegos más elaborados como &lt;strong&gt;League of Legends&lt;/strong&gt;? Estos juegos sí necesitan cierta complejidad para analizar. Tienes que aprenderte todas las mecánicas y combinaciones (que no son pocas), y además está en constante evolución.&lt;/p&gt;

&lt;p&gt;En resumen, la experiencia de usuario en Minecraft ha sido increíble, y pocos juegos han logrado replicar algo similar.&lt;/p&gt;

&lt;p&gt;Aquí puedes decir: "Bueno, esto es un juego, ¿no? No tiene nada que ver con desarrollar apps".&lt;br&gt;&lt;br&gt;
Pues... el concepto es el mismo. Pero aun así, te muestro otro ejemplo:&lt;/p&gt;

&lt;h3&gt;
  
  
  Instagram
&lt;/h3&gt;

&lt;p&gt;Instagram, aunque tiene serios problemas de rendimiento, sigue siendo una de las aplicaciones más adictivas. Su éxito no radica en la perfección técnica, sino en la experiencia de usuario que ha logrado crear: es fácil de usar, simple, directa, y su diseño provoca que los usuarios se queden.&lt;/p&gt;

&lt;p&gt;¡Vaya!... volvemos a otra app que funciona fatal, pero con una experiencia de usuario impecable, al menos en lo que se refiere a retención.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Podría ponerte ejemplos como Canva vs Photoshop, Figma vs Adobe XD o Windows vs Mac.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  ¿Cuándo funciona realmente funcionalidad primero?
&lt;/h2&gt;

&lt;p&gt;Cuando la herramienta está totalmente enfocada a procesos internos, herramientas muy, muy técnicas y muy, muy de nicho. Ahí funciona perfecto.&lt;/p&gt;

&lt;p&gt;Herramientas como &lt;strong&gt;Jira&lt;/strong&gt; y administración de consolas como &lt;strong&gt;AWS&lt;/strong&gt;, donde tienen una potencia técnica increíble y el usuario final va enfocado a su funcionalidad (aunque la primera debería ponerse las pilas en UX... es un dolor de cabeza, en serio).&lt;/p&gt;

&lt;h2&gt;
  
  
  Un criterio más realista
&lt;/h2&gt;

&lt;p&gt;Basándome en comentarios que se hicieron, podríamos sacar un &lt;em&gt;path&lt;/em&gt; más realista:&lt;/p&gt;

&lt;h3&gt;
  
  
  Primero, las matemáticas
&lt;/h3&gt;

&lt;p&gt;Tener una lógica impecable y una experiencia de usuario perfecta no sirve de nada si la aplicación no es viable. Antes de comenzar a desarrollar, asegúrate de que el proyecto sea realizable y que haya un enfoque claro en la viabilidad.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Lo sé, esto se aleja muchísimo de estar estudiando, haciendo prácticas o siendo junior, pero ve ampliando ya tu horizonte.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Segundo, identificar el problema
&lt;/h3&gt;

&lt;p&gt;Antes de escribir una sola línea de código, pregúntate:&lt;br&gt;&lt;br&gt;
¿Qué problema estamos resolviendo? ¿Qué solución podemos ofrecer?&lt;br&gt;&lt;br&gt;
Definir esto con claridad es el primer paso.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ofrecer soluciones al problema
&lt;/h3&gt;

&lt;p&gt;Y aquí sí: aquí entra todo documento técnico con la funcionalidad y, por supuesto, la experiencia de usuario. Y una vez tenemos todo esto claro, ya vamos a empezar con arquitecturas, &lt;em&gt;stacks&lt;/em&gt; y diseño.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Antes de escribir una línea de código, pregúntate:&lt;br&gt;&lt;br&gt;
¿Hay una necesidad real? ¿Es viable económicamente? ¿Quién va a usar esto y cómo lo va a sentir?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Importante&lt;/strong&gt;: no puedes crear una app que no se entienda, que no se sepa usar o que aporte más problemas al usuario final.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Recuerda&lt;/strong&gt;: aportamos valor y hacemos que todo sea más accesible y cómodo. Por supuesto, como todo en nuestro campo, nada es fijo y todo cambia según el escenario, el proyecto y la finalidad.&lt;/p&gt;

&lt;p&gt;Pero desde ya, &lt;em&gt;olvídate de centrar todo en la funcionalidad&lt;/em&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Nuestro trabajo es aportar valor y solventar problemas.&lt;br&gt;&lt;br&gt;
No es solamente escribir código.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;&lt;strong&gt;En resumen&lt;/strong&gt;, nuestro trabajo como desarrolladores no es solo escribir código.&lt;br&gt;&lt;br&gt;
Es resolver problemas y aportar valor.&lt;br&gt;&lt;br&gt;
Si centramos todo en la funcionalidad sin tener en cuenta la experiencia del usuario, corremos el riesgo de crear soluciones complicadas que no sean útiles.&lt;/p&gt;

&lt;p&gt;Y no, esto no va de decir qué está bien o mal. Se trata de abrir el debate, sumar puntos de vista y nutrir nuestro background para que, poco a poco, sepamos por qué hacemos lo que hacemos… y no solo cómo hacerlo.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;¿Qué opinas? ¿Por dónde empezarías tú un proyecto?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
¡Déjame tu respuesta en los comentarios!&lt;/p&gt;

&lt;p&gt;🙌 Si te gustó este post, sígueme en &lt;a href="https://altaskur.live/" rel="noopener noreferrer"&gt;mis redes&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>spanish</category>
      <category>beginners</category>
      <category>discuss</category>
    </item>
    <item>
      <title>¿Listo para el mundo real? Sube tu proyecto de 2º DAW/DAM a un VPS en pocos pasos</title>
      <dc:creator>Altaskur</dc:creator>
      <pubDate>Mon, 07 Jul 2025 21:10:36 +0000</pubDate>
      <link>https://forem.com/altaskur/listo-para-el-mundo-real-sube-tu-proyecto-de-2o-dawdam-a-un-vps-en-pocos-pasos-21bj</link>
      <guid>https://forem.com/altaskur/listo-para-el-mundo-real-sube-tu-proyecto-de-2o-dawdam-a-un-vps-en-pocos-pasos-21bj</guid>
      <description>&lt;p&gt;Tabla de contenidos&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Motivación y prevención de errores típicos&lt;/li&gt;
&lt;li&gt;¿Y para qué te vas a complicar con un VPS teniendo Netlify o Vercel?&lt;/li&gt;
&lt;li&gt;Ventajas económicas y de aprendizaje&lt;/li&gt;
&lt;li&gt;
Pasos iniciales en DonWeb

&lt;ul&gt;
&lt;li&gt;Comencemos&lt;/li&gt;
&lt;li&gt;Elige la imagen de sistema operativo&lt;/li&gt;
&lt;li&gt;Usuario Root&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Acceso por SSH&lt;/li&gt;

&lt;li&gt;Primeros pasos en tu VPS&lt;/li&gt;

&lt;li&gt;Crear una snapshot (copia de seguridad)&lt;/li&gt;

&lt;li&gt;Creación de usuario para deploy&lt;/li&gt;

&lt;li&gt;

Instalar NVM (Node Version Manager)

&lt;ul&gt;
&lt;li&gt;Instalar Node.js LTS con NVM&lt;/li&gt;
&lt;li&gt;¿Por qué instalar Node.js?&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Instalar Nginx y por qué usarlo&lt;/li&gt;

&lt;li&gt;Instalación básica de Nginx&lt;/li&gt;

&lt;li&gt;

Configuración de puertos en DonWeb

&lt;ul&gt;
&lt;li&gt;Cómo configurar los puertos&lt;/li&gt;
&lt;li&gt;Pasos a seguir&lt;/li&gt;
&lt;li&gt;¿Qué pasa si no configuras esto?&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

Preparar el acceso SSH para despliegue con GitHub Actions

&lt;ul&gt;
&lt;li&gt;¿Por qué necesitas esto?&lt;/li&gt;
&lt;li&gt;Pasos para configurar SSH para el usuario deploy&lt;/li&gt;
&lt;li&gt;Configurar GitHub Actions para usar la clave privada&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Configurar un workflow de GitHub Actions para desplegar tu proyecto&lt;/li&gt;

&lt;li&gt;

Explicación del workflow de GitHub Actions paso a paso

&lt;ul&gt;
&lt;li&gt;Configuración básica del workflow&lt;/li&gt;
&lt;li&gt;Disparadores del workflow&lt;/li&gt;
&lt;li&gt;Permisos y concurrencia&lt;/li&gt;
&lt;li&gt;Definición del trabajo (job)&lt;/li&gt;
&lt;li&gt;El paso de despliegue&lt;/li&gt;
&lt;li&gt;Configuración de la conexión SSH&lt;/li&gt;
&lt;li&gt;La lógica del script de despliegue&lt;/li&gt;
&lt;li&gt;¿Por qué funciona tan bien esta lógica?&lt;/li&gt;
&lt;li&gt;Un detalle importante sobre los secrets&lt;/li&gt;
&lt;li&gt;Cómo funciona todo el proceso completo&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Mejoras y optimizaciones avanzadas&lt;/li&gt;

&lt;li&gt;🚀 ¿Quieres que haga una segunda parte sobre despliegue avanzado?&lt;/li&gt;

&lt;li&gt;

Solución de problemas comunes

&lt;ul&gt;
&lt;li&gt;Error: "Permission denied" al hacer git pull&lt;/li&gt;
&lt;li&gt;Error: "Host key verification failed"&lt;/li&gt;
&lt;li&gt;Nginx muestra "403 Forbidden"&lt;/li&gt;
&lt;li&gt;El workflow se ejecuta pero no se actualiza la web&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Conclusión&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Estoy seguro de que si estás en 2º de DAW o DAM y te toca presentar tu proyecto final, has pensado en desplegarlo en un servidor, pensarás que te llevará mucho tiempo, además de no comprender del todo cómo funciona, así que seguramente has pensado en servicios como Netlify o Vercel, que son muy cómodos y fáciles de usar, pero... ¿Qué pasa si quieres algo más? O simplemente aprender a desplegar tu proyecto sin tanta magia por detrás. ¿Se supone que estamos aprendiendo a desarrollar no? Y el despliegue es una parte fundamental del proceso de desarrollo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Motivación y prevención de errores típicos
&lt;/h2&gt;

&lt;p&gt;Antes de meternos en faena, ¿qué ganas con todo esto? Lo principal es que te quitas riesgos importantes. El más común: tienes todo preparado, llega el día de la defensa y... sorpresa, al iniciar el proyecto en el portátil, no funciona. No te puedes hacer una idea de lo habitual que es eso, y créeme, no te quieres ver en esa situación.&lt;/p&gt;

&lt;p&gt;Además, muy típico, cambios de última hora o llevas mucho desarrollado y no has probado nada. &lt;br&gt;
Todo esto te lo puedes saltar usando un despliegue continuo con GitHub Actions (por ejemplo), así cada vez que subas cambios a tu repositorio, se desplegará automáticamente en tu servidor. Esto te ahorra tiempo y te asegura que siempre tienes la última versión funcionando.&lt;/p&gt;
&lt;h2&gt;
  
  
  ¿Y para qué te vas a complicar con un VPS teniendo Netlify o Vercel?
&lt;/h2&gt;

&lt;p&gt;Si solo necesitas publicar una web sencilla, funcionan perfecto. Pero si necesitas un backend completo, bases de datos, bots, tareas automáticas (cron), websockets... puedes montar lo que quieras, aunque sea raro, experimental o muy ambicioso. La única limitación es la capacidad de tu servidor.&lt;/p&gt;

&lt;p&gt;Además, con un VPS tienes control total: puedes instalar lo que quieras, configurar el sistema a tu medida y optimizarlo para tu proyecto. No dependes de las limitaciones ni del template que ofrecen.&lt;/p&gt;
&lt;h2&gt;
  
  
  Ventajas económicas y de aprendizaje
&lt;/h2&gt;

&lt;p&gt;Algo que me parece primordial y sobre todo al estar estudiando, &lt;strong&gt;no hay cobros sorpresa: pagas lo mismo cada mes, superes o no la capacidad del servidor&lt;/strong&gt;. Es muy común en servicios de nube como AWS, Azure o Google Cloud, donde cobras por uso, cualquier fallo, descuido o vulnerabilidad puede hacer que te lleves una sorpresa desagradable al final de mes. Que ya sabemos que no tiene por qué pasar, pero te da muchísima más tranquilidad saber que apagas tu servidor, haces tus cambios y no te cobran más por ello.&lt;/p&gt;

&lt;p&gt;Esto es sin duda fue mi principal temor cuando estaba estudiando DAW, aunque me gradué con los dos primeros Tier de AWS, ese temor siempre me ha frenado muchísimo a subir mis proyectos. Así que te muestro la opción más segura que encontré y que sigo aplicando en mis proyectos.&lt;/p&gt;

&lt;p&gt;Y por último, el aprendizaje: vas a entender realmente cómo funciona el despliegue, la configuración y la administración de servidores, algo que marca la diferencia y suma muchos puntos cuando salgas al mundo profesional, independientemente de si tiras hacia front o back. Créeme que cuando aprendes que cuantas menos magias mientras estás creando tu base de conocimientos, más fácil te será adaptarte a cualquier tecnología o servicio que surja en el futuro (que te aseguro que van a venir).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Resumen: ganas control, flexibilidad y aprendizaje.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Para el post vamos a elegir &lt;a href="//Donweb.com"&gt;https://donweb.com/es-es/cloud-server-altaskur&lt;/a&gt; como proveedor de servicios.&lt;/p&gt;

&lt;p&gt;¿Por qué &lt;a href="//Donweb.com"&gt;https://donweb.com/es-es/cloud-server-altaskur&lt;/a&gt;? Es una empresa conocida en Latinoamérica, tiene soporte en español, es sencilla de usar y, lo más importante, para este post he contado con su apoyo, que me ha facilitado un VPS para hacer las pruebas y capturas.&lt;/p&gt;

&lt;p&gt;¿Y si tienes otro proveedor? Si tienes otros servicios (OVH, Hetzner, DigitalOcean, etc.), puedes seguir los pasos igual. Como te he comentado antes, las bases son exactamente las mismas; solo cambiarán pequeños detalles del panel.&lt;/p&gt;
&lt;h2&gt;
  
  
  Pasos iniciales en DonWeb
&lt;/h2&gt;

&lt;p&gt;Ahora que lo tenemos todo decidido vamos a comenzar con la aventura. Desde este punto voy a dar por hecho que ya tienes una cuenta en DonWeb y has iniciado sesión en su panel de control, además de tener un VPS contratado.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fesowf9c31gl7le0jlg6e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fesowf9c31gl7le0jlg6e.png" alt=" " width="800" height="540"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Recuerda que puedes replicarlo con cualquier proveedor de VPS, los pasos son muy similares.&lt;/p&gt;

&lt;p&gt;Puedes crear una cuenta en este enlace: &lt;a href="//donweb.com"&gt;https://donweb.com/es-es/cloud-server-altaskur&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  Comencemos
&lt;/h3&gt;

&lt;p&gt;Una vez dentro del panel de &lt;a href="//Donweb.com"&gt;https://donweb.com/es-es/cloud-server-altaskur&lt;/a&gt; y nuestro servidor contratado, vamos a configurar nuestro VPS para que esté listo para desplegar nuestro proyecto.&lt;/p&gt;
&lt;h3&gt;
  
  
  Elige la imagen de sistema operativo
&lt;/h3&gt;

&lt;p&gt;Elige la imagen de sistema operativo. Selecciona "Instalación Mínima" con Ubuntu 24.04. Esto garantiza un sistema limpio y ligero, ideal para montar solo lo que necesitas.&lt;/p&gt;

&lt;p&gt;Que además, si necesitas cualquier otro servicio, tienes muchas imágenes preconfiguradas, con todo disponible. Una de mis favoritas es la de node (que ya viene con node y pm2 instalado), pero para este post vamos a usar una instalación mínima de Ubuntu 24.04, que es la versión LTS más reciente y estable.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flvo79sns0oeyijif5m4k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flvo79sns0oeyijif5m4k.png" alt=" " width="493" height="531"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;¿Por qué una instalación mínima y por qué Ubuntu? Básicamente Ubuntu es un sistema muy fácil de usar con una gran comunidad y documentación, así que si tienes cualquier problema seguro que con una búsqueda rápida encuentras la solución. Podríamos optar por una imagen como Debian (seguramente te lo dirán) porque es la más usada en servidores, pero en este post voy a intentar facilitarte las cosas ante cualquier problema que pueda salirte, y Ubuntu es una de las distribuciones más amigables y con más soporte.&lt;/p&gt;

&lt;p&gt;¿Te apetece probar con Debian? 👀 No te juzgo, pensé igual que tú cuando estudiaba. ¡Adelante! Los pasos son muy similares, pero ten en cuenta que la configuración puede variar un poco.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Te recomiendo que una vez tengas hecha con Ubuntu pruebes otras distribuciones e imágenes.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  Usuario Root
&lt;/h3&gt;

&lt;p&gt;Crea la contraseña del usuario root. El panel te pedirá establecer una contraseña segura para el usuario root. DonWeb incluye un generador de contraseñas integrado bastante decente, aprovéchalo.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Por si no has estado muy pendiente en clase, el usuario root tiene acceso total a todo el sistema, así que no menosprecies este paso, vale. Es importante aunque no te lo parezca y además siempre puedes cambiarla más adelante.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Confirma y lanza la instalación. Haz clic en continuar y espera unos minutos (no suele ser más de 3 min, que es muchísimo menos de lo que tardas en hacerlo en VirtualBox). Durante este tiempo, el sistema se instala y prepara.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6jukhu49joe1i93uml4q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6jukhu49joe1i93uml4q.png" alt=" " width="800" height="199"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Una vez termine la instalación, tendrás acceso a tu VPS por SSH usando la IP, el usuario root y la contraseña que has puesto antes.&lt;/p&gt;

&lt;p&gt;Y sin tener que especificar ni dominio de actualizaciones ni idioma del teclado ni nada de eso, como pasaba con VirtualBox.&lt;/p&gt;
&lt;h2&gt;
  
  
  Acceso por SSH
&lt;/h2&gt;

&lt;p&gt;Conectarte por SSH a tu VPS te será muy familiar si has usado VirtualBox durante el curso (¡seguro que sí! 😊).&lt;/p&gt;

&lt;p&gt;Y si no, ni te preocupes. Suponiendo que estás en un entorno Windows usa la PowerShell o si estás en Mac o Linux, abre la terminal.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4ms2ekns4iy1tf8dsaxr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4ms2ekns4iy1tf8dsaxr.png" alt=" " width="800" height="433"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;¿Dónde están los datos de acceso? Ve al apartado de software y accesos en el panel de DonWeb. Ahí tendrás para copiar en tu terminal un comando como este:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh &lt;span class="nt"&gt;-p&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;tu puerto] root@[tu_direccion_IP]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;El puerto (-p[tu puerto]) y la dirección IP pueden variar según tu VPS. Asegúrate de copiar los valores que te da DonWeb para tu máquina.&lt;/p&gt;

&lt;h2&gt;
  
  
  Primeros pasos en tu VPS
&lt;/h2&gt;

&lt;p&gt;Ahora estamos en nuestro servidor y lo primero que vamos a hacer es actualizar la máquina. Para ello, ejecuta estos comandos en la terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt upgrade
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esto puede tardar un ratito, así que ten paciencia. Actualizar el sistema asegura que tienes todos los parches de seguridad y las versiones más recientes de los paquetes instalados y nos olvidamos de problemas de compatibilidad más adelante.&lt;/p&gt;

&lt;h2&gt;
  
  
  Crear una snapshot (copia de seguridad)
&lt;/h2&gt;

&lt;p&gt;Cuando termine la actualización, lo siguiente es crear una snapshot. Así tendrás una imagen de tu sistema justo desde el inicio, por si algo falla más adelante y necesitas volver atrás.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkqd3gg3hde4x9xewnf5b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkqd3gg3hde4x9xewnf5b.png" alt=" " width="800" height="267"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Busca en el panel de DonWeb la opción de Snapshots o copias de seguridad y crea una nueva antes de seguir.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creación de usuario para deploy
&lt;/h2&gt;

&lt;p&gt;Ahora que ya tenemos preparada una versión limpia y actualizada de Ubuntu, vamos a dar el siguiente paso. &lt;em&gt;No es recomendable usar Root&lt;/em&gt;. De hecho, cuanto menos lo expongamos mejor, ya que este tiene acceso total al sistema, así que lo primero que hay que hacer es crear un usuario nuevo para gestionar el servidor y el despliegue de tu proyecto.&lt;/p&gt;

&lt;p&gt;Vamos a ello. Para ello vamos a crear un usuario, lo vamos a llamar deploy por el tema de semántica, pero puedes ponerle el nombre que quieras.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;adduser deploy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxefrtnbg06fugyddfa0t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxefrtnbg06fugyddfa0t.png" alt=" " width="774" height="260"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Sigue las instrucciones para ponerle contraseña (puede ser distinta a la de root) y, si quieres, rellena los datos adicionales (puedes dejarlos en blanco pulsando Enter).&lt;/p&gt;

&lt;p&gt;Después, añade este usuario al grupo sudo para que pueda usar permisos de administración cuando lo necesite:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt; usermod &lt;span class="nt"&gt;-aG&lt;/span&gt; &lt;span class="nb"&gt;sudo &lt;/span&gt;deploy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Una vez tienes esto listo, sal de la sesión de root en la terminal y vuelve a conectarte, pero esta vez usando el usuario deploy que acabas de crear.&lt;/p&gt;

&lt;p&gt;Para salir de la terminal como root, simplemente escribe:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;exit&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ahora inicia sesión de nuevo por SSH, pero cambiando root por deploy y usando la misma IP y puerto que antes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh &lt;span class="nt"&gt;-p&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;tu puerto] deploy@[tu_direccion_IP]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Introduce la contraseña del usuario deploy cuando te la pida.&lt;/p&gt;

&lt;p&gt;Ahora que ya estamos dentro vamos a empezar a aprovisionar el servidor. Para ello vamos a instalar Node.js con NVM (Node Version Manager), Nginx como instalación mínima para poder desplegar tu proyecto de front y backend con node.&lt;/p&gt;

&lt;h2&gt;
  
  
  Instalar NVM (Node Version Manager)
&lt;/h2&gt;

&lt;p&gt;Ahora que ya estás conectado como el usuario deploy, vamos a instalar NVM. NVM te permitirá instalar y gestionar diferentes versiones de Node.js de forma sencilla.&lt;/p&gt;

&lt;p&gt;En la terminal, ejecuta el siguiente comando para descargar e instalar la última versión de NVM:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-o-&lt;/span&gt; https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Una vez termine, cierra y vuelve a abrir la terminal, o ejecuta el siguiente comando para cargar NVM en la sesión actual:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;NVM_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/.nvm"&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$NVM_DIR&lt;/span&gt;&lt;span class="s2"&gt;/nvm.sh"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\.&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$NVM_DIR&lt;/span&gt;&lt;span class="s2"&gt;/nvm.sh"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Para comprobar que NVM está instalado correctamente, ejecuta:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nvm &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Si ves un número de versión, ¡ya lo tienes listo!&lt;/p&gt;

&lt;h3&gt;
  
  
  Instalar Node.js LTS con NVM
&lt;/h3&gt;

&lt;p&gt;Ahora que tienes NVM instalado, vamos a instalar la versión LTS de Node.js. La versión LTS es la más recomendada para la mayoría de proyectos porque es la más estable y tiene soporte a largo plazo.&lt;/p&gt;

&lt;p&gt;En la terminal, ejecuta:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nvm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--lts&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esto descargará e instalará la última versión LTS disponible de Node.js.&lt;/p&gt;

&lt;p&gt;Para comprobar que la instalación se realizó correctamente y estás usando la versión LTS, ejecuta:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node &lt;span class="nt"&gt;-v&lt;/span&gt;
npm &lt;span class="nt"&gt;-v&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Deberías ver los números de versión correspondientes.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Por qué instalar Node.js?
&lt;/h3&gt;

&lt;p&gt;Instalar Node.js es necesario porque la mayoría de proyectos modernos de backend y muchas herramientas de frontend (como React, Angular, Vue, Svelte, etc.) usan Node.js para funcionar, tanto en desarrollo como en producción.&lt;/p&gt;

&lt;p&gt;Además si tu proyecto está hecho con cualquier stack basado en JavaScript o necesitas ejecutar scripts asique necesitarás Node.js en tu servidor&lt;/p&gt;

&lt;p&gt;En resumen: Instalar Node.js te garantiza que tu VPS puede ejecutar la mayoría de proyectos web actuales y es casi imprescindible para DAW/DAM hoy en día.&lt;/p&gt;

&lt;h2&gt;
  
  
  Instalar Nginx y por qué usarlo
&lt;/h2&gt;

&lt;p&gt;Ahora que ya tienes Node.js instalado, vamos a instalar nginx.&lt;/p&gt;

&lt;p&gt;¿Y por qué Nginx? Porque Nginx es un servidor web ligero, rápido y muy usado en producción.&lt;br&gt;
Mucha gente te hablará de Apache, y es el servidor web más antiguo y conocido, ¿pero por qué Nginx? Es más ligero, y en la mayoría de los casos es más fácil de configurar y mantener.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Al igual que te dije con Ubuntu Vs Debian, Nginx es el más fácil, así que si quieres adentrarte con apache ¡Adelante! 👀 aunque te recomiendo que primero lo montes con Nginx así luego te sonará todo.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;¿Y qué es esto de Nginx o Apache? Pues lo que hacen es servir tu página web, similar a un &lt;code&gt;npm start&lt;/code&gt; de Node.js, pero a nivel de servidor de modo que hará tu proyecto accesible desde Internet.&lt;/p&gt;

&lt;p&gt;No solo sirve para servir páginas web estáticas, sino que también puede actuar como proxy inverso para aplicaciones Node.js, gestionar certificados SSL, balancear carga entre varios servidores y mucho más.&lt;/p&gt;

&lt;p&gt;Es compatible con SSL (HTTPS), por lo que es imprescindible si quieres usar certificados y servir tu web de forma segura.&lt;/p&gt;

&lt;p&gt;En resumen: Nginx es un servidor web moderno versátil y ligero. Es una herramienta fundamental para desplegar aplicaciones web en producción, ya sea para servir archivos estáticos, actuar como proxy inverso o gestionar certificados SSL.&lt;/p&gt;
&lt;h2&gt;
  
  
  Instalación básica de Nginx
&lt;/h2&gt;

&lt;p&gt;En tu terminal (con el usuario deploy, usando sudo), ejecuta:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cuando termine, puedes comprobar que Nginx está funcionando abriendo tu navegador y poniendo la IP de tu servidor: Deberías ver la página de bienvenida de Nginx.&lt;/p&gt;

&lt;p&gt;Y ya está, ya tienes Nginx instalado y funcionando en tu servidor. Ahora puedes ver la página de bienvenida de Nginx en la carpeta /var/www/html, que es donde se guardan los archivos que Nginx sirve por defecto.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuración de puertos en DonWeb
&lt;/h2&gt;

&lt;p&gt;Antes de seguir con el despliegue automático, hay un paso importante que muchas veces se pasa por alto: &lt;strong&gt;configurar correctamente los puertos en el panel de DonWeb&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;¿Por qué es importante esto? Aunque tengas Nginx funcionando perfectamente en tu servidor, si los puertos no están abiertos en el firewall de DonWeb, nadie podrá acceder a tu web desde Internet. Es como tener una casa perfectamente amueblada pero con la puerta de entrada cerrada.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cómo configurar los puertos
&lt;/h3&gt;

&lt;p&gt;Ve al panel de DonWeb, busca la sección de &lt;strong&gt;Firewall&lt;/strong&gt; o &lt;strong&gt;Configuración de puertos&lt;/strong&gt; de tu VPS. Ahí verás una interfaz similar a esta:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmdz0duxuotsyh009j2g6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmdz0duxuotsyh009j2g6.png" alt=" " width="800" height="280"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Los puertos que necesitas abrir como mínimo son:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Puerto 80 (HTTP)&lt;/strong&gt;: Para que tu web sea accesible sin HTTPS&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Puerto 443 (HTTPS)&lt;/strong&gt;: Para cuando configures certificados SSL&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Puerto SSH&lt;/strong&gt;: El que usas para conectarte (normalmente aparece ya configurado)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Pasos a seguir
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Identifica los puertos necesarios&lt;/strong&gt;: Para un proyecto web básico, necesitas el 80 y 443&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Añade las reglas&lt;/strong&gt;: En el panel de DonWeb, crea nuevas reglas para estos puertos&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Configura el origen&lt;/strong&gt;: Normalmente puedes dejarlo como "Any" (0.0.0.0/0) para que sea accesible desde cualquier lugar&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Aplica los cambios&lt;/strong&gt;: Guarda la configuración y espera unos segundos a que se aplique&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  ¿Qué pasa si no configuras esto?
&lt;/h3&gt;

&lt;p&gt;Si no abres estos puertos, aunque tu aplicación esté funcionando perfectamente en el servidor, cuando intentes acceder desde tu navegador verás errores tipo "No se puede conectar" o "Tiempo de espera agotado". Es uno de los errores más comunes y que más frustración genera, especialmente cuando todo lo demás está bien configurado.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;💡 Tip importante&lt;/strong&gt;: Si tu aplicación Node.js usa un puerto diferente (como el 3000), también necesitarás abrirlo en el firewall, o mejor aún, configurar Nginx como proxy inverso para que sirva tu aplicación a través del puerto 80/443.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Una vez tengas los puertos configurados correctamente, podrás acceder a tu servidor desde el navegador usando la IP que te proporciona DonWeb, y deberías ver la página de bienvenida de Nginx.&lt;/p&gt;

&lt;h2&gt;
  
  
  Preparar el acceso SSH para despliegue con GitHub Actions
&lt;/h2&gt;

&lt;p&gt;Ya tenemos tanto backend como frontend preparados para desplegar y un servidor web disponible para servir tu proyecto.&lt;/p&gt;

&lt;p&gt;Pero, ¿cómo vamos a subir los archivos de tu proyecto al servidor? ¿Y cómo vamos a hacer que GitHub Actions pueda desplegar automáticamente cada vez que subas cambios?&lt;br&gt;
Para esto, vamos a configurar el acceso SSH para el usuario deploy que acabamos de crear.&lt;/p&gt;
&lt;h3&gt;
  
  
  ¿Por qué necesitas esto?
&lt;/h3&gt;

&lt;p&gt;GitHub Actions puede ejecutar scripts y comandos automáticamente cada vez que subes código (push).&lt;/p&gt;

&lt;p&gt;Para que pueda copiar los archivos o ejecutar comandos en tu servidor, necesita conectarse por SSH sin pedirte la contraseña cada vez. Así te olvidas de hacer zips con el build del proyecto de ftp y subirlo manualmente. Esto normalmente se tarda mucho tiempo, son muchos pasos y cuantos más pasos más probable es que algo falle (sobre todo si lo haces a última hora 👀 que ya sabemos lo que pasa).&lt;/p&gt;

&lt;p&gt;Por seguridad y automatización, se usan claves SSH, no contraseñas. Así no tienes que escribir la contraseña cada vez que quieras hacer un despliegue ni hardcodear la contraseña en tu repositorio de GitHub (que también te veo venir).&lt;/p&gt;
&lt;h3&gt;
  
  
  Pasos para configurar SSH para el usuario deploy
&lt;/h3&gt;

&lt;p&gt;Entonces desde la terminal nos vamos a tu servidor VPS y vas a ejecutar el siguiente comando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh-keygen &lt;span class="nt"&gt;-t&lt;/span&gt; ed25519 &lt;span class="nt"&gt;-C&lt;/span&gt; &lt;span class="s2"&gt;"deploy@tuproyecto"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pulsa Enter en todas las preguntas (puedes poner una ruta o dejar la predeterminada y no pongas passphrase).&lt;/p&gt;

&lt;p&gt;Copia la clave pública al servidor usando el siguiente comando (reemplaza los datos según tu configuración):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh-copy-id &lt;span class="nt"&gt;-p&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;tu puerto] deploy@[tu_direccion_IP]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Si no tienes ssh-copy-id, puedes copiar manualmente el contenido de ~/.ssh/id_ed25519.pub al archivo ~/.ssh/authorized_keys en el servidor, dentro del usuario deploy. Puede ser que tengas que crear o la carpeta .ssh o el archivo authorized_keys si no existen. Revísalo primero con un ls -la en la carpeta del usuario deploy.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; ~/.ssh
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"tu_clave_publica"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; ~/.ssh/authorized_keys
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Una vez lo tenemos, vamos a asegurarnos de que los permisos son correctos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;chmod &lt;/span&gt;700 ~/.ssh
&lt;span class="nb"&gt;chmod &lt;/span&gt;600 ~/.ssh/authorized_keys
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ahora ya podemos usar las claves SSH para conectarnos al servidor desde GitHub Actions sin necesidad de introducir la contraseña cada vez y comenzar a desplegar tu proyecto automáticamente.&lt;/p&gt;

&lt;h3&gt;
  
  
  Configurar GitHub Actions para usar la clave privada
&lt;/h3&gt;

&lt;p&gt;Abre tu clave privada (por ejemplo, ~/.ssh/id_ed25519) con un editor de texto y cópiala entera.&lt;/p&gt;

&lt;p&gt;Ve a tu repositorio en GitHub → Settings → Secrets and variables → Actions.&lt;/p&gt;

&lt;p&gt;Crea un nuevo Secret llamado, por ejemplo, DEPLOY_KEY y pega ahí el contenido de la clave privada.&lt;/p&gt;

&lt;p&gt;Y ya está, ahora tu GitHub Actions puede usar esta clave para conectarse a tu servidor y desplegar tu proyecto automáticamente.&lt;/p&gt;

&lt;p&gt;Aún queda un paso más. Ahora mismo lo único que hemos hecho es guardar la clave privada en GitHub de manera segura, pero aún no le hemos dicho a GitHub Actions que la use y lo más importante no le hemos dicho cómo ha de usarla.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configurar un workflow de GitHub Actions para desplegar tu proyecto
&lt;/h2&gt;

&lt;p&gt;Aquí es donde empieza la fiesta realmente. Hay muchas formas de hacer esto y sobre todo ha de ser adaptado a tu proyecto, según estés usando Frontend con (React, Angular, Vue, Svelte, etc.) o Backend con Node.js (Express, NestJS, etc.) o cualquier otro lenguaje o framework. Cada uno tiene su propia manera de ser desplegado, así que eso tendrás que adaptarlo a tu proyecto.&lt;/p&gt;

&lt;p&gt;Pero te voy a dar un ejemplo básico de cómo podrías configurar un workflow de GitHub Actions para desplegar tu proyecto al servidor usando un HTML estático simulando un build de un proyecto de frontend ya realizado.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;📚 Contenido relacionado&lt;/strong&gt;: Si tienes un proyecto Angular y quieres desplegarlo, puedes ver mi post sobre &lt;a href="https://dev.to/altaskur/como-desplegar-angular-19-en-github-pages-desde-github-actions-9d8"&gt;cómo desplegar Angular 19 en GitHub Pages&lt;/a&gt;. Esta enfocado a GitHub Pages pero puedes adaptarlo al VPS sin problema. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Lo primero necesitarás crear una carpeta en tu proyecto llamada &lt;code&gt;.github/workflows&lt;/code&gt; y dentro de esta un archivo llamado &lt;code&gt;deploy.yml&lt;/code&gt; o el nombre que quieras, pero con la extensión &lt;code&gt;.yml&lt;/code&gt;. Aquí es donde vamos a definir el workflow de GitHub Actions que no es nada más que un conjunto de pasos que se ejecutarán automáticamente cada vez que subas cambios a tu repositorio.&lt;/p&gt;

&lt;p&gt;Te dejo un ejemplo básico de cómo podría ser este archivo:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;¿Quieres ver en detalle un workflow de GitHub Actions completo? o alguna tecnología en concreto? Dímelo en los comentarios y lo preparo para un próximo post.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;🚀 Deploy Web to VPS&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;main&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;workflow_dispatch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

&lt;span class="na"&gt;permissions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;contents&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;read&lt;/span&gt;
  &lt;span class="na"&gt;pages&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;write&lt;/span&gt;
  &lt;span class="na"&gt;id-token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;write&lt;/span&gt;

&lt;span class="na"&gt;concurrency&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;group&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pages"&lt;/span&gt;
  &lt;span class="na"&gt;cancel-in-progress&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;⚙️ Execute Deployment SSH Command&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;appleboy/ssh-action@v1&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.VPS_HOST }}&lt;/span&gt;
          &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.VPS_USERNAME }}&lt;/span&gt;
          &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.VPS_SSH_KEY }}&lt;/span&gt;
          &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.VPS_SSH_PORT }}&lt;/span&gt;
          &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
            &lt;span class="s"&gt;cd /var/www/html/&lt;/span&gt;
            &lt;span class="s"&gt;if [ -d "[nombre proyecto]/.git" ]; then&lt;/span&gt;
              &lt;span class="s"&gt;echo "El repositorio ya existe, haciendo pull..."&lt;/span&gt;
              &lt;span class="s"&gt;cd [nombre proyecto]&lt;/span&gt;
              &lt;span class="s"&gt;git pull&lt;/span&gt;
            &lt;span class="s"&gt;else&lt;/span&gt;
              &lt;span class="s"&gt;if [ -d "[nombre proyecto]" ]; then&lt;/span&gt;
                &lt;span class="s"&gt;echo "Existe [nombre proyecto] pero NO es repo, borrando carpeta..."&lt;/span&gt;
                &lt;span class="s"&gt;rm -rf [nombre proyecto]&lt;/span&gt;
              &lt;span class="s"&gt;fi&lt;/span&gt;
              &lt;span class="s"&gt;echo "Clonando repo..."&lt;/span&gt;
              &lt;span class="s"&gt;git clone ${{ secrets.VPS_REPO_URL }}&lt;/span&gt;
            &lt;span class="s"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Explicación del workflow de GitHub Actions paso a paso
&lt;/h2&gt;

&lt;p&gt;Ahora que ya tienes el archivo YAML del workflow, vamos a explicar qué hace cada parte para que entiendas exactamente cómo funciona este despliegue automático.&lt;/p&gt;

&lt;h3&gt;
  
  
  Configuración básica del workflow
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;🚀 Deploy Web to VPS&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Aquí defines el nombre que aparecerá en la pestaña de Actions de tu repositorio de GitHub. El emoji es opcional pero ayuda a identificar rápidamente el workflow.&lt;/p&gt;

&lt;h3&gt;
  
  
  Disparadores del workflow
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;main&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;workflow_dispatch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esta sección define &lt;strong&gt;cuándo&lt;/strong&gt; se ejecutará el workflow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;push: branches: [main]&lt;/code&gt; → Se ejecuta automáticamente cada vez que haces push a la rama main&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;workflow_dispatch&lt;/code&gt; → Te permite ejecutar el workflow manualmente desde la interfaz de GitHub&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;¿Por qué usar ambos? El automático te ahorra trabajo en el día a día, y el manual te da control cuando necesitas hacer un despliegue específico.&lt;/p&gt;

&lt;h3&gt;
  
  
  Permisos y concurrencia
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;permissions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;contents&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;read&lt;/span&gt;
  &lt;span class="na"&gt;pages&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;write&lt;/span&gt;
  &lt;span class="na"&gt;id-token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;write&lt;/span&gt;

&lt;span class="na"&gt;concurrency&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;group&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pages"&lt;/span&gt;
  &lt;span class="na"&gt;cancel-in-progress&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Permisos&lt;/strong&gt;: Define qué puede hacer GitHub Actions en tu repositorio:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;contents: read&lt;/code&gt; → Puede leer el código de tu repositorio&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;pages: write&lt;/code&gt; → Puede escribir en GitHub Pages (si lo usas)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;id-token: write&lt;/code&gt; → Puede generar tokens de identidad para autenticación&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Concurrencia&lt;/strong&gt;: Evita que se ejecuten múltiples despliegues al mismo tiempo:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Si hay un despliegue en curso y haces otro push, cancela el anterior y ejecuta el nuevo&lt;/li&gt;
&lt;li&gt;Esto previene conflictos y problemas de estado inconsistente&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Definición del trabajo (job)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Aquí defines:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;deploy&lt;/code&gt; → Nombre del trabajo (puedes tener varios jobs en un workflow)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;runs-on: ubuntu-latest&lt;/code&gt; → El sistema operativo donde se ejecutará (GitHub proporciona la máquina virtual)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  El paso de despliegue
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;⚙️ Execute Deployment SSH Command&lt;/span&gt;
    &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;appleboy/ssh-action@v1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;¿Qué es &lt;code&gt;appleboy/ssh-action&lt;/code&gt;?&lt;/strong&gt; Es una acción desarrollada por la comunidad que facilita ejecutar comandos SSH desde GitHub Actions. Es como si GitHub se conectara por SSH a tu servidor y ejecutara comandos automáticamente.&lt;/p&gt;

&lt;h3&gt;
  
  
  Configuración de la conexión SSH
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.VPS_HOST }}&lt;/span&gt;
  &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.VPS_USERNAME }}&lt;/span&gt;
  &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.VPS_SSH_KEY }}&lt;/span&gt;
  &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.VPS_SSH_PORT }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Estos son los &lt;strong&gt;GitHub Secrets&lt;/strong&gt; que configuraste antes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;VPS_HOST&lt;/code&gt; → La IP de tu servidor&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;VPS_USERNAME&lt;/code&gt; → El usuario deploy que creaste&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;VPS_SSH_KEY&lt;/code&gt; → La clave privada SSH&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;VPS_SSH_PORT&lt;/code&gt; → El puerto SSH de tu servidor&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;¿Por qué secrets?&lt;/strong&gt; Porque esta información es sensible y no debe estar visible en tu código público.&lt;/p&gt;

&lt;h3&gt;
  
  
  La lógica del script de despliegue
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
  &lt;span class="s"&gt;cd /var/www/html/proyects/&lt;/span&gt;
  &lt;span class="s"&gt;if [ -d "[nombre proyecto]/.git" ]; then&lt;/span&gt;
    &lt;span class="s"&gt;echo "El repositorio ya existe, haciendo pull..."&lt;/span&gt;
    &lt;span class="s"&gt;cd [nombre proyecto]&lt;/span&gt;
    &lt;span class="s"&gt;git pull&lt;/span&gt;
  &lt;span class="s"&gt;else&lt;/span&gt;
    &lt;span class="s"&gt;if [ -d "[nombre proyecto]" ]; then&lt;/span&gt;
      &lt;span class="s"&gt;echo "Existe [nombre proyecto] pero NO es repo, borrando carpeta..."&lt;/span&gt;
      &lt;span class="s"&gt;rm -rf [nombre proyecto]&lt;/span&gt;
    &lt;span class="s"&gt;fi&lt;/span&gt;
    &lt;span class="s"&gt;echo "Clonando repo..."&lt;/span&gt;
    &lt;span class="s"&gt;git clone ${{ secrets.VPS_REPO_URL }}&lt;/span&gt;
  &lt;span class="s"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Vale, ahora vamos a lo que realmente hace este script cuando se ejecuta en tu servidor. Primero se mueve a la carpeta &lt;code&gt;/var/www/html/&lt;/code&gt; que es donde están los archivos que Nginx sirve por defecto. Una vez ahí, lo primero que hace es verificar si ya existe una carpeta con el nombre de tu proyecto y además si esa carpeta es un repositorio Git válido.&lt;/p&gt;

&lt;p&gt;Si encuentra que ya tienes el proyecto ahí y es un repo Git, genial, solo hace un &lt;code&gt;git pull&lt;/code&gt; para bajarse los últimos cambios que hayas hecho. Es súper eficiente porque no tiene que descargar todo otra vez, solo los archivos que cambiaron.&lt;/p&gt;

&lt;p&gt;Pero si encuentra una carpeta con el nombre de tu proyecto pero resulta que no es un repositorio Git (esto puede pasar si algo se rompió antes o si pusiste archivos manualmente), lo que hace es borrar toda esa carpeta y empezar de cero. Mejor limpio que con archivos raros por ahí.&lt;/p&gt;

&lt;p&gt;Y finalmente, si no existe absolutamente nada, pues clona el repositorio completo desde GitHub usando la URL que tienes guardada en los secrets.&lt;/p&gt;

&lt;h3&gt;
  
  
  ¿Por qué funciona tan bien esta lógica?
&lt;/h3&gt;

&lt;p&gt;Si ya tienes el proyecto desplegado, solo actualiza lo que necesita, que es mucho más rápido que estar bajando todo cada vez. Y si algo falló en algún momento (que pasa más de lo que te imaginas), no se queda ahí dando vueltas con archivos corruptos, simplemente borra todo y empieza fresh.&lt;/p&gt;

&lt;p&gt;Además funciona igual de bien tanto si es la primera vez que despliegas como si ya llevas meses actualizando el proyecto. No tienes que estar pensando en casos especiales ni nada raro.&lt;/p&gt;

&lt;h3&gt;
  
  
  Un detalle importante sobre los secrets
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Ojo que aparte de todos los secrets de SSH que configuramos antes, también vas a necesitar agregar &lt;code&gt;VPS_REPO_URL&lt;/code&gt; en GitHub. Este es simplemente la URL de tu repositorio, algo como &lt;code&gt;https://github.com/tuusuario/tuproyecto.git&lt;/code&gt;. Nada del otro mundo pero es importante no olvidarlo.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Cómo funciona todo el proceso completo
&lt;/h3&gt;

&lt;p&gt;En resumen, cada vez que haces push a main, GitHub se da cuenta automáticamente y arranca todo el proceso. Crea una máquina virtual con Ubuntu (que es gratis, por cierto), se conecta por SSH a tu VPS usando todas las credenciales que guardaste de forma segura, ejecuta el script que acabamos de ver y boom, tu proyecto queda desplegado con la última versión.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;¡Y ya está!&lt;/strong&gt; Te olvidas completamente de estar subiendo archivos a mano, de hacer FTP, de comprimir carpetas y toda esa marabunta. Cada vez que hagas un cambio en tu código y lo subas a GitHub, automáticamente se despliega en tu servidor. Es como magia pero que realmente entiendes cómo funciona.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;💡 Tip&lt;/strong&gt;: Puedes personalizar este workflow según tu proyecto. Por ejemplo, si usas React, podrías añadir pasos para hacer &lt;code&gt;npm install&lt;/code&gt; y &lt;code&gt;npm run build&lt;/code&gt; antes del despliegue.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Como ves este script es muy básico y puedes adaptarlo y mejorar muchísimo. Te animo a que lo hagas, y si realmente quieres o tienes dudas, no dudes en preguntarme en los comentarios y preparo un post centrado sólo en GitHub Actions y cómo hacer despliegues más avanzados.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;💡 Contenido relacionado&lt;/strong&gt;: Si quieres ver un ejemplo práctico de GitHub Actions en acción, he creado un post sobre &lt;a href="https://dev.to/altaskur/como-desplegar-angular-19-en-github-pages-desde-github-actions-9d8"&gt;cómo desplegar Angular 19 en GitHub Pages desde GitHub Actions&lt;/a&gt;, donde explico paso a paso un workflow completo para proyectos frontend.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Mejoras y optimizaciones avanzadas
&lt;/h2&gt;

&lt;p&gt;El workflow que acabamos de ver es funcional, pero hay muchas formas de mejorarlo. Aquí te dejo algunas ideas para que puedas expandir y optimizar tu setup:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;🔒 Nota importante de seguridad&lt;/strong&gt;: Este tutorial está enfocado en el aprendizaje y la funcionalidad básica. Para entornos de producción empresariales, considera implementar medidas adicionales como fail2ban, configuración de firewall más restrictiva, auditorías de seguridad regulares y políticas de acceso más estrictas.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  🚀 ¿Quieres que haga una segunda parte sobre despliegue avanzado?
&lt;/h2&gt;

&lt;p&gt;Estas son solo algunas ideas básicas. Si hay interés, puedo preparar un post completo cubriendo temas avanzados como&lt;/p&gt;

&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Seguridad avanzada&lt;/strong&gt;: Configuración de fail2ban, certificados SSL automáticos con Let's Encrypt, hardening del servidor&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Nginx avanzado&lt;/strong&gt;: Configuración como proxy inverso, configuración específica de proyectos, load balancing, optimización de performance
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monitoreo y logs&lt;/strong&gt;: Configuración de Grafana, Prometheus, gestión centralizada de logs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bases de datos&lt;/strong&gt;: Instalación y configuración de MySQL, PostgreSQL, MongoDB con backups automáticos&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dockerización completa&lt;/strong&gt;: Convertir todo el setup a contenedores Docker con Docker Compose&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CI/CD robusto&lt;/strong&gt;: Tests automáticos, análisis de código, despliegues con aprobación manual&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Entornos diferenciados&lt;/strong&gt;: Configuración entornos de desarrollo, staging y producción con GitHub Actions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;💡 Tip para proyectos robustos&lt;/strong&gt;: Si quieres asegurar la calidad de tu código antes del despliegue, te recomiendo configurar herramientas de linting y formateo. Tengo un post completo sobre &lt;a href="https://dev.to/altaskur/crear-un-proyecto-nuevo-con-eslint-stylelint-commitlint-y-husky-k6j"&gt;cómo crear un proyecto nuevo con ESLint, Stylelint, Commitlint y Husky&lt;/a&gt; que te ayudará a automatizar las verificaciones de calidad antes de cada commit.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;¡Comenta si te interesa alguno de estos temas y veré cuál es el que más demanda tiene para hacer la segunda parte!&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Solución de problemas comunes
&lt;/h2&gt;

&lt;p&gt;Cuando empiezas con despliegues en VPS, es normal que te encuentres con algunos problemas. Aquí te dejo los más comunes y cómo solucionarlos:&lt;/p&gt;

&lt;h3&gt;
  
  
  Error: "Permission denied" al hacer git pull
&lt;/h3&gt;

&lt;p&gt;Si tu workflow falla con errores de permisos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# En tu servidor, asegúrate de que el usuario deploy es el propietario&lt;/span&gt;
&lt;span class="nb"&gt;sudo chown&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; deploy:deploy /var/www/html/
&lt;span class="nb"&gt;sudo chmod&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; 755 /var/www/html/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Error: "Host key verification failed"
&lt;/h3&gt;

&lt;p&gt;Si GitHub Actions no puede conectarse por SSH:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# En tu servidor, regenera las claves SSH&lt;/span&gt;
ssh-keygen &lt;span class="nt"&gt;-R&lt;/span&gt; github.com
ssh-keyscan github.com &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; ~/.ssh/known_hosts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Nginx muestra "403 Forbidden"
&lt;/h3&gt;

&lt;p&gt;Si tu web no se ve correctamente:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Verifica los permisos de la carpeta web&lt;/span&gt;
&lt;span class="nb"&gt;sudo chmod&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; 755 /var/www/html/
&lt;span class="nb"&gt;sudo chown&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; www-data:www-data /var/www/html/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  El workflow se ejecuta pero no se actualiza la web
&lt;/h3&gt;

&lt;p&gt;Verifica que los archivos están en el lugar correcto:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Conecta por SSH y verifica&lt;/span&gt;
&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-la&lt;/span&gt; /var/www/html/[tu-proyecto]/
&lt;span class="c"&gt;# Si es un proyecto con build, asegúrate de copiar los archivos compilados a la carpeta correcta&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;🔧 Tip de debugging&lt;/strong&gt;: Siempre puedes conectarte por SSH a tu servidor después de un despliegue para verificar qué está pasando. Los logs de Nginx están en &lt;code&gt;/var/log/nginx/&lt;/code&gt; y puedes verlos con &lt;code&gt;sudo tail -f /var/log/nginx/error.log&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Conclusión
&lt;/h2&gt;

&lt;p&gt;El proceso te va a llevar poco tiempo. Calculo que unas 2 horas si es la primera vez que lo haces, pero una vez lo tengas montado, cada vez que hagas un cambio en tu proyecto y lo subas a GitHub, se desplegará automáticamente en tu servidor sin que tengas que hacer nada más.&lt;/p&gt;

&lt;p&gt;Y lo mejor de todo, te quitas de encima el miedo a que algo falle el día de la defensa. Tu proyecto estará siempre actualizado y funcionando, y tú podrás centrarte en lo que realmente importa: demostrar todo lo que has aprendido.&lt;/p&gt;

&lt;p&gt;Recuerda darle las gracias a &lt;a href="//Donweb.com"&gt;https://donweb.com/es-es/cloud-server-altaskur&lt;/a&gt; por el apoyo y por facilitarme un VPS para hacer las pruebas y capturas de este post. Si quieres probarlo, puedes crear una cuenta en &lt;a href="https://donweb.com/es-es/cloud-server-altaskur" rel="noopener noreferrer"&gt;DonWeb&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Y si tienes alguna duda o quieres que profundice en algún aspecto, ¡déjamelo en los comentarios!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>beginners</category>
      <category>devops</category>
      <category>spanish</category>
    </item>
    <item>
      <title>Cómo desplegar Angular 19 en GitHub Pages desde GitHub Actions</title>
      <dc:creator>Altaskur</dc:creator>
      <pubDate>Sun, 18 May 2025 15:02:11 +0000</pubDate>
      <link>https://forem.com/altaskur/como-desplegar-angular-19-en-github-pages-desde-github-actions-9d8</link>
      <guid>https://forem.com/altaskur/como-desplegar-angular-19-en-github-pages-desde-github-actions-9d8</guid>
      <description>&lt;h2&gt;
  
  
  Indice
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Plantilla del workflow&lt;/li&gt;
&lt;li&gt;Primer problema: &lt;strong&gt;Missing download info&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Segundo problema: &lt;strong&gt;¿Y si es mi custom domain?&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Tercer problema: &lt;strong&gt;¿Y si la ruta del proyecto?&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Cuarto paso y solución: &lt;strong&gt;¿Espera... qué estamos mandando al deploy?&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Conclusión&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;En los últimos directos estoy desarrollando una Pokédex funcional con Angular 19, y quería aprovechar la ocasión para mostrar el proceso completo, incluyendo cómo hacer el despliegue automático con GitHub Pages mediante GitHub Actions&lt;/p&gt;

&lt;p&gt;La idea era sencilla: que cada vez que terminara un directo y subiera cambios a la rama main, el proyecto se construyera automáticamente y se publicara en GitHub Pages. Algo más que suficiente para ir mostrando los avances sin tener que hacer deploys manuales.&lt;/p&gt;

&lt;p&gt;La idea era perfecta... hasta que empezaron los problemas.&lt;/p&gt;

&lt;p&gt;Como hacía tiempo que no montaba un flujo de despliegue con Angular y Pages, fui directo a buscar tutoriales (en pleno directo, claro 😅). Pero todos los que encontraba pedían configurar un token personal de GitHub para poder hacer el despliegue, y yo sabía —por experiencia— que eso ya no es necesario.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;💬 Este post refleja un proceso personal de aprendizaje mientras desarrollo un proyecto propio. No representa ninguna práctica oficial.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Plantilla del workflow
&lt;/h2&gt;

&lt;p&gt;Aquí te dejo la plantilla .yml que estoy utilizando y que puedes adaptar fácilmente a tu repositorio:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;🚀 Deploy Angular to GitHub Pages&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;main&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;workflow_dispatch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

&lt;span class="na"&gt;permissions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;contents&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;read&lt;/span&gt;
  &lt;span class="na"&gt;pages&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;write&lt;/span&gt;
  &lt;span class="na"&gt;id-token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;write&lt;/span&gt;

&lt;span class="na"&gt;concurrency&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;group&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;pages'&lt;/span&gt;
  &lt;span class="na"&gt;cancel-in-progress&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;🧾 Checkout repository&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;⚙️ Set up Node.js&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v4&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;node-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;
          &lt;span class="na"&gt;cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;npm'&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;📦 Install dependencies&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm ci&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;🛠️ Build Angular App&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npx ng build --configuration production --base-href "/[NOMBRE_DEL_REPOSITORIO]/"&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;🧩 Add .nojekyll file&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;echo "" &amp;gt; dist/[NOMBRE_DEL_PROYECTO]/browser/.nojekyll&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;📤 Upload Pages artifact&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/upload-pages-artifact@v3&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dist/[NOMBRE_DEL_PROYECTO]/browser&lt;/span&gt;

  &lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;needs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;build&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;⚙️ Setup GitHub Pages&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/configure-pages@v4&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;🚀 Deploy to GitHub Pages&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deployment&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/deploy-pages@v4&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Y no te olvides de ajustar el angular.json:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"options"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"outputPath"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"dist/[NOMBRE_DEL_PROYECTO]"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"baseHref"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/[NOMBRE_DEL_REPOSITORIO]/"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;😉 Ahora que ya tienes la solución funcional, voy a contarte todo lo que pasó para llegar hasta aquí.&lt;/p&gt;

&lt;h2&gt;
  
  
  Primer problema: &lt;strong&gt;Missing download info&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Al montar el workflow siguiendo algunos ejemplos que encontré por internet, me topé con el siguiente error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Missing download info &lt;span class="k"&gt;for &lt;/span&gt;actions/upload-pages-artifact@v3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Y claro, lo primero que pensé fue: ¿qué demonios significa esto? 🤯&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;upload-pages-artifact&lt;/code&gt; es una acción de GitHub que permite subir el contenido generado (por ejemplo, la carpeta &lt;code&gt;dist&lt;/code&gt; de Angular) para que otra acción, normalmente &lt;code&gt;deploy-pages&lt;/code&gt;, lo recoja y lo publique en GitHub Pages.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Hasta aquí todo bien, ¿no? Pues no.&lt;/p&gt;

&lt;p&gt;A fecha de creación de esta entrada, la última versión de deploy-pages es la v4, así que normalmente la invocas con:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/deploy-pages@v4&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pero aquí viene el plot twist: esta versión espera un formato de artefacto diferente al que genera &lt;code&gt;upload-pages-artifact@v2&lt;/code&gt;, que es el que aún aparece en muchos tutoriales y ejemplos.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Primer golpe de realidad: me costó un buen rato descubrirlo, así que tenlo en cuenta cuando estés consultando documentación desactualizada o siguiendo ejemplos de hace unos meses.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Segundo problema: &lt;strong&gt;¿Y si es mi custom domain?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Una vez solucionado el error anterior, la pipeline se ejecutaba correctamente y me lanzaba el siguiente mensaje:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Evaluate and &lt;span class="nb"&gt;set &lt;/span&gt;environment url
Evaluated environment url: http://altaskur.live/pokedex-angular/
Cleaning up orphan processes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;¡Perfecto! 🎉 Ya lo tenía. Podía visitar la URL y acceder al proyecto... o eso pensaba.&lt;/p&gt;

&lt;p&gt;Pero sorpresa: al acceder a la URL obtenía un 404.&lt;/p&gt;

&lt;p&gt;¿Perdona? Si la pipeline decía que el despliegue se había hecho correctamente... ¿por qué no puedo acceder?&lt;/p&gt;

&lt;p&gt;Mi primera sospecha fue que quizás el problema era el custom domain. GitHub Pages, por defecto, muestra las páginas usando la ruta [tu_usuario].github.io, pero puedes añadirle un dominio personalizado, como es mi caso (altaskur.live).&lt;/p&gt;

&lt;p&gt;¿Entonces no estaba bien configurado? 🤔&lt;/p&gt;

&lt;p&gt;Revisé otros proyectos que tengo activos usando GitHub Pages y todos estaban funcionando perfectamente. Así que descarté que el problema viniera del dominio.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tercer problema: &lt;strong&gt;¿Y si la ruta del proyecto?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;En este caso, el nombre del proyecto de Angular y el del repositorio en GitHub &lt;strong&gt;no coinciden&lt;/strong&gt;. Y pensé: ¿y si, al hacer el build, Angular está usando internamente el nombre del proyecto en lugar del nombre del repositorio?&lt;/p&gt;

&lt;p&gt;Entonces, al acceder a la URL del deploy con el nombre del repositorio, evidentemente no podría encontrar los archivos... lo que causaría un buen &lt;strong&gt;404&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;En mi cabeza tenía todo el sentido del mundo, así que me puse a investigar.&lt;/p&gt;

&lt;p&gt;Descubrí que en el archivo angular.json puedes establecer manualmente estos parámetros añadiendo lo siguiente:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"options"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"outputPath"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"dist/[NOMBRE_DEL_PROYECTO]"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"baseHref"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/[NOMBRE_DEL_REPOSITORIO]/"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hice los cambios, subí el proyecto y...&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sorpresa: otro 404.&lt;/strong&gt; 😩&lt;/p&gt;

&lt;p&gt;Ya estaba desesperado. Probé unas cuantas combinaciones, rutas distintas, incluso nombres en minúsculas… casi doy el proyecto por perdido.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hasta que…&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Cuarto paso y solución: &lt;strong&gt;¿Espera... qué estamos mandando al deploy?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Ya un poco harto, me puse a repasar conceptos.&lt;br&gt;
La pipeline se ejecutaba sin errores, el build se completaba correctamente... Entonces, ¿el problema está en el deploy?&lt;/p&gt;

&lt;p&gt;Lo siguiente que hice fue generar un build en local para ver qué estaba saliendo. En principio, todo parecía bien (aunque aquí estaba la clave, y yo aún no lo sabía).&lt;br&gt;
Dentro de la carpeta dist, vi un directorio llamado browser, y ahí estaba el proyecto transpilado, listo para desplegar.&lt;br&gt;
Lo abrí en el navegador: ¡todo funcionando! Bueno, salvo algún CORS... nada nuevo.&lt;/p&gt;

&lt;p&gt;¿Entonces qué puede estar pasando?&lt;/p&gt;

&lt;p&gt;Se me ocurrió entonces añadir unos logs al workflow para ver exactamente qué estaba subiendo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Check output directory&lt;/span&gt;
        &lt;span class="s"&gt;run&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ls -lah dist/pokedex&lt;/span&gt;

      &lt;span class="s"&gt;- name&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Check browser directory&lt;/span&gt;
        &lt;span class="s"&gt;run&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ls -lah dist/pokedex/browser&lt;/span&gt;

      &lt;span class="s"&gt;- name&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Show index.html&lt;/span&gt;
        &lt;span class="s"&gt;run&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cat dist/pokedex/browser/index.html || echo "index.html NOT FOUND"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Y ahí lo vi, como un mazazo:&lt;br&gt;
index.html NOT FOUND&lt;/p&gt;

&lt;p&gt;Fijándome bien, caí en la cuenta de algo que había pasado por alto: la carpeta browser.&lt;/p&gt;

&lt;p&gt;👀 Busqué información al respecto y, efectivamente, desde Angular 17, la estructura del build cambió y ahora el contenido a desplegar se encuentra dentro de esa carpeta browser.&lt;/p&gt;

&lt;p&gt;Solo tuve que modificar el yml, apuntar bien al nuevo path, quitar los logs…&lt;br&gt;
¡y por fin funcionando! 🎉&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusión
&lt;/h2&gt;

&lt;p&gt;Después de unos cuantos tropiezos, errores 404, pruebas en directo y mucho ensayo-error, por fin logré tener mi proyecto de Angular 19 desplegado automáticamente en GitHub Pages usando GitHub Actions.&lt;br&gt;
Y lo mejor de todo: sin tokens manuales ni pasos innecesarios.&lt;/p&gt;

&lt;p&gt;Lo que parecía una simple tarea de CI/CD terminó siendo una masterclass práctica de versiones, rutas, estructuras de build y pequeños detalles que cambian según la versión de Angular.&lt;/p&gt;

&lt;p&gt;Pero de eso se trata, ¿no? De ir aprendiendo a golpes... y luego dejarlo por escrito para no olvidarlo 😅.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;¿Te ha pasado algo parecido? ¿Has tenido que pelearte con GitHub Pages o las nuevas versiones de Angular?&lt;br&gt;
Cuéntamelo en los comentarios o compártelo si crees que a alguien más le puede ahorrar un buen rato.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Nos vemos en el siguiente directo, ¡o en el siguiente post! 👋&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>angular</category>
      <category>githubactions</category>
      <category>spanish</category>
    </item>
    <item>
      <title>Tipar automáticamente Swagger/OpenAPI endpoints con NSwag</title>
      <dc:creator>Altaskur</dc:creator>
      <pubDate>Sun, 30 Jun 2024 15:50:15 +0000</pubDate>
      <link>https://forem.com/altaskur/tipar-automaticamente-swaggeropenapi-endpoints-con-nswag-397g</link>
      <guid>https://forem.com/altaskur/tipar-automaticamente-swaggeropenapi-endpoints-con-nswag-397g</guid>
      <description>&lt;h1&gt;
  
  
  Tipar automáticamente Swagger/OpenAPI endpoints con NSwag
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;
Tipar automáticamente Swagger/OpenAPI endpoints con NSwag

&lt;ul&gt;
&lt;li&gt;¿Qué es NSwag?&lt;/li&gt;
&lt;li&gt;¿Qué necesitas?&lt;/li&gt;
&lt;li&gt;Instalación&lt;/li&gt;
&lt;li&gt;Configuración&lt;/li&gt;
&lt;li&gt;Generar Interfaces&lt;/li&gt;
&lt;li&gt;Final&lt;/li&gt;
&lt;li&gt;Redes&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Si alguna vez has tenido que tipar las respuestas de tus endpoints, sabrás que muchas veces es una tarea bastante difícil y larga. ¿Te imaginas poder hacerlo de manera automática y en pocos segundos? En este artículo, te explicaré cómo usar NSwag y cómo prepararlo para añadirlo a tus proyectos frontend.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Qué es NSwag?
&lt;/h2&gt;

&lt;p&gt;NSwag es una herramienta muy flexible que nos permite tipar automáticamente clientes API a partir del archivo de definición de OpenAPI, de una manera clara y precisa. Es especialmente útil para endpoints de cierta envergadura.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Qué necesitas?
&lt;/h2&gt;

&lt;p&gt;NSwag está creado en C#, por lo tanto, necesitarás tener instalado el Framework .NET completo 4.6.2+ o .NET 6.0+ en tu sistema. Al instalar el paquete npm, se verificarán los requisitos necesarios y, en caso de faltar alguno, se te proporcionará un enlace directo a la web oficial de Microsoft, así que no te preocupes por eso.&lt;/p&gt;

&lt;p&gt;Por supuesto, también necesitarás disponer de un Endpoint que cumpla con los estándares de Swagger/OpenAPI 2.0. Normalmente, estos archivos de definición Swagger se encuentran en la página de Swagger de tu endpoint, justo debajo del título.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqpcld1wyi5aslgmkcj9f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqpcld1wyi5aslgmkcj9f.png" alt=" " width="479" height="80"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nos interesa el archivo .json que contiene toda la documentación de nuestro backend y con el que NSwag va a trabajar.&lt;/p&gt;

&lt;p&gt;También disponemos de una interfaz gráfica para realizar la configuración, pero en nuestro caso nos vamos a enfocar en la generación manual a través de comandos, para así poder añadirlo al flujo de automatización.&lt;/p&gt;

&lt;h2&gt;
  
  
  Instalación
&lt;/h2&gt;

&lt;p&gt;Ahora vamos a añadir este paquete a nuestro repositorio. Dado que esta herramienta es una ayuda al desarrollo y no tiene impacto en la versión final del cliente, la añadiremos a las dependencias de desarrollo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;nswag &lt;span class="nt"&gt;--save-dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Durante el proceso de instalación, si no tienes instalado el framework .NET necesario (como el Framework .NET completo 4.6.2+ o .NET 6.0+), el asistente te pedirá que lo instales. También proporcionará un enlace directo a la web oficial de Microsoft para que puedas descargarlo e instalarlo fácilmente.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuración
&lt;/h2&gt;

&lt;p&gt;La herramienta va a consumir un archivo tipo config.nswag dónde añadiremos toda la configuración, en este artículo nos vamos a enfocar en sacar los tipados de nuestro endpoint, ya que la herramienta puede generar hasta las peticiones y los DTO del lenguaje, desde Typescript, a Angular, pasando por Jquery y C#&lt;/p&gt;

&lt;p&gt;Voy a ponerte un archivo base que llamaremos config.nswag:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"runtime"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Net80"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"defaultVariables"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"documentGenerator"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"fromDocument"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"[la dirección del swagger.json de tu endpoint]"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"output"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"newLineBehavior"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Auto"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"codeGenerators"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"openApiToTypeScriptClient"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"className"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"{controller}Client"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"moduleName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"namespace"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"typeScriptVersion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;5.4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"template"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Fetch"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"promiseType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Promise"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"httpClass"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"HttpClient"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"withCredentials"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"useSingletonProvider"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"injectionTokenType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"OpaqueToken"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"dateTimeType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Date"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"nullValue"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Undefined"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"generateClientClasses"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"generateClientInterfaces"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"generateOptionalParameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"exportTypes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"wrapDtoExceptions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"exceptionClass"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"SwaggerException"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"clientBaseClass"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"wrapResponses"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"generateResponseClasses"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"responseClass"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"SwaggerResponse"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"configurationClass"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"useTransformOptionsMethod"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"useTransformResultMethod"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"generateDtoTypes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"operationGenerationMode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"MultipleClientsFromOperationId"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"markOptionalProperties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"generateCloneMethod"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"typeStyle"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Interface"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"enumStyle"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Enum"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"useLeafType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"extensionCode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"generateDefaultValues"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"handleReferences"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"generateTypeCheckFunctions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"generateConstructorInterface"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"convertConstructorInterfaceData"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"importRequiredTypes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"useGetBaseUrlMethod"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"baseUrlTokenName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"API_BASE_URL"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"useAbortSignal"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"inlineNamedDictionaries"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"inlineNamedAny"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"includeHttpContext"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"templateDirectory"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"serviceHost"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"serviceSchemes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"output"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"src/app/api/interfaces.ts"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"newLineBehavior"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Auto"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Asegúrate de cambiar la url del from document, tanto local cómo externa&lt;br&gt;
y de cambiar el output de  codeGenerators a la ruta que prefieras para guardar los typos de tu endpoint.&lt;/p&gt;
&lt;h2&gt;
  
  
  Generar Interfaces
&lt;/h2&gt;

&lt;p&gt;Una vez tenemos el archivo de configuración podemos ejecutar nswag con el comando&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx nswag run ./config.nswag
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ahora podemos ir a la ruta de nuestro output y ver todos los tipos y enums de nuestro endpoint en nuestro caso sería src/app/api/interfaces.ts&lt;/p&gt;

&lt;h2&gt;
  
  
  Final
&lt;/h2&gt;

&lt;p&gt;Pero esta herramienta no se queda aquí, puedes generar los DTOs, las peticiones y hasta los servicios de tu endpoint, todo de manera automática y en pocos segundos.&lt;/p&gt;

&lt;p&gt;Si quieres saber más sobre esta herramienta, te recomiendo que visites la &lt;a href="https://github.com/RicoSuter/NSwag" rel="noopener noreferrer"&gt;documentación oficial&lt;/a&gt; de NSwag.&lt;/p&gt;

&lt;p&gt;¡Espero que te haya sido de ayuda! Si tienes alguna duda, no dudes en preguntar en los comentarios.&lt;/p&gt;

&lt;p&gt;Y no te olvides de seguirme en redes sociales para estar al tanto de todas las novedades.&lt;/p&gt;

&lt;h2&gt;
  
  
  Redes
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://twitter.com/altaskur" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.twitch.tv/altaskur" rel="noopener noreferrer"&gt;Twitch&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.instagram.com/altaskur/" rel="noopener noreferrer"&gt;Instagram&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.github.com/altaskur" rel="noopener noreferrer"&gt;Github&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.github.io/altaskur" rel="noopener noreferrer"&gt;Otras redes&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>typescript</category>
      <category>tutorial</category>
      <category>spanish</category>
    </item>
    <item>
      <title>Crear un proyecto nuevo con Eslint, Stylelint, CommitLint y Husky</title>
      <dc:creator>Altaskur</dc:creator>
      <pubDate>Fri, 21 Jun 2024 22:47:33 +0000</pubDate>
      <link>https://forem.com/altaskur/crear-un-proyecto-nuevo-con-eslint-stylelint-commitlint-y-husky-k6j</link>
      <guid>https://forem.com/altaskur/crear-un-proyecto-nuevo-con-eslint-stylelint-commitlint-y-husky-k6j</guid>
      <description>&lt;p&gt;En este artículo vamos a ver cómo configurar tu proyecto utilizando herramientas de revisión de código y vamos a modificar Git para que podamos ejecutar estas herramientas antes de subir nuestro código al repositorio, asegurándonos de mantener unas reglas, estructuras y configuraciones que homogenicen y limpien nuestro código.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;El comienzo&lt;/li&gt;
&lt;li&gt;Formateador Airbnb&lt;/li&gt;
&lt;li&gt;StyleLint y CommitLint&lt;/li&gt;
&lt;li&gt;Husky&lt;/li&gt;
&lt;li&gt;Package.json&lt;/li&gt;
&lt;li&gt;Integración con Husky&lt;/li&gt;
&lt;li&gt;Bonus Track: Comprobación de ramas&lt;/li&gt;
&lt;li&gt;Repositorio de ejemplo&lt;/li&gt;
&lt;li&gt;Final&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  El comienzo
&lt;/h2&gt;

&lt;p&gt;Para comenzar, me centraré en el uso de Angular, esta configuración puedes adaptarla fácilmente en los frameworks más populares cómo React, Vite y Astro.&lt;/p&gt;

&lt;p&gt;En este artículo vamos a usar la última versión de Angular disponible al momento de escribirlo, que es la 18. Para ello, comenzaremos creando nuestro proyecto usando:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ng new proyectoArticulo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;Asegúrate de cambiar "proyectoArticulo" por el nombre que desees utilizar. Sigamos los pasos del Angular CLI. No es el objetivo de este artículo explicarte cómo funciona el CLI de Angular, así que te mostraré la configuración que he elegido para el proyecto:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;He utilizado SCSS y no vamos a usar SSR.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Una vez finalice la creación del proyecto, pasamos a instalar la integración de ESLint con Angular usando el esquema @angular-eslint/schematics. Esta es una herramienta para el CLI de Angular, por lo que usaremos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ng add @angular-eslint/schematics
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;De esta manera, al usar ng lint, directamente nos saltará ESLint.&lt;/p&gt;

&lt;p&gt;Una vez instalado el Angular schematics, pasamos a la instalación de ESLint. Es muy popular el uso de Prettier cómo formateador de código junto a ESLint. Aunque este último puede modificarse, personalmente prefiero usar ESLint con las normas de formateo de Airbnb. Esta es una preferencia totalmente personal y es la que usaremos en el artículo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Formateador Airbnb
&lt;/h2&gt;

&lt;p&gt;Para instalar ESLint junto a las normas de Airbnb, necesitaremos un listado de paquetes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;eslint-config-airbnb-base eslint-config-airbnb-typescript eslint-plugin-simple-import-sort &lt;span class="nt"&gt;--save-dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;Como ves, las estamos guardando en dev, ya que estas dependencias solo nos interesan en desarrollo y no tiene sentido añadirlas a la versión de producción.&lt;/p&gt;

&lt;p&gt;¿Qué son todas estas dependencias? Hemos añadido la normativa de Airbnb a ESLint, la variante para TypeScript, y el último paquete es para ordenar las importaciones.&lt;/p&gt;

&lt;p&gt;Una vez tengamos esto, podrás ver que se ha creado el archivo .eslintrc.json, que es el que usa ESLint para guardar su configuración.&lt;/p&gt;

&lt;p&gt;Si utilizas “_” para declarar valores que no se van a usar, te recomiendo que añadas dentro de overrides &amp;gt;&amp;gt; rules:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"@typescript-eslint/no-unused-vars"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="s2"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"argsIgnorePattern"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^_"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"varsIgnorePattern"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^_"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;Ahora vamos a configurar la extensión simple-import-sort que hemos instalado anteriormente y, además, vamos a compatibilizar un poco las reglas de Airbnb con el convenio de Angular deshabilitando los default imports. Al igual que el paso anterior, esto va dentro de rules:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"simple-import-sort/imports"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"error"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"simple-import-sort/exports"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"error"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"import/prefer-default-export"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"off"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;Ahora añadimos a ESLint que use los paquetes que hemos descargado de Airbnb. Dentro de extends añadimos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="s2"&gt;"airbnb-base"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="s2"&gt;"airbnb-typescript/base"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;Una vez instalado ESLint, le indicaremos que ignore las carpetas node_modules y dist para evitar problemas tanto en las librerías como en el bundle de dist. Para ello, creamos el archivo .eslintignore y añadimos estas dos carpetas, similar a como haríamos con .gitignore, quedando así:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dist
node_modules
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  StyleLint y CommitLint
&lt;/h2&gt;

&lt;p&gt;Una vez tenemos esto, vamos a instalar StyleLint y CommitLint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save-dev&lt;/span&gt; stylelint stylelint-config-standard-scss
npm &lt;span class="nb"&gt;install&lt;/span&gt; @commitlint/cli @commitlint/config-conventional &lt;span class="nt"&gt;--save-dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;Verás que se ha añadido la carpeta de configuración de StyleLint al estilo de ESLint, pero en cambio para CommitLint no. Así que vamos a crearla:&lt;/p&gt;

&lt;p&gt;Creamos el archivo &lt;code&gt;.commitlintrc.json&lt;/code&gt; y dentro de este archivo debemos poner:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"extends"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"@commitlint/config-conventional"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Husky
&lt;/h2&gt;

&lt;p&gt;Ahora vamos a instalar la herramienta que nos permite utilizar los hooks de Git para comprobar que todo nuestro código pasa las normas establecidas antes de subirlo al repositorio. Para ello, usaremos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx husky-init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;El comando nos pedirá instalar la dependencia de Husky, por lo tanto, le decimos que sí. Una vez instalada, en el directorio raíz de nuestro proyecto tendremos la carpeta .husky con varios archivos dentro. El que nos interesa es &lt;code&gt;pre-commit&lt;/code&gt;. Si lo abres, tendrás algo similar a esto:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# !/usr/bin/env sh&lt;/span&gt;
&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;dirname&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;/_/husky.sh"&lt;/span&gt;
npm &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;Como puedes ver, esto ejecutaría el comando npm test de nuestro proyecto antes de hacer el commit, y si estos presentan algún error, no nos dejará hacer el commit. Ahora nos faltaría añadir los formateadores de código.&lt;/p&gt;

&lt;h2&gt;
  
  
  Package.json
&lt;/h2&gt;

&lt;p&gt;Ahora vamos a crear nuestros propios comandos para que Husky pueda ejecutarlos de una manera limpia. Para ello, nos dirigimos al archivo &lt;code&gt;package.json&lt;/code&gt; y dentro de la propiedad scripts añadimos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"lint:fix"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ng lint --fix"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"lint:scss"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"stylelint src/**/*.scss"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;Ahora tenemos nuestros linters preparados tanto para comprobar los archivos cómo para forzar estos cambios al subirlos al repositorio.&lt;/p&gt;

&lt;h2&gt;
  
  
  Integración con Husky
&lt;/h2&gt;

&lt;p&gt;Vamos a añadir estas sentencias a Husky. Para ESLint es bastante sencillo, ya que solo necesitamos dirigirnos al archivo pre-commit del directorio &lt;code&gt;.husky&lt;/code&gt; y añadir:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run lint
npm run lint:scss
npm run &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;Tendrás algo cómo esto dentro del directorio &lt;code&gt;.husky/pre-commit&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# !/usr/bin/env sh&lt;/span&gt;

&lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;dirname&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;/_/husky.sh"&lt;/span&gt;

npm run lint
npm run lint:scss
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;Te preguntarás que pasó con CommitLint, para este último necesitamos añadirlo a través de la utilidad de comando de Husky para ello ejecutamos:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx husky add .husky/commit-msg  &lt;span class="s1"&gt;'npx --no --commitlint --edit ${1}'&lt;/span&gt;     
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;¿Por qué está dentro de commit-msg y no dentro de  pre-commit como todo lo anterior?&lt;/p&gt;

&lt;p&gt;El hook &lt;code&gt;commit-msg&lt;/code&gt; se enfoca en la validación del mensaje de commit este se ejecuta después de que el mensaje de commit ha sido introducido, pero antes de que el commit sea finalizado, además de que nos permite obtener el nombre y el mensaje del commit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bonus Track: Comprobación de ramas
&lt;/h2&gt;

&lt;p&gt;Es frecuente que no quieras subir los cambios directamente a tu repositorio y que estos sean aprobados mediante una pull request. Para esto, podemos crear nuestro propio script para comprobar en qué rama estamos y si podemos o no hacer commit.&lt;/p&gt;

&lt;p&gt;Dentro de la carpeta .husky, añadimos el archivo &lt;code&gt;prevent-commit.sh&lt;/code&gt; y dentro de este añadimos el siguiente código en sh:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# !/bin/sh&lt;/span&gt;

&lt;span class="nv"&gt;branch_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;git symbolic-ref &lt;span class="nt"&gt;--short&lt;/span&gt; HEAD&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$branch_name&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; feature&lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$branch_name&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="nb"&gt;test&lt;/span&gt;&lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Commits are only allowed on feature and test branches. Current branch: &lt;/span&gt;&lt;span class="nv"&gt;$branch_name&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;Como puedes ver, en la sentencia if he especificado que solo se pueda hacer commit en el caso de que la rama comience con feature o test, siguiendo siempre la estructura base de los conventional commits. Recuerda que puedes ampliarlo o cambiarlo según tu gusto o necesidad.&lt;/p&gt;

&lt;p&gt;Ahora para ejecutar nuestro .sh debemos añadirlo al hook de &lt;code&gt;commit-msg&lt;/code&gt; añadiendo la siguiente línea&lt;/p&gt;

&lt;p&gt;&lt;code&gt;bash .husky/prevent-commit.sh&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Repositorio de ejemplo
&lt;/h2&gt;

&lt;p&gt;Te dejo un enlace a un proyecto de GitHub vacío con la configuración que acabas de ver:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/altaskur/AngularConventionalCommitsTemplate" rel="noopener noreferrer"&gt;AngularConventionalCommitsTemplate&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Final
&lt;/h2&gt;

&lt;p&gt;Con este artículo tienes una estructura completa y avanzada del uso de linters y hooks de Git en un repositorio de Angular.&lt;/p&gt;

&lt;p&gt;Espero que te haya sido de ayuda y que puedas aplicar estas configuraciones en tus proyectos. Si tienes alguna duda o sugerencia, no dudes en dejar un comentario.&lt;/p&gt;

&lt;p&gt;¿Y tú? ¿Utilizas linters en tus proyectos? ¿Qué herramientas utilizas? ¡Déjame tu opinión en los comentarios!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>spanish</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Figma, Auto Layout</title>
      <dc:creator>Altaskur</dc:creator>
      <pubDate>Mon, 01 Apr 2024 14:29:14 +0000</pubDate>
      <link>https://forem.com/altaskur/figma-auto-layout-138k</link>
      <guid>https://forem.com/altaskur/figma-auto-layout-138k</guid>
      <description>&lt;h1&gt;
  
  
  Figma Auto Layout
&lt;/h1&gt;

&lt;p&gt;Continuamos con la serie de Figma; este tutorial es la continuación de &lt;a href="https://dev.to/altaskur/figma-conociendo-la-interfaz-1ijn"&gt;Figma, conociendo la interfaz&lt;/a&gt;. Te recomiendo encarecidamente que, si no lo has visto, lo veas primero.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
Figma Auto Layout

&lt;ul&gt;
&lt;li&gt;Introducción&lt;/li&gt;
&lt;li&gt;Crear un Auto Layout&lt;/li&gt;
&lt;li&gt;Crear un frame&lt;/li&gt;
&lt;li&gt;Modificando el frame&lt;/li&gt;
&lt;li&gt;Propiedades de Auto Layout&lt;/li&gt;
&lt;li&gt;Flechas de dirección&lt;/li&gt;
&lt;li&gt;Espaciado entre elementos (Gap)&lt;/li&gt;
&lt;li&gt;Padding o borde interno&lt;/li&gt;
&lt;li&gt;
Panel de alineación

&lt;ul&gt;
&lt;li&gt;Centrar elementos&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Barra de navegación&lt;/li&gt;

&lt;li&gt;Ajustar tamaño del frame a un contenedor Auto Layout&lt;/li&gt;

&lt;li&gt;Conclusión&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Introducción
&lt;/h2&gt;

&lt;p&gt;Una de las características principales de Figma es la capacidad de crear diseños escalables y hacer que los elementos se coloquen automáticamente en el contenedor.&lt;/p&gt;

&lt;p&gt;Esta característica se llama Auto Layout y es tremendamente útil. Olvídate de tener que colocar los elementos manualmente; de esta manera, estarán perfectamente alineados y distribuidos.&lt;/p&gt;

&lt;p&gt;Vamos a ver cómo funciona.&lt;/p&gt;

&lt;h2&gt;
  
  
  Crear un Auto Layout
&lt;/h2&gt;

&lt;p&gt;Para indicarle a un frame que los elementos que contiene deben colocarse automáticamente, debemos seleccionar el frame y hacer clic en el botón de Auto Layout. En este ejemplo, vamos a crear una barra de navegación superior con tres elementos: un logo, un texto y un menú.&lt;/p&gt;

&lt;h2&gt;
  
  
  Crear un frame
&lt;/h2&gt;

&lt;p&gt;Vamos a crear un frame. Podemos hacerlo haciendo clic en el icono de Frame en la barra de herramientas o pulsando la tecla F.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuxuc4192f6tq6c862ll6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuxuc4192f6tq6c862ll6.png" alt="Barra de herramientas superior" width="405" height="51"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Siempre que creemos un frame, vamos a renombrarlo para que sea más fácil identificarlo. Es importante tener una buena convención de nombres desde el principio. En este caso, Barra de navegación. Créeme, esto es muy importante; si no cuidas bien el naming, se te va a ir el proyecto de las manos rápidamente.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0cjsodi1lr6vg76l3jz1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0cjsodi1lr6vg76l3jz1.png" alt="Frame renombrado" width="250" height="155"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Fíjate en que en la imagen de la barra izquierda de Figma, aparece el icono de una almohadilla # y el nombre del frame. Quédate con este detalle; según el tipo de elemento o las propiedades que tenga, este icono cambiará. De este modo, de un simple vistazo, podemos hacernos una idea de la disposición de los elementos.&lt;/p&gt;

&lt;h2&gt;
  
  
  Modificando el frame
&lt;/h2&gt;

&lt;p&gt;Una vez que tenemos nuestro frame, vamos a darle un pequeño borde para poder verlo mejor, ya que ahora mismo es invisible.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkspit0fzm3zwfcftuamx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkspit0fzm3zwfcftuamx.png" alt="Frame sin borde con el tamaño predeterminado" width="429" height="221"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Esta vez nos dirigimos a la barra de propiedades o CSS, y nos dirigimos al &lt;code&gt;&lt;/code&gt;+&lt;code&gt;&lt;/code&gt; de la sección de Stroke para añadir un borde predeterminado.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmwskfr9cf1hn46cb7530.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmwskfr9cf1hn46cb7530.png" alt="Frame con un stroke predeterminado" width="231" height="341"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ahora veremos que tiene un borde de 1px de color negro puro.&lt;/p&gt;

&lt;p&gt;Nos vamos al panel de opciones y al igual que hicimos con el borde, nos dirigimos a la barra de propiedades y hacemos clic en el &lt;code&gt;+&lt;/code&gt; de Auto Layout.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F52mb0zf9aakuo4y1eeo9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F52mb0zf9aakuo4y1eeo9.png" alt="Propiedades de auto layout" width="236" height="217"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Propiedades de Auto Layout
&lt;/h2&gt;

&lt;p&gt;Antes de irnos a las propiedades del Auto Layout, tenemos que fijarnos en algo que acaba de cambiar y que normalmente solemos pasar por alto. En el panel de propiedades del Frame, justo donde se indica el ancho W y el alto H (Weight y Height en inglés), veremos la palabra "Hug" abrazo en inglés.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Auto layout coloca el tamaño del frame adaptable de forma predeterminada.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzf92732sopryxm13oefz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzf92732sopryxm13oefz.png" alt="Panel de tamaño del frame" width="239" height="213"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;¿Por qué abrazo? Porque nuestro frame se va a adaptar al tamaño de los elementos que contiene, "abrazándolos", comportándose como una envoltura. Vamos a cambiar esto y a decirle que queremos un ancho fijo.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4pdxblyjnt8nth6kbgtn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4pdxblyjnt8nth6kbgtn.png" alt="Propiedades de ancho en un elemento auto layout" width="208" height="180"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flga7i8lg9fsrdzjav7zg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flga7i8lg9fsrdzjav7zg.png" alt="Un frame con Auto layout con ancho fijo" width="238" height="200"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ahora que ya tenemos nuestro Frame con Auto Layout y con un ancho fijo, vamos a añadir los elementos que va a contener. Creamos tres Frames de 20 x 20, con un Fill de color negro y los llamamos Logo, Texto y Menú.&lt;/p&gt;

&lt;p&gt;Te tiene que quedar algo así:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4qmu3sotyjqr59397adi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4qmu3sotyjqr59397adi.png" alt=" " width="243" height="222"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fagqs52nfmgg4ele28w1n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fagqs52nfmgg4ele28w1n.png" alt="Elementos en vertical" width="145" height="136"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Una vez tengamos esto, vamos a dirigirnos al panel de propiedades y continuamos desde ahí.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F52mb0zf9aakuo4y1eeo9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F52mb0zf9aakuo4y1eeo9.png" alt="Propiedades de auto layout" width="236" height="217"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Flechas de dirección
&lt;/h3&gt;

&lt;p&gt;En el panel de Auto Layout, verás tres flechas de dirección: hacia abajo, hacia la izquierda y otra que parece volver al punto de inicio. Con esto te puedes ir haciendo una idea de su funcionalidad. Estas flechas le dicen al Frame de qué manera se van a colocar los elementos que va a contener.&lt;br&gt;
Si vienes de un perfil de desarrollo, esta opción en CSS es igual que la propiedad flex-direction.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Orientación&lt;/th&gt;
&lt;th&gt;Flecha&lt;/th&gt;
&lt;th&gt;Panel&lt;/th&gt;
&lt;th&gt;Resultado&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Vertical&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzyujjn346f8o9xgvm6tu.png" alt="Flecha vertical" width="84" height="43"&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm3t9xccc1rjfi4fyzouf.png" alt=" " width="77" height="77"&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fagqs52nfmgg4ele28w1n.png" alt="Elementos en vertical" width="145" height="136"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Horizontal&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Favyh3hlt6e5zx154q58t.png" alt="Flecha horizontal" width="85" height="35"&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc805ib3hhaqb7su9cbdw.png" alt="Panel horizontal" width="74" height="80"&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk7vdcfh3m1gd37b0jma5.png" alt="elementos horizontal" width="131" height="137"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Adaptable&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4m4b7p2o0qmuaemtigmm.png" alt="Flecha adaptativa" width="75" height="38"&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9wb91daoxsm70tq1zt2i.png" alt="Panel adaptativo" width="91" height="79"&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk7vdcfh3m1gd37b0jma5.png" alt="elementos horizontal" width="131" height="137"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Como puedes ver en la tabla anterior, las flechas de dirección nos indican cómo se va a colocar y en el panel de Auto Layout podemos ver que el icono de color azul cambia según la orientación que le hayamos dado.&lt;/p&gt;

&lt;p&gt;¿Recuerdas que te dije que te fijaras en el icono de la barra izquierda? Pues es el mismo icono que aparece en el panel de propiedades. De esta manera, podemos saber de un simple vistazo la disposición de los elementos.&lt;/p&gt;

&lt;p&gt;Pero esto no es todo. En el panel de Auto layout, podemos ver que existen más opciones: Horizontal Gap, Horizontal padding y Vertical padding. Estas opciones nos permiten ajustar la separación entre los elementos (Gap) y el espacio que hay sobre y debajo de los elementos (Padding).&lt;/p&gt;

&lt;p&gt;Si vienes del desarrollo, esto te sonará bastante, ¿verdad? Es exactamente el mismo comportamiento que la propiedad Flexbox de CSS.&lt;/p&gt;

&lt;p&gt;En cambio, si vienes del diseño, cómo ves, ya te estás familiarizando con los conceptos de desarrollo sin darte cuenta, además de hacer la vida más fácil para el desarrollo. Ahora vamos a identificar estos elementos y a ver cómo se comportan.&lt;/p&gt;

&lt;h3&gt;
  
  
  Espaciado entre elementos (Gap)
&lt;/h3&gt;

&lt;p&gt;Cómo hemos visto antes, el "Gap" es el espacio horizontal que hay entre los elementos. Para modificarlo, tenemos que hacer clic en el número que aparece al lado del icono de Gap y escribir el valor que queremos. En este caso, vamos a poner 20.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdkqs8lot1yrglekx6trv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdkqs8lot1yrglekx6trv.png" alt="Panel de Auto Layout, con el foco puesto en Gap" width="222" height="141"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Fíjate bien mientras escribes el valor o lo estás modificando; resulta que en el elemento en sí va a aparecer unas líneas de color rosa que te indican el espacio que va a haber entre los elementos. Este detalle suele pasar desapercibido, pero es realmente útil y está presente en muchos de los elementos de Figma.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Mientras modificas las propiedades de un elemento, Figma te muestra una vista previa de los cambios, en rosa.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F190uqiz4m1c464m8obrc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F190uqiz4m1c464m8obrc.png" alt="Previsualización de gap" width="136" height="144"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Con esta modificación, acabamos de provocar un desbordamiento en nuestro diseño, ya que el Frame no tiene el tamaño suficiente para contener los elementos, provocando que la parte que va sobrando se oculte.&lt;br&gt;
En desarrollo, esto se conoce como overflow; en Figma, por defecto, lo tenemos en hidden, oculto.&lt;br&gt;
Para cambiar esta propiedad, por ejemplo para hacer un scroll, tenemos que ir a la propiedad de Clip content y desactivarla.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd1oo6z4pttycl9bdxgsp.png" alt=" " width="232" height="192"&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff5u124un30t9xtxd7ehj.png" alt=" " width="139" height="135"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;De esta manera podemos ver el desbordamiento.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbeftuchgerdrfob2dslg.png" alt=" " width="234" height="187"&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fra47yaho1zdkpz1xi3xd.png" alt=" " width="159" height="145"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;Clip content oculta el contenido que se desborda del frame. Es igual que la propiedad overflow de CSS.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Padding o borde interno
&lt;/h3&gt;

&lt;p&gt;El padding es el espacio que hay entre el borde del frame y los elementos que contiene.&lt;br&gt;
Lo podemos identificar en el panel de Auto Layout, justo debajo de gap con los iconos de un cuadrado entre líneas. Según la orientación de las líneas, nos indica si el padding es horizontal o vertical.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8i7iqsjq7emnmz1r5prb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8i7iqsjq7emnmz1r5prb.png" alt=" " width="222" height="43"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Además, tenemos un tercer icono; este nos permite modificar el padding de cada uno de los lados del frame de manera independiente. Si hacemos clic en el icono, veremos que aparecen cuatro campos de texto, uno para cada lado del frame.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fehddx116jcsx3o1mgpk9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fehddx116jcsx3o1mgpk9.png" alt=" " width="221" height="68"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Cómo puedes ver, el icono del cuadrado se mantiene, representando al frame, solo que ahora hay una sola línea representando el padding de cada lado.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;El padding es el espacio que hay entre el borde del frame y los elementos que contiene.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Intenta jugar con el padding y el gap para entender cómo se comportan y afectan a los elementos.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpvw4sjbve8iuxjbod3uz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpvw4sjbve8iuxjbod3uz.png" alt=" " width="126" height="147"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Quiero recordarte que si mantienes el ratón en la propiedad que estás modificando, Figma te muestra una previsualización de los cambios que estás realizando.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Recuerda que Figma te muestra una previsualización de los cambios que estás realizando.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Panel de alineación
&lt;/h3&gt;

&lt;p&gt;¿Qué ocurre si queremos centrar los elementos en el frame o queremos separarlos de manera uniforme? Pues para eso tenemos el panel de alineación, que nos permite alinear los elementos de manera uniforme, centrarlos o separarlos de manera uniforme.&lt;br&gt;
Si vienes del desarrollo, esto te sonará a la propiedad justify-content y align-items de CSS.&lt;/p&gt;

&lt;p&gt;Ahora veremos cómo se comporta el panel de alineación. Vamos a centrar los elementos en el frame y, por último, separarlos de manera uniforme. Así podremos crear nuestro menú de navegación.&lt;/p&gt;

&lt;h4&gt;
  
  
  Centrar elementos
&lt;/h4&gt;

&lt;p&gt;El panel de alineación es muy intuitivo; dentro de él, verás que tienes distintos puntos. Cada punto representa el alineamiento de los elementos. Si queremos centrar los elementos en el frame, tenemos que hacer clic en el punto central.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Panel&lt;/th&gt;
&lt;th&gt;Resultado&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiofyzeiz8ze0ofzbmgw5.png" alt=" " width="79" height="78"&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6zrpknkgf9q113322iiy.png" alt=" " width="143" height="128"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Te recomiendo que juegues con las distintas opciones para que veas cómo se comportan los elementos.&lt;/p&gt;

&lt;p&gt;Ahora bien, necesitamos que nuestra barra de navegación se adapte a los elementos de su tamaño; de esta manera, tendremos un frame responsive teniendo un frame a la izquierda, otro a la derecha y el logotipo en el centro.&lt;/p&gt;

&lt;p&gt;Para ello, seleccionamos el punto central y hacemos doble clic. De esta manera, los elementos se adaptarán al tamaño del frame. En desarrollo, esto es igual a la propiedad space-between de CSS.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Panel&lt;/th&gt;
&lt;th&gt;Resultado&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv3zdaa8t4czrxrcl3rp6.png" alt=" " width="228" height="155"&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhoau0quxhacehoijquvn.png" alt=" " width="124" height="128"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Aquí puedes ver que han pasado varias cosas. Aparte de alinearse los elementos adaptándose al contenedor, el gap ha cambiado a Auto, indicando esto mismo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Barra de navegación
&lt;/h2&gt;

&lt;p&gt;Ahora solo tenemos que adaptar el frame al tamaño de nuestro diseño. Recuerda que usamos el preset del iPhone 13 &amp;amp; 14.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr5zf8boc0o45bfwuzhq4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr5zf8boc0o45bfwuzhq4.png" alt=" " width="418" height="200"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Te dejo las propiedades del frame para que puedas replicar el diseño.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fim6qr9iu4wtn9gteb5n1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fim6qr9iu4wtn9gteb5n1.png" alt=" " width="228" height="192"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ahora bien, según lo que acabamos de ver, ¿no te parece raro tener que alinear nuestra barra de navegación al frame principal? Si a nuestro frame principal le establecemos cómo auto layout, podemos hacer que nuestra barra de navegación se acomode al frame principal, haciendo ahora nuestro diseño responsive.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4p8h3646dbyjo5wmck0l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4p8h3646dbyjo5wmck0l.png" alt=" " width="272" height="215"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F27tidykqmploplrbd87q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F27tidykqmploplrbd87q.png" alt=" " width="229" height="154"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Solo nos quedaría decirle a nuestro frame Barra de navegación que se adapte al tamaño del frame principal. ¿Cómo hacemos esto?&lt;/p&gt;

&lt;h3&gt;
  
  
  Ajustar tamaño del frame a un contenedor Auto Layout
&lt;/h3&gt;

&lt;p&gt;Si seleccionamos nuestra barra de navegación y hacemos clic en el ancho w (width en inglés), veremos que aparece una nueva opción, Fill container. Si hacemos clic en esta opción, nuestro frame se adaptará al tamaño del frame principal, siempre y cuando este tenga Auto Layout.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbv7ypvulq9s5utyz84vm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbv7ypvulq9s5utyz84vm.png" alt=" " width="235" height="192"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqdcquxkiv6bihku06p7a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqdcquxkiv6bihku06p7a.png" alt=" " width="235" height="183"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Al activar esta opción, la propiedad de ancho quedará "desactivada", y el frame se adaptará al tamaño del frame principal. ¿Probamos a cambiar el tamaño del frame principal a ver qué pasa?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkm1s9fccdyb2hleou3cj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkm1s9fccdyb2hleou3cj.png" alt=" " width="223" height="210"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Cómo puedes ver, el frame se adapta al tamaño del frame principal. De esta manera, podemos hacer que nuestro diseño sea totalmente responsive.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhleon834ajkakq3p6cfl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhleon834ajkakq3p6cfl.png" alt=" " width="795" height="126"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusión
&lt;/h2&gt;

&lt;p&gt;Con esto, ya tendríamos nuestro diseño responsive, con una barra de navegación que se adapta al tamaño de nuestro diseño.&lt;/p&gt;

&lt;p&gt;¿Qué te ha parecido? ¿Te ha resultado útil? ¿Quieres que hable de algo en concreto? ¡Déjamelo en los comentarios!&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>beginners</category>
      <category>design</category>
      <category>spanish</category>
    </item>
    <item>
      <title>Figma, Conociendo la interfaz</title>
      <dc:creator>Altaskur</dc:creator>
      <pubDate>Thu, 28 Mar 2024 19:41:54 +0000</pubDate>
      <link>https://forem.com/altaskur/figma-conociendo-la-interfaz-1ijn</link>
      <guid>https://forem.com/altaskur/figma-conociendo-la-interfaz-1ijn</guid>
      <description>&lt;h1&gt;
  
  
  Figma, Conociendo la interfaz
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;
Figma, Conociendo la interfaz

&lt;ul&gt;
&lt;li&gt;Contenido de la entrada&lt;/li&gt;
&lt;li&gt;¿Qué es Figma?&lt;/li&gt;
&lt;li&gt;¿Por qué hacer esta entrada?&lt;/li&gt;
&lt;li&gt;¿Qué diferencia a Figma de otras herramientas de diseño?&lt;/li&gt;
&lt;li&gt;Introducción ¿Cómo diablos consigue esto?&lt;/li&gt;
&lt;li&gt;¿Cómo empezar a utilizar Figma?&lt;/li&gt;
&lt;li&gt;Ui del home de Figma&lt;/li&gt;
&lt;li&gt;Un nuevo proyecto, interfaz de Figma&lt;/li&gt;
&lt;li&gt;Comenzamos a trabajar en Figma&lt;/li&gt;
&lt;li&gt;Modificando Frames&lt;/li&gt;
&lt;li&gt;Alineación&lt;/li&gt;
&lt;li&gt;Posición&lt;/li&gt;
&lt;li&gt;Auto layout y Grid layout&lt;/li&gt;
&lt;li&gt;Capas o &lt;code&gt;layers&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Fill, Stroke y Effects&lt;/li&gt;
&lt;li&gt;Export&lt;/li&gt;
&lt;li&gt;Final&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Contenido de la entrada
&lt;/h2&gt;

&lt;p&gt;En esta entrada vamos a explorar qué es Figma, por qué es tan popular y cómo empezar a utilizarlo. También planeo agregar más entradas explicando las distintas funcionalidades de Figma, como la creación de componentes, estilos, etc. El objetivo es proporcionar una guía en capítulos cortos y fáciles de seguir.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Qué es Figma?
&lt;/h2&gt;

&lt;p&gt;Lo primero que debes saber es: ¿Qué es Figma? Si no has estado viviendo bajo una piedra, probablemente hayas escuchado sobre Figma, pero si necesitas una explicación, aquí va. Figma es una herramienta de diseño de interfaces que funciona como una aplicación web, lo que significa que no necesitas instalar nada en tu ordenador. Esta característica te permite trabajar desde cualquier lugar y en cualquier plataforma, siempre y cuando tengas acceso a Internet.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🫡💻 No necesitas instalar nada en tu ordenador.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  ¿Por qué hacer esta entrada?
&lt;/h2&gt;

&lt;p&gt;Uso Figma casi todos los días y me gustaría tener una guía de referencia para consultas rápidas y para ayudar a cualquier persona que quiera comenzar a utilizar Figma.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Entrada no patrocinada 😅 que ya quisiera yo.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  ¿Qué diferencia a Figma de otras herramientas de diseño?
&lt;/h2&gt;

&lt;p&gt;Figma tiene varias ventajas, pero la principal, en mi opinión, es su enfoque orientado a la programación. Esto significa que tiene funcionalidades que acercan el diseño al flujo de trabajo de la programación.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introducción ¿Cómo diablos consigue esto?
&lt;/h2&gt;

&lt;p&gt;Si tienes el perfil de diseño, la idea de "programación" puede intimidarte un poco 😅, pero no te preocupes, Figma está diseñado para hacerlo accesible para todos.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;No te asustes, no es tan complicado.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Figma está orientado al diseño de componentes, tokens, variables, etc. 👀 Esto significa que puedes crear componentes y reutilizarlos en diferentes partes de tu diseño, además de poder crear estilos globales que se pueden modificar en un solo lugar.&lt;/p&gt;

&lt;p&gt;Esto agiliza el trabajo y garantiza un diseño más consistente y escalable. (Olvida la necesidad de copiar y pegar el mismo botón mil veces y tener que modificarlo en mil lugares diferentes).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Realizas un cambio y se refleja en todos los lugares.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Además, Figma cuenta con una función llamada "Auto layout" que ajusta automáticamente los elementos al contenido que contienen. 🤯&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Los elementos se ajustan automáticamente al contenido que contienen.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;También puedes trabajar de forma colaborativa y en tiempo real con otras personas, dejar comentarios, controlar versiones y marcar elementos como listos para pasar a desarrollo o no.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Puedes trabajar en tiempo real con otras personas.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Por último, puedes preparar tus diseños para crear presentaciones interactivas sin necesidad de escribir una sola línea de código. Puedes crear prototipos, animaciones, etc., y compartirlos con cualquier persona que tenga el enlace.&lt;/p&gt;

&lt;p&gt;Si tu perfil es de programación, tampoco te costará adaptarte a Figma, ya que comparte muchas similitudes con los flujos de trabajo de desarrollo. Personalmente, encuentro que esta familiaridad facilita mucho el proceso de diseño.&lt;/p&gt;

&lt;p&gt;Puede parecer abrumador al principio, pero una vez que te acostumbras a trabajar de esta manera, no querrás volver atrás. Además, Figma se integra muy bien con otras herramientas de diseño y desarrollo, como LottieFiles y VSCode, así que no tienes que abandonar tus herramientas favoritas; puedes combinarlas perfectamente.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Se integra muy bien con otras herramientas de diseño y desarrollo.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  ¿Cómo empezar a utilizar Figma?
&lt;/h2&gt;

&lt;p&gt;Voy a asumir que ya te has registrado en la plataforma de Figma. Si no lo has hecho, ¿a qué estás esperando? 😅 Dirígete a&lt;br&gt;
&lt;a href="https://www.figma.com/" rel="noopener noreferrer"&gt;Figma.com&lt;/a&gt; y regístrate.&lt;/p&gt;

&lt;p&gt;Prefiero comenzar desde un espacio de trabajo nuevo, aunque la primera pantalla puede resultar un poco intimidante. Por lo tanto, vamos a crear un nuevo espacio de trabajo.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Vamos a crear un nuevo espacio de trabajo. 🚀&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Verás algo como esto:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh06r7iw973u64ce2ntsp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh06r7iw973u64ce2ntsp.png" alt="Imagen de Figma" width="800" height="510"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Ui del home de Figma
&lt;/h2&gt;

&lt;p&gt;Podemos identificar tres secciones principales:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Barra de navegación izquierda&lt;/strong&gt;: Aquí encontrarás tu perfil, tus espacios de trabajo, espacios favoritos, proyectos compartidos y grupos de trabajo.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqdpterzo66aib028h9sq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqdpterzo66aib028h9sq.png" alt="Barra izquierda de Figma" width="264" height="527"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;En este momento, nos interesa principalmente la sección "Drafts", donde se guardan los proyectos que aún no has compartido con nadie.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Empezaremos a trabajar en un borrador.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Es como la unidad mínima, así que no te preocupes por la palabra "borrador" 😅&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Barra de navegación superior&lt;/strong&gt;: Aquí encontrarás botones para crear un nuevo proyecto, crear un nuevo Jamboard, importar un archivo y acceder a proyectos recientes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Favaabmbszs3xx3uizkcb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Favaabmbszs3xx3uizkcb.png" alt="Barra superior" width="800" height="32"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;No nos enfocaremos en Jamboard ni en la importación de archivos en esta entrada, así que nos centraremos en la creación de un nuevo proyecto. Si quieres que cubra estos temas en otra entrada, déjame saber en los comentarios.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Espacio de trabajo&lt;/strong&gt;: Aquí verás todos tus proyectos, podrás filtrarlos, buscarlos, etc. En este momento, estará vacío, pero vamos a cambiar eso. Dirígete a la esquina superior derecha y haz clic en "Desing new file", luego selecciona "Drafts".&lt;/p&gt;

&lt;h2&gt;
  
  
  Un nuevo proyecto, interfaz de Figma
&lt;/h2&gt;

&lt;p&gt;Ahora verás algo cómo esto:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feri088xyf2mkw2ycrusa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feri088xyf2mkw2ycrusa.png" alt="Draft" width="800" height="435"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Puede que veas algo ligeramente diferente, ya que tengo una configuración personalizada, pero no te preocupes, lo iremos explorando poco a poco.&lt;/p&gt;

&lt;p&gt;Lo importante es que te familiarices con tres conceptos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Barra de herramientas superior&lt;/strong&gt;: Aquí encontrarás el menú de Figma, las herramientas de diseño, la opción de compartir y la opción de presentar.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2q0xywfk00wyre8j0cz6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2q0xywfk00wyre8j0cz6.png" alt="Barra de herramientas superior" width="454" height="55"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Barra de herramientas izquierda&lt;/strong&gt;: Aquí encontrarás una lista de los elementos de tu diseño, como frames, componentes, etc. Me gusta llamarlo el panel de HTML, porque es como si estuvieras viendo el código HTML de tu diseño.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1y6975xcfewib2e5tl6s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1y6975xcfewib2e5tl6s.png" alt="Barra izquierda de herramientas " width="240" height="180"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Área de trabajo&lt;/strong&gt;: Aquí es donde verás tu diseño y donde trabajarás.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fazjbzcgtpdfhthkthrco.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fazjbzcgtpdfhthkthrco.png" alt="Área de trabajo" width="530" height="386"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Barra de herramientas derecha&lt;/strong&gt;: Aquí encontrarás opciones de diseño, como colores, estilos, etc. Me gusta llamarlo el panel de CSS, porque es como si estuvieras viendo el código CSS de tu diseño.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmvcbennbzgwyxgbfqc3s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmvcbennbzgwyxgbfqc3s.png" alt="Barra de herramientas derecha" width="237" height="286"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Comenzamos a trabajar en Figma
&lt;/h2&gt;

&lt;p&gt;Ahora que conoces la interfaz de Figma, vamos a empezar a trabajar en un diseño, veremos los diferentes elementos, los posicionaremos y les daremos estilos.&lt;/p&gt;

&lt;p&gt;La unidad mínima de trabajo en Figma es el Frame. Un frame es un contenedor que puede ser un elemento de diseño por sí solo y puede contener otros elementos, como otros frames, componentes, textos, etc.&lt;/p&gt;

&lt;p&gt;Para crear un frame, vamos a la barra de herramientas superior y hacemos clic en el botón "Frame", que tiene el icono de una almohadilla o hashtag (#).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuxuc4192f6tq6c862ll6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuxuc4192f6tq6c862ll6.png" alt="Barra de herramientas superior" width="405" height="51"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Verás que la interfaz cambia, especialmente en la barra de herramientas derecha, donde verás las opciones para este elemento que aún no hemos creado, pero ya estamos viendo sus opciones.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqo0i2gi1x4cy6jtyffub.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqo0i2gi1x4cy6jtyffub.png" alt=" " width="231" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Una de las características que más me gusta de Figma son los tamaños predefinidos que puedes utilizar, adaptados a diferentes plataformas, físicas y digitales, además de poder crear tus propios tamaños.&lt;/p&gt;

&lt;p&gt;Elige el tamaño que más te convenga. Personalmente, seleccionaré el tamaño "iPhone 13 &amp;amp; 14" dentro de la categoría "Phone", ya que será más fácil hacer una captura de pantalla y compartirlo.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6jxyga9p5eizbyiehicy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6jxyga9p5eizbyiehicy.png" alt=" " width="237" height="393"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Esto es muy importante, y aunque no lo utilizarás ahora, es útil familiarizarse con los atajos de teclado, especialmente para elementos como el Frame que utilizarás con frecuencia.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;La tecla &lt;strong&gt;F&lt;/strong&gt; es el atajo de teclado para crear un Frame.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Si deseas conocer más atajos de teclado, puedes encontrarlos en el icono de interrogación (?) en la esquina inferior derecha de la interfaz.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fberb5di2p1qydi3w0pkm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fberb5di2p1qydi3w0pkm.png" alt=" " width="55" height="54"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Modificando Frames
&lt;/h2&gt;

&lt;p&gt;Ahora que ya tienes un Frame, vamos a ver cómo modificarlo, es decir, cómo cambiarle el tamaño, la posición, etc.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Barra de Herramientas derecha | barra de propiedades
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzhj4n3owt7ltpiyft6su.png" alt=" " width="233" height="664"&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Vamos a analizar esta barra por secciones:&lt;/p&gt;

&lt;h3&gt;
  
  
  Alineación
&lt;/h3&gt;

&lt;p&gt;La primera sección es la de alineación. Aquí puedes alinear el elemento con respecto a los demás, de manera similar a como lo harías en un procesador de textos o en una herramienta de edición de imágenes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1rwq0xwhlxdtt60x0ar6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1rwq0xwhlxdtt60x0ar6.png" alt=" " width="273" height="30"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Posición
&lt;/h3&gt;

&lt;p&gt;La segunda sección nos permite posicionar el elemento, cambiar sus anchos, rotarlo y aplicar un borde. Explicaré los elementos de izquierda a derecha y de arriba hacia abajo.&lt;/p&gt;

&lt;p&gt;Los primeros elementos son los de posición según los ejes de coordenadas X e Y, es decir, la posición horizontal y vertical respectivamente.&lt;/p&gt;

&lt;p&gt;Además de poder cambiar el tamaño del elemento, tanto de ancho como de alto, con Width (W) y Height (H) en inglés, respectivamente.&lt;/p&gt;

&lt;p&gt;Por último, tenemos la opción de rotar el elemento y aplicar un efecto de redondeo a las esquinas.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fldtqw5txi0qjupv791e7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fldtqw5txi0qjupv791e7.png" alt=" " width="273" height="206"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Auto layout y Grid layout
&lt;/h2&gt;

&lt;p&gt;Estas dos opciones son súper interesantes ya que te permiten alinear automáticamente los elementos. Las veremos en próximas entradas, pero por ahora no te preocupes por ellas.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkgg2onplc7t5g9op4z34.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkgg2onplc7t5g9op4z34.png" alt=" " width="275" height="128"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Capas o &lt;code&gt;layers&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Si estás familiarizado con programas de diseño como Photoshop, Illustrator, Sketch, etc., ya sabrás a qué me refiero con capas. Si en cambio vienes de un perfil de programación, esto lo podrás entender como el método de fusión de elementos z-index y backdrop-filter en CSS.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F88p3l186oufbnr2dccie.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F88p3l186oufbnr2dccie.png" alt=" " width="269" height="94"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Fill, Stroke y Effects
&lt;/h3&gt;

&lt;p&gt;Relleno, Borde y efectos. Aquí podrás cambiar el color de relleno, el color del borde y añadir efectos como sombras, desenfoques, etc.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frkjqkyc0x0y547bszplg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frkjqkyc0x0y547bszplg.png" alt=" " width="270" height="213"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Export
&lt;/h3&gt;

&lt;p&gt;Por último, la opción de exportar. Aquí podrás exportar el elemento como imagen, SVG, PDF, etc. Esto es muy útil y básico para poder compartir tus diseños con otras personas y añadirlos al proyecto de desarrollo.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1gag2bxexizhdr1ven2t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1gag2bxexizhdr1ven2t.png" alt=" " width="243" height="169"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Final
&lt;/h2&gt;

&lt;p&gt;Con esta entrada hemos visto qué es Figma, nos hemos familiarizado con la interfaz y hemos creado nuestro primer Frame. Además, hemos visto cómo modificarlo y las diferentes opciones de diseño disponibles.&lt;/p&gt;

&lt;p&gt;En la próxima entrada profundizaremos en cada opción y exploraremos los distintos resultados, además de ver auto layout.&lt;/p&gt;

&lt;p&gt;Si te ha gustado la entrada, no dudes en compartirla. Y si tienes alguna duda, sugerencia o petición, déjala en los comentarios.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/altaskur/figma-auto-layout-138k"&gt;Siguiente paso conocer Auto Layout&lt;/a&gt;&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>beginners</category>
      <category>design</category>
      <category>spanish</category>
    </item>
    <item>
      <title>TuiCSS Tutorial - parte 2</title>
      <dc:creator>Altaskur</dc:creator>
      <pubDate>Mon, 11 Mar 2024 14:20:36 +0000</pubDate>
      <link>https://forem.com/altaskur/tuicss-tutorial-parte-2-lkb</link>
      <guid>https://forem.com/altaskur/tuicss-tutorial-parte-2-lkb</guid>
      <description>&lt;p&gt;Segunda parte del tutorial de la librería TuiCss, En esta parte veremos los componentes de Utilidad y veremos algún ejemplo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Estructura del tutorial
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://dev.to/altaskur/tuicss-tutorial-parte-1-dd5"&gt;Elementos de estructura&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Componentes de Utilidad [actual]&lt;/li&gt;
&lt;li&gt;Componentes generales (por hacer)&lt;/li&gt;
&lt;li&gt;Elementos de formulario (por hacer)&lt;/li&gt;
&lt;li&gt;Clases utilidad (por hacer)&lt;/li&gt;
&lt;li&gt;Ejemplos (por hacer)&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Índice
&lt;/h2&gt;

&lt;p&gt;Componentes de utilidad&lt;br&gt;
Background&lt;br&gt;
Border&lt;br&gt;
Shadow&lt;br&gt;
Scrollbar&lt;br&gt;
Temas&lt;br&gt;
Colores&lt;/p&gt;
&lt;h2&gt;
  
  
  Componentes de utilidad
&lt;/h2&gt;

&lt;p&gt;En este tutorial veremos como alterar los elementos para añadir o eliminar características como color, fondo o sombras.&lt;/p&gt;
&lt;h3&gt;
  
  
  Background
&lt;/h3&gt;

&lt;p&gt;Quizás una de las más importantes, añade un fondo de puntos simulando un monitor de tubo, suelen recomendar añadir la case al html para cambiar toda la página.&lt;/p&gt;

&lt;p&gt;Tenemos catorce fondos diferentes divididos en dos bloques según el fondo de la matriz de puntos:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Puntos&lt;/th&gt;
&lt;th&gt;Fondo&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;tui-bg-blue-black&lt;/td&gt;
&lt;td&gt;tui-bg-blue-white&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;tui-bg-green-black&lt;/td&gt;
&lt;td&gt;tui-bg-green-white&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;tui-bg-cyan-black&lt;/td&gt;
&lt;td&gt;tui-bg-cyan-white&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;tui-bg-red-black&lt;/td&gt;
&lt;td&gt;tui-bg-red-white&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;tui-bg-purple-black&lt;/td&gt;
&lt;td&gt;tui-bg-purple-white&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;tui-bg-yellow-black&lt;/td&gt;
&lt;td&gt;tui-bg-yellow-white&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;tui-bg-orange-black&lt;/td&gt;
&lt;td&gt;tui-bg-orange-white&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://camo.githubusercontent.com/38261d9d56a8e97fdf9c4588b0a013247a69ddb5d25dc512c4d0de9be25935d6/68747470733a2f2f75706c6f61646465696d6167656e732e636f6d2e62722f696d616765732f3030322f3332382f3836332f66756c6c2f5475694373735f6261636b67726f756e645f6578616d706c652e706e673f31353637393637303338" class="article-body-image-wrapper"&gt;&lt;img src="https://camo.githubusercontent.com/38261d9d56a8e97fdf9c4588b0a013247a69ddb5d25dc512c4d0de9be25935d6/68747470733a2f2f75706c6f61646465696d6167656e732e636f6d2e62722f696d616765732f3030322f3332382f3836332f66756c6c2f5475694373735f6261636b67726f756e645f6578616d706c652e706e673f31353637393637303338" alt="Ejemplos de fondo" width="" height=""&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;
&lt;span class="c"&gt;&amp;lt;!-- Estructura --&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- Html --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"tui-bg-blue-black"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/html&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- Screen --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;section&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"tui-screen-800-600 tui-bg-blue-black"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    ...
&lt;span class="nt"&gt;&amp;lt;/section&amp;gt;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Border
&lt;/h3&gt;

&lt;p&gt;Recomendado para el componente fieldset y controlamos el tipo de borde de este componente, tenemos 4 tipos de borde:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tipos&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;.tui-border-double&lt;/td&gt;
&lt;td&gt;.tui-border-solid&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;.tui-border-dotted&lt;/td&gt;
&lt;td&gt;.tui-border-dashed&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://camo.githubusercontent.com/55ee73887c4787f4ed280eba3b36ac642ba1745c90a06aab0c826dc54e1b4c31/68747470733a2f2f692e6962622e636f2f38304b516679472f5475696373732d626f726465722d6578616d706c652e706e67" class="article-body-image-wrapper"&gt;&lt;img src="https://camo.githubusercontent.com/55ee73887c4787f4ed280eba3b36ac642ba1745c90a06aab0c826dc54e1b4c31/68747470733a2f2f692e6962622e636f2f38304b516679472f5475696373732d626f726465722d6578616d706c652e706e67" alt="ejemplo de borde" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Shadow
&lt;/h3&gt;

&lt;p&gt;Con esta clase podemos controlar la sombra de los componentes window, panel y button. Cambiando posición, tamaño o directamente eliminar la sombra.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;Posición&lt;/span&gt;   
&lt;span class="nc"&gt;.tui-shadow-left&lt;/span&gt;    
&lt;span class="nc"&gt;.tui-shadow-left-1&lt;/span&gt;    
&lt;span class="nc"&gt;.tui-shadow-left-2&lt;/span&gt;   
&lt;span class="nc"&gt;.tui-shadow-left-3&lt;/span&gt;    
&lt;span class="nc"&gt;.tui-shadow-left-4&lt;/span&gt; 
&lt;span class="nc"&gt;.tui-shadow-left-5&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;Tamaño&lt;/span&gt;
&lt;span class="nc"&gt;.tui-shadow&lt;/span&gt;
&lt;span class="nc"&gt;.tui-shadow-1&lt;/span&gt;
&lt;span class="nc"&gt;.tui-shadow-2&lt;/span&gt;
&lt;span class="nc"&gt;.tui-shadow-3&lt;/span&gt;
&lt;span class="nc"&gt;.tui-shadow-4&lt;/span&gt;
&lt;span class="nc"&gt;.tui-shadow-5&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;Eliminación&lt;/span&gt;
&lt;span class="nc"&gt;.tui-no-shadow&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Scrollbar
&lt;/h3&gt;

&lt;p&gt;Con las palabras de la wiki oficial&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This is just applied for Google Chrome browser unfortunately. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Podemos cambiar el estilo de la barra de scroll pero sólo en Google Chrome, tenemos disponibles los siete colores de la librería:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.tui-scroll-cyan&lt;/span&gt;
&lt;span class="nc"&gt;.tui-scroll-green&lt;/span&gt;
&lt;span class="nc"&gt;.tui-scroll-red&lt;/span&gt;
&lt;span class="nc"&gt;.tui-scroll-purple&lt;/span&gt;
&lt;span class="nc"&gt;.tui-scroll-yellow&lt;/span&gt;
&lt;span class="nc"&gt;.tui-scroll-white&lt;/span&gt;
&lt;span class="nc"&gt;.tui-scroll-orange&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://camo.githubusercontent.com/63781c22553270fe434f8bd704b7b05f8e3133506f27e2e828d80869a3c53607/68747470733a2f2f692e6962622e636f2f433042685a71762f5475692d4373732d5363726f6f6c2d4578616d706c652e706e67" class="article-body-image-wrapper"&gt;&lt;img src="https://camo.githubusercontent.com/63781c22553270fe434f8bd704b7b05f8e3133506f27e2e828d80869a3c53607/68747470733a2f2f692e6962622e636f2f433042685a71762f5475692d4373732d5363726f6f6c2d4578616d706c652e706e67" alt="ejemplo de scrollbar" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Temas
&lt;/h2&gt;

&lt;p&gt;Por defecto tenemos una serie de configuraciones para todo lo que hemos visto anterior mente, llamadas temas, tenemos seis temas disponibles:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.primary&lt;/span&gt;
&lt;span class="nc"&gt;.secondary&lt;/span&gt;
&lt;span class="nc"&gt;.success&lt;/span&gt;
&lt;span class="nc"&gt;.danger&lt;/span&gt;
&lt;span class="nc"&gt;.warning&lt;/span&gt;
&lt;span class="nc"&gt;.info&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Colores
&lt;/h2&gt;

&lt;p&gt;Si con esto no tienes suficiente TuiCSS nos brinda una serie de nueve colores en dos variantes; en la variante de 255 colores y la variante de 168, basadas en las aplicaciones de MS-DOS.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fikv7w5p4tzajxhpm7hc3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fikv7w5p4tzajxhpm7hc3.png" alt="Ejemplos de imagenes" width="643" height="234"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;los colores disponibles son:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;
&lt;span class="nc"&gt;.black-&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;variante&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="nc"&gt;.blue-&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;variante&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="nc"&gt;.green-&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;variante&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="nc"&gt;.cyan-&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;variante&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="nc"&gt;.red-&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;variante&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="nc"&gt;.purple-&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;variante&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="nc"&gt;.yellow-&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;variante&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="nc"&gt;.white-&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;variante&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="nc"&gt;.orange-&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;variante&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Tan solo tienes que sustituir [variante] por la variante de 255 o 168 colores y puedes aplicar estos colores en todas las propiedades con el sufijo de color.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"tui-panel black-255"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Podemos ponerlos en las siguientes clases:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;color&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;color&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nt"&gt;-text&lt;/span&gt;    
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;color&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nt"&gt;-border&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;color&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nt"&gt;-hover&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;color&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nt"&gt;-text-hover&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;color&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nt"&gt;-border-hover&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>webdev</category>
      <category>css</category>
      <category>tutorial</category>
      <category>spanish</category>
    </item>
    <item>
      <title>TuiCss Tutorial - parte 1</title>
      <dc:creator>Altaskur</dc:creator>
      <pubDate>Sun, 10 Mar 2024 18:46:59 +0000</pubDate>
      <link>https://forem.com/altaskur/tuicss-tutorial-parte-1-dd5</link>
      <guid>https://forem.com/altaskur/tuicss-tutorial-parte-1-dd5</guid>
      <description>&lt;p&gt;Primera parte del tutorial de la librería TuiCss, voy a enfocar en cuatro partes:&lt;/p&gt;

&lt;h2&gt;
  
  
  Estructura del tutorial
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Elementos de estructura [Actual] &lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/altaskur/tuicss-tutorial-parte-2-lkb"&gt;Componentes de utilidad&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Componentes generales (por hacer)&lt;/li&gt;
&lt;li&gt;Elementos de formulario (por hacer)&lt;/li&gt;
&lt;li&gt;Clases utilidad (por hacer)&lt;/li&gt;
&lt;li&gt;Ejemplos (por hacer)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;En esta parte veremos que es TuiCSS y los elementos estructurales.&lt;/p&gt;

&lt;h1&gt;
  
  
  TuiCSS
&lt;/h1&gt;

&lt;p&gt;TuiCss es una librería de CSS enfocada a crear interfaces basadas en la tabla de ASCII cómo MSDOS y en Turbo Vision Framework, es un proyecto OpenSource creado por el usuario &lt;a href="https://github.com/vinibiavatti1/TuiCss/" rel="noopener noreferrer"&gt;@vinibiavatti1 en GitHub&lt;/a&gt; con 7 colaboradores y a la fecha de este post, el último commit fue Jul 19, 2023.&lt;/p&gt;

&lt;h2&gt;
  
  
  Índice
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Ejemplos&lt;/li&gt;
&lt;li&gt;
Elementos estructurales

&lt;ul&gt;
&lt;li&gt;tui-screen&lt;/li&gt;
&lt;li&gt;tui-window&lt;/li&gt;
&lt;li&gt;tui-panel&lt;/li&gt;
&lt;li&gt;tui-divider&lt;/li&gt;
&lt;li&gt;tui-statusbar&lt;/li&gt;
&lt;li&gt;tui-table&lt;/li&gt;
&lt;li&gt;tui-navbar&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Imagen de ejemplo
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxfsum4eznmf7gjwb37uf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxfsum4eznmf7gjwb37uf.png" alt="TuiCss explample" width="800" height="562"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Elementos estructurales
&lt;/h2&gt;

&lt;p&gt;Son todos los elementos que te ayudarán a crear tu composición, como pantallas, ventanas, divisores, barras de estado y por supuesto ¡tablas!&lt;/p&gt;

&lt;h3&gt;
  
  
  tui-screen
&lt;/h3&gt;

&lt;p&gt;Este es el elemento principal de las vistas, con él establecemos el tamaño de pantalla que vamos a representar, lo más común es usar el tamaño de pantalla estándar de la época 800x600&lt;/p&gt;

&lt;p&gt;&lt;a href="https://camo.githubusercontent.com/09c1f1bae5c709915bd0170f789d926029224540109bc910b204d05877eedf92/68747470733a2f2f75706c6f61646465696d6167656e732e636f6d2e62722f696d616765732f3030322f3334302f3036322f66756c6c2f5475694373735f53637265656e5f4578616d706c652e706e673f31353638333031383136" class="article-body-image-wrapper"&gt;&lt;img src="https://camo.githubusercontent.com/09c1f1bae5c709915bd0170f789d926029224540109bc910b204d05877eedf92/68747470733a2f2f75706c6f61646465696d6167656e732e636f6d2e62722f696d616765732f3030322f3334302f3036322f66756c6c2f5475694373735f53637265656e5f4578616d706c652e706e673f31353638333031383136" alt="ejemplo de tui-scrren" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;No te preocupes también podemos crear diseños responsive&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Elementos que añade:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* .tui-screen */&lt;/span&gt;
&lt;span class="nc"&gt;.tui-screen&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;relative&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;overflow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;hidden&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Estructura:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- Screen --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;section&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"tui-screen-800-600"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    ...
&lt;span class="nt"&gt;&amp;lt;/section&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Tamaños que admite:&lt;/p&gt;

&lt;p&gt;.tui-screen-640-480&lt;br&gt;
.tui-screen-800-600&lt;br&gt;
.tui-screen-1024-768&lt;/p&gt;
&lt;h3&gt;
  
  
  tui-window
&lt;/h3&gt;

&lt;p&gt;Con el podemos representar las distintas ventanas, según el estilo que quieras representar podemos combinarlo con la clase &lt;code&gt;fieldset&lt;/code&gt; que agrega un borde al rededor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://camo.githubusercontent.com/38b1bac763f3f30189a9d4aa8432c0331c2f0b7a7100772eafd1c31d92b038c2/68747470733a2f2f75706c6f61646465696d6167656e732e636f6d2e62722f696d616765732f3030322f3334382f3737382f66756c6c2f5475694373735f57696e646f775f4578616d706c652e706e673f31353638363439353839" class="article-body-image-wrapper"&gt;&lt;img src="https://camo.githubusercontent.com/38b1bac763f3f30189a9d4aa8432c0331c2f0b7a7100772eafd1c31d92b038c2/68747470733a2f2f75706c6f61646465696d6167656e732e636f6d2e62722f696d616765732f3030322f3334382f3737382f66756c6c2f5475694373735f57696e646f775f4578616d706c652e706e673f31353638363439353839" alt="ejemplo de tui-window" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Elementos que añade:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* tui-window */&lt;/span&gt;
&lt;span class="nc"&gt;.tui-window&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;inline-block&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;relative&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;box-shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10px&lt;/span&gt; &lt;span class="m"&gt;10px&lt;/span&gt; &lt;span class="m"&gt;#000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Estructura:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- Window --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;section&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"tui-window"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    ...
&lt;span class="nt"&gt;&amp;lt;/section&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  tui-panel
&lt;/h3&gt;

&lt;p&gt;Exactamente igual que &lt;code&gt;tui-window&lt;/code&gt; salvo que este no está pensado para representarse con un borde de la clase &lt;code&gt;fieldset&lt;/code&gt; si no que podemos añadirle los elementos &lt;code&gt;tui-panel-header&lt;/code&gt; y &lt;code&gt;tui-panel-content&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://camo.githubusercontent.com/2c967f74a24959fa933836f7c3467d12d554abc9296db010d55080b5395f31b6/68747470733a2f2f75706c6f61646465696d6167656e732e636f6d2e62722f696d616765732f3030322f3333352f3633382f66756c6c2f5475694373735f70616e656c5f6578616d706c652e706e673f31353638313539303239" class="article-body-image-wrapper"&gt;&lt;img src="https://camo.githubusercontent.com/2c967f74a24959fa933836f7c3467d12d554abc9296db010d55080b5395f31b6/68747470733a2f2f75706c6f61646465696d6167656e732e636f6d2e62722f696d616765732f3030322f3333352f3633382f66756c6c2f5475694373735f70616e656c5f6578616d706c652e706e673f31353638313539303239" alt="ejemplo tui-panel" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Elementos que añade:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.tui-panel&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;iline-block&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;relative&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;box-shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10px&lt;/span&gt; &lt;span class="m"&gt;10px&lt;/span&gt; &lt;span class="m"&gt;#000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Estructura:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;section&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"tui-panel"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"tui-panel-header"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        ...
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"tui-panel-content"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        ...
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/section&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  tui-panel-header
&lt;/h4&gt;

&lt;p&gt;Indicado para añadir un título.&lt;br&gt;
Elementos que añade:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.tui-panel-header&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;padding-top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;block&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#fff&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;text-align&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  tui-panel-content
&lt;/h4&gt;

&lt;p&gt;Añade un padding de 12px&lt;/p&gt;

&lt;h2&gt;
  
  
  tui-divider
&lt;/h2&gt;

&lt;p&gt;Un divisor vertical, se suele representar con la etiqueta &lt;code&gt;span&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://camo.githubusercontent.com/25ef6ac69edc3c2171c70764c2204ed3b60a6894ae3abe15cbc0295462c21192/68747470733a2f2f692e6962622e636f2f4a3730565039382f5475692d4373732d64697669736f722d6578616d706c652e706e67" class="article-body-image-wrapper"&gt;&lt;img src="https://camo.githubusercontent.com/25ef6ac69edc3c2171c70764c2204ed3b60a6894ae3abe15cbc0295462c21192/68747470733a2f2f692e6962622e636f2f4a3730565039382f5475692d4373732d64697669736f722d6578616d706c652e706e67" alt="ejemplo de tui-divider" width="" height=""&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.tui-divider&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;block&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="nl"&gt;border-bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="m"&gt;#fff&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"tui-divider"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    ...
&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  tui-status-bar
&lt;/h2&gt;

&lt;p&gt;Está pensada para añadir acciones rápidas o texto informativo.&lt;br&gt;
contiene.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://camo.githubusercontent.com/2693724d79558117d0bddf67c1bf327e38f0bd9e4129404e448b13f0debbac07/68747470733a2f2f75706c6f61646465696d6167656e732e636f6d2e62722f696d616765732f3030322f3334332f3130392f66756c6c2f5475694373735f7374617475736261725f6578616d706c652e706e673f31353638333930373534" class="article-body-image-wrapper"&gt;&lt;img src="https://camo.githubusercontent.com/2693724d79558117d0bddf67c1bf327e38f0bd9e4129404e448b13f0debbac07/68747470733a2f2f75706c6f61646465696d6167656e732e636f6d2e62722f696d616765732f3030322f3334332f3130392f66756c6c2f5475694373735f7374617475736261725f6578616d706c652e706e673f31353638333930373534" alt="Ejemplo statusbar" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  tui-statusbar-divider
&lt;/h3&gt;

&lt;p&gt;Añade un divisor vertical.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.tui-statusbar-divider&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;border-right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="m"&gt;#000&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;inline&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;3px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"statusbar"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    ...
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  tui-table
&lt;/h2&gt;

&lt;p&gt;¡Tablas!&lt;br&gt;
Como buen diseño retro no podrían faltas las tablas.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://camo.githubusercontent.com/ec2415d8beb056ced71338d577558eb43695fecb9f628899ca9c5c645786bbb5/68747470733a2f2f75706c6f61646465696d6167656e732e636f6d2e62722f696d616765732f3030322f3334332f3132392f66756c6c2f5475694373735f7461626c655f6578616d706c652e706e673f31353638333931333238" class="article-body-image-wrapper"&gt;&lt;img src="https://camo.githubusercontent.com/ec2415d8beb056ced71338d577558eb43695fecb9f628899ca9c5c645786bbb5/68747470733a2f2f75706c6f61646465696d6167656e732e636f6d2e62722f696d616765732f3030322f3334332f3132392f66756c6c2f5475694373735f7461626c655f6578616d706c652e706e673f31353638333931333238" alt="ejemplo de tabla" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;El funcionamiento es el mismo sólo tenemos que añadir la clase &lt;code&gt;.tui-table&lt;/code&gt; aunque admite una serie de modificaciones.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Podemos añadir un hoover a la tabla, decirle que se resalten los elementos pares o cambiar la barra de separación.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;code&gt;.hovered-{color}  striped-{color}&lt;/code&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Colores&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;blue&lt;/td&gt;
&lt;td&gt;green&lt;/td&gt;
&lt;td&gt;cyan&lt;/td&gt;
&lt;td&gt;white&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;red&lt;/td&gt;
&lt;td&gt;purle&lt;/td&gt;
&lt;td&gt;yellow&lt;/td&gt;
&lt;td&gt;orange&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- Table hovered --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;table&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"tui-table hovered-cyan"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    ...
&lt;span class="nt"&gt;&amp;lt;/table&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;Ahora ya puedes continuar con la parte dos del tutorial&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/altaskur/tuicss-tutorial-parte-2-lkb"&gt;Componentes de utilidad&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>css</category>
      <category>tutorial</category>
      <category>spanish</category>
    </item>
    <item>
      <title>React, Animando un Texto con useRef() desde la carga del componente</title>
      <dc:creator>Altaskur</dc:creator>
      <pubDate>Fri, 16 Feb 2024 16:06:40 +0000</pubDate>
      <link>https://forem.com/altaskur/react-animando-un-texto-con-useref-desde-la-carga-del-componente-4hj5</link>
      <guid>https://forem.com/altaskur/react-animando-un-texto-con-useref-desde-la-carga-del-componente-4hj5</guid>
      <description>&lt;p&gt;Recientemente, quise añadir un toque animado a mi proyecto final en React, inspirado por una animación compartida por la creadora de contenido &lt;a href="https://bento.me/mewtru" rel="noopener noreferrer"&gt;Mewtru&lt;/a&gt;. &lt;br&gt;
Aquí está el efecto que capturó mi atención:&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/altaskur/embed/VwRXoay?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;La idea inicial era trasladarlo de JavaScript a React, y automáticamente pensé en utilizar &lt;code&gt;useRef&lt;/code&gt; para lograrlo. Sin embargo, como es común en el mundo del desarrollo, las cosas no siempre siguen el guion previsto, y los desafíos surgieron justo al cargar el componente.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problema al cargar el Componente
&lt;/h2&gt;

&lt;p&gt;La sorpresa y el motivo de este post, llegó al momento de cargar el componente, la consola lanzaba el mismo error.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"append is not defined divElement is null"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;En un principio, sospeché de algún error de sintaxis, Sin embargo tras revisar el código y revisarlo repetidamente, el problema se mantenía con el mensaje &lt;code&gt;is null&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;te dejo parte del código para que veas como estaba todo definido.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;div1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;div2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;words&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@property - example&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ANIMATION_DURATION&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;characters&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;words&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;character&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;createElement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;div&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;character&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;character&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;animationDelay&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ANIMATION_DURATION&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;offset&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;ms`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="nx"&gt;div1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="nx"&gt;div2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ANIMATION_DURATION&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="p"&gt;},[]}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esta es la raíz del problema, div1 y div2 son &lt;code&gt;null&lt;/code&gt; siempre.&lt;/p&gt;

&lt;h2&gt;
  
  
  La incógnita
&lt;/h2&gt;

&lt;p&gt;Mi primera suposición fue que quizás no le estaba dando tiempo al hook de "vincularse" con el contenido. Sin embargo, el contenido de useEffect() se ejecuta al inicio del componente después de que todo se ha cargado, según la &lt;a href="https://react.dev/reference/react/useEffect#caveats" rel="noopener noreferrer"&gt;documentación oficial de React&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;React will generally let the browser paint the updated screen first before running your Effect.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A pesar de esto, el problema persistía, y el mensaje &lt;code&gt;null&lt;/code&gt; seguía apareciendo. La confusión se apoderaba de mí: ¿por qué sigue siendo null?&lt;/p&gt;

&lt;h2&gt;
  
  
  Solución
&lt;/h2&gt;

&lt;p&gt;Después de explorar múltiples fuentes en la web y  consultar a distintas inteligencias artificiales sin obtener resultados significativos, finalmente encontré una solución:&lt;/p&gt;

&lt;p&gt;En el &lt;code&gt;useEffect()&lt;/code&gt; forzar a comprobar si los &lt;code&gt;useRef()&lt;/code&gt; están definidos, en ese caso ejecutar el código. Te dejo el código completo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;div1&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;div2&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
       &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;words&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@property - example&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

       &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ANIMATION_DURATION&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

       &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;characters&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;words&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;character&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;createElement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;div&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
              &lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerText&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;character&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
              &lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;character&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
              &lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;animationDelay&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ANIMATION_DURATION&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;ms`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
              &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
          &lt;span class="p"&gt;};&lt;/span&gt;

          &lt;span class="nx"&gt;div1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
          &lt;span class="nx"&gt;div2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ANIMATION_DURATION&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="p"&gt;},[]}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Resolución
&lt;/h2&gt;

&lt;p&gt;¡Y funcionó! 🎉🎉 el componente cargaba correctamente, y la animación entraba. Aún no consigo entender porque hay que forzar al &lt;code&gt;useEffect()&lt;/code&gt; a que se definan los &lt;code&gt;useState()&lt;/code&gt; si este se ejecuta después de renderizar todo. además de como consigue esa reactividad, si el &lt;code&gt;useEffect()&lt;/code&gt; está definido para que se ejecute sólo al montar el componente.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;¿Te ha pasado alguna vez, o sabes lo que está ocurriendo? no dudes en dejarlo en comentarios.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Referencias
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://bento.me/mewtru" rel="noopener noreferrer"&gt;Mewtru&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://codepen.io/altaskur/pen/VwRXoay" rel="noopener noreferrer"&gt;CodePen&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://react.dev/reference/react/useEffect#caveats" rel="noopener noreferrer"&gt;Documentación oficial de React&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>beginners</category>
      <category>spanish</category>
    </item>
    <item>
      <title>Descubriendo la magia de las Guard Clauses</title>
      <dc:creator>Altaskur</dc:creator>
      <pubDate>Mon, 05 Feb 2024 11:21:08 +0000</pubDate>
      <link>https://forem.com/altaskur/descubriendo-la-magia-de-las-guard-clauses-en-mi-viaje-con-express-1p6m</link>
      <guid>https://forem.com/altaskur/descubriendo-la-magia-de-las-guard-clauses-en-mi-viaje-con-express-1p6m</guid>
      <description>&lt;p&gt;No me di cuenta de cómo el desarrollo Backend había cambiado mi forma de programar hasta el Jueves 1 de Febrero de 2024.&lt;/p&gt;

&lt;h2&gt;
  
  
  El momento de la revelación
&lt;/h2&gt;

&lt;p&gt;No fue sino durante una conversación con mi profesor que me di cuenta de que no estaba utilizando la clásica estructura de if-else. Este episodio me desconcertó por completo e instigó una investigación sobre el tema. Nunca me había cuestionado el uso de esta estructura de manera consciente; simplemente la aplicaba de forma automática al verla en los ejemplos.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Qué estaba usando?
&lt;/h2&gt;

&lt;p&gt;Descubrí que en una estructura básica de código, colocaba las negaciones al principio y cancelaba el flujo de la función con un return. A continuación, te muestro cómo lo estaba utilizando en una función para registrar a un usuario:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;singInUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;Users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findOne&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Usuario no encontrado&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isMatch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;comparePassword&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isMatch&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;401&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Contraseña incorrecta&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;generateToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Ocurrió un error durante la solicitud&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Transformar esto en un conjunto de if-else anidados crearía un laberinto de condiciones difícil de mantener. Al inicio de mi investigación no encontraba nada al respecto; sólo encontraba formas de devolver varios elementos dentro de una función, lo que se aleja completamente del objetivo.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Necesitaba un Rescate&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;No fue hasta que pude hablar sobre el tema con &lt;a href="https://github.com/pedrovelasquez9" rel="noopener noreferrer"&gt;@programacon_es&lt;/a&gt; que me sugirió que buscara por las "Guard Clauses", y aquí comienza mi aventura.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Qué són las Guard clauses?
&lt;/h2&gt;

&lt;p&gt;Las Guard Clauses, también conocidas como "early returns" o "return early", son estructuras de control de flujo en programación que se utilizan para mejorar la legibilidad y simplicidad del código al evitar anidaciones excesivas de condicionales. En concepto, estas estructuras se utilizan para evitar el uso de anidaciones excesivas y mejorar la simplicidad y legibilidad del código.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pongamos un ejemplo teórico
&lt;/h2&gt;

&lt;p&gt;Podemos escribir las cláusulas de error y negativas al principio, no solo mejorando la legibilidad sino también interrumpiendo el resto del código, lo que contribuye a una mejor optimización del mismo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;validarContrasena&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;contrasena&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;contrasena&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;La contraseña no puede estar vacía.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;contrasena&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;La contraseña debe tener al menos 8 caracteres.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\d&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;contrasena&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;La contraseña debe contener al menos un número.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;La contraseña es válida. ¡Bien hecho!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Veamos una alternativa con if-else.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;validarContrasena&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;contrasena&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;contrasena&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;La contraseña no puede estar vacía.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;contrasena&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;La contraseña debe tener al menos 8 caracteres.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\d&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;contrasena&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;La contraseña debe contener al menos un número.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;La contraseña es válida. ¡Bien hecho!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Aunque observamos un cambio evidente, no siempre es lo más indicado. Como en todo en programación, el abuso de estas cláusulas puede ser contraproducente y generar fácilmente el efecto contrario, generando un código sucio. Veamos también un ejemplo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;calculateScore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;player&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;player&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Jugador no especificado&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;player&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;score&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Puntuación del jugador no encontrada&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;player&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;score&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Puntuación del jugador negativa&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;player&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;score&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  ¿Entonces en que casos podemos usarlo?
&lt;/h2&gt;

&lt;p&gt;Es importante darle un uso moderado, en casos simples y directos teniendo en cuenta siempre el uso de otras estructuras, recuerda el uso de los comentarios en caso de ser necesario. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;¿Has experimentado con Guard Clauses en tus proyectos? ¡Comparte tu experiencia en los comentarios!&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Referencias
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://refactoring.guru/replace-nested-conditional-with-guard-clauses" rel="noopener noreferrer"&gt;https://refactoring.guru/replace-nested-conditional-with-guard-clauses&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/homolibere/guard-clauses-in-c-30d0"&gt;https://dev.to/homolibere/guard-clauses-in-c-30d0&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://tech.jotform.com/making-code-more-robust-with-guard-clauses-tips-and-tricks-d8d3d1940bce" rel="noopener noreferrer"&gt;https://tech.jotform.com/making-code-more-robust-with-guard-clauses-tips-and-tricks-d8d3d1940bce&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.codementor.io/@clintwinter/use-guard-clauses-for-cleaner-code-1rrsczgwxp" rel="noopener noreferrer"&gt;https://www.codementor.io/@clintwinter/use-guard-clauses-for-cleaner-code-1rrsczgwxp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.linkedin.com/pulse/guard-clauses-vs-statements-j%C3%A1n-hor%C5%88%C3%A1k" rel="noopener noreferrer"&gt;https://www.linkedin.com/pulse/guard-clauses-vs-statements-j%C3%A1n-hor%C5%88%C3%A1k&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/@basuraratnayake/clean-code-guard-clauses-796225c83c3e" rel="noopener noreferrer"&gt;https://medium.com/@basuraratnayake/clean-code-guard-clauses-796225c83c3e&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://refactoring.com/catalog/replaceNestedConditionalWithGuardClauses.html" rel="noopener noreferrer"&gt;https://refactoring.com/catalog/replaceNestedConditionalWithGuardClauses.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>beginners</category>
      <category>programming</category>
      <category>spanish</category>
    </item>
    <item>
      <title>Despidiéndome de Console.log</title>
      <dc:creator>Altaskur</dc:creator>
      <pubDate>Fri, 02 Feb 2024 01:37:39 +0000</pubDate>
      <link>https://forem.com/altaskur/despidiendome-de-consolelog-5a6a</link>
      <guid>https://forem.com/altaskur/despidiendome-de-consolelog-5a6a</guid>
      <description>&lt;h2&gt;
  
  
  El dilema
&lt;/h2&gt;

&lt;p&gt;Llevaba tiempo con la idea de replantearme el uso de &lt;code&gt;console.log()&lt;/code&gt; en mis proyectos de estudio. Las evidencias provenían de cuatro actores clave: ESLint, con sus persistentes advertencias, indicándome que no era la mejor práctica; mi propia sospecha de que debía existir una alternativa más eficiente; y, por último, la insistencia de mi profesor de entregar las prácticas sin la presencia de console.log(), emulando así un entorno de producción más estricto.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demasiado bueno para ser cierto
&lt;/h2&gt;

&lt;p&gt;Desde el principio, me limité a utilizar dos enfoques. El más rápido: &lt;code&gt;/* eslint-disable no-console */&lt;/code&gt; al inicio del documento. Como alternativa, prescindir completamente de su uso, mejorando así la estructura y legibilidad del código.&lt;/p&gt;

&lt;p&gt;No nos engañemos, evitar el uso de &lt;code&gt;console.log()&lt;/code&gt; bajo la excusa de mejorar mis habilidades de desarrollo ha sido una idea que ha alimentado mi ego durante este año y medio. Aunque seguía intuyendo que debía haber algo más. Claro, el uso de debugger estaba ahí, pero &lt;code&gt;console.log()&lt;/code&gt; seguía siendo más simple y rápido de implementar. No me convencía completamente como alternativa directa.&lt;/p&gt;

&lt;h2&gt;
  
  
  History Time
&lt;/h2&gt;

&lt;p&gt;Los eventos de desarrollo suelen ser oportunidades mágicas de aprendizaje. Un día, durante el OpenSourceJam en Alicante, esta revelación llegó de manera inesperada.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Evento: OpenSourceJam Alicante.&lt;br&gt;
Fecha: 18 de Noviembre de 2023.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Junto a otras dos personas, contribuíamos al código abierto. Mi tarea consistía en desarrollar un pequeño crawler con Express.js y Puppeter para obtener datos de eventos Tech. Del otro lado, Noe y Cesar trabajaban en el frontend con Next.js.&lt;/p&gt;

&lt;p&gt;La sorpresa llegó cuando Cesar, con una sonrisa pícara, anticipando que me iba a gustar lo que tenía que decirme, mencionó algo sobre mi Pull Request en GitHub. En ese momento, me encontraba abrumado y luchaba por comprender lo que estaba diciendo.&lt;/p&gt;

&lt;p&gt;Mi curiosidad se disparó cuando, tras actualizar la rama y ejecutar el proyecto, vi por consola:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;Server running on port 3000&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;En verde y negrita, pero sin rastro de console.log(). En ese momento, mis sospechas se confirmaron: existía una alternativa viable y eficiente. Continuamos con el proyecto, y la lección quedó grabada.&lt;/p&gt;

&lt;h2&gt;
  
  
  Después de un tiempo
&lt;/h2&gt;

&lt;p&gt;Ha pasado un tiempo desde ese episodio y fue hoy, durante la revisión del Backend de mi proyecto final de 2ºDAW, donde tuve el flashback. Tenía mi &lt;code&gt;console.log('Server running on port 3000');&lt;/code&gt; junto a la cláusula &lt;code&gt;/* eslint-disable no-console */&lt;/code&gt; y no pude aguantar más. Me dirigí al repositorio del evento y descubrí algo muy sencillo, rápido y que implementaré como mínimo a partir de ahora.&lt;/p&gt;

&lt;h2&gt;
  
  
  El código
&lt;/h2&gt;

&lt;p&gt;Nos encontramos en &lt;code&gt;/src/utils/logger.js&lt;/code&gt; y podemos encontrar estas simpáticas líneas:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;chalk&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;chalk&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;log&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;chalk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;blue&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;chalk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;red&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;warning&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;chalk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;yellow&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;chalk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;green&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;¡Había deconstruido console.log() y creado su propia versión! 👀 La librería chalk.js añade colores y decoraciones a la terminal.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Terminal string styling done right&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;y un ejemplo de uso del mismo proyecto:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Saving &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;records&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; events`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;El método ofrece mensajes más amigables con el desarrollador y ESLint no se queja más.&lt;/p&gt;

&lt;p&gt;Aún así, mi curiosidad me ha empujado a encontrar formas más elegantes y prácticas como Winston y el log4js; este último me sonaba porque saltó a la palestra hace tiempo por fallas de seguridad, pero no profundicé más al respecto.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusión
&lt;/h2&gt;

&lt;p&gt;Despedirme de &lt;code&gt;console.log()&lt;/code&gt; no va solo de seguir ciertas convenciones o reglas, sino de elevar la calidad y la estética del código. Continuaré con otra entrada explicando cómo voy a añadir Winston al proyecto.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;¿Tienes alguna anécdota sobre la transición de console.log() a otras alternativas? ¡Me encantaría escuchar tus historias!&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Enlaces:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Evento: &lt;a href="https://www.opensourcejam.com/" rel="noopener noreferrer"&gt;OpenSourceJam web&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Proyectos: &lt;a href="https://github.com/altaskur/opensource_puppeter" rel="noopener noreferrer"&gt;Crawler&lt;/a&gt;, &lt;a href="https://github.com/nsdonato/openjam_picklerick" rel="noopener noreferrer"&gt;Frontal&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Perfiles:  &lt;a href="https://github.com/cesmunoz" rel="noopener noreferrer"&gt;Cesar&lt;/a&gt; &lt;a href="https://github.com/nsdonato" rel="noopener noreferrer"&gt;Noe&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Librerías: &lt;a href="https://www.npmjs.com/package/chalk" rel="noopener noreferrer"&gt;Chalk&lt;/a&gt; &lt;a href="https://www.npmjs.com/package/winston" rel="noopener noreferrer"&gt;winston&lt;/a&gt;, &lt;a href="https://www.npmjs.com/package/log4js" rel="noopener noreferrer"&gt;log4js&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Noticia Relacionada: &lt;a href="https://www.elespanol.com/omicrono/software/20211214/log4j-vulnerabilidad-saltar-alarmas-afecta-millones-dispositivos/634686563_0.html" rel="noopener noreferrer"&gt;Omicrono Portal de noticias&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>node</category>
      <category>javascript</category>
      <category>spanish</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
