<?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: Lucho Peñafiel</title>
    <description>The latest articles on Forem by Lucho Peñafiel (@luchopenafiel).</description>
    <link>https://forem.com/luchopenafiel</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%2F386924%2Ff5dbb8ac-bf33-4f7f-9c54-5f075a8a4285.jpg</url>
      <title>Forem: Lucho Peñafiel</title>
      <link>https://forem.com/luchopenafiel</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/luchopenafiel"/>
    <language>en</language>
    <item>
      <title>I built a garage for my roomba with a ESP32.</title>
      <dc:creator>Lucho Peñafiel</dc:creator>
      <pubDate>Tue, 20 Feb 2024 08:36:41 +0000</pubDate>
      <link>https://forem.com/luchopenafiel/i-built-a-garage-for-my-roomba-with-a-esp32-2g1o</link>
      <guid>https://forem.com/luchopenafiel/i-built-a-garage-for-my-roomba-with-a-esp32-2g1o</guid>
      <description>&lt;p&gt;A few weeks back, my partner showed me this image, and I thought, "&lt;em&gt;Alright, I can tackle this. And maybe make it a bit fancier. Challenge accepted.&lt;/em&gt;"&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fympwqpb6agdv38a64u6o.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fympwqpb6agdv38a64u6o.jpeg" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Same IKEA box, different approach.
&lt;/h3&gt;

&lt;p&gt;I purchased the same &lt;a href="https://www.ikea.com/gb/en/p/hol-side-table-acacia-70161320/" rel="noopener noreferrer"&gt;IKEA Hol side table&lt;/a&gt;, but I opted for a different strategy. The side door wasn't going to work for me because the vacuuming robot needs a clear path.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fvog6np5zfvh42al1hdbg.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fvog6np5zfvh42al1hdbg.jpeg" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Requirements and research.
&lt;/h3&gt;

&lt;p&gt;To make it cool (and a bit challenging for a non-professional like me, just a hobbyist), I set three goals for this project:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I should be able to open/close the door using Alexa.&lt;/li&gt;
&lt;li&gt;The system should be able to detect when the robot is leaving its base and open the door.&lt;/li&gt;
&lt;li&gt;The system should be able to detect when the robot is returning to its base and close the door.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For the first goal, I used SincrinPro, and it was a breeze. Not a big deal.&lt;/p&gt;

&lt;p&gt;To tackle the next two goals, after exploring options, I settled on using an Infrared sensor. This way, I can determine when the robot is in or out of its base.&lt;/p&gt;

&lt;h3&gt;
  
  
  Proof of concept.
&lt;/h3&gt;

&lt;p&gt;At this stage, it was time to code and start validating the plan.&lt;/p&gt;

&lt;p&gt;I must say it worked quite well. The only issue I ran into is that the robot leaves the base faster than the actuator opens the door, but that's okay. I can live with it. In future versions, maybe I'll try to get another actuator that works faster.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fnorvfe7148pj6n0faz1s.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fnorvfe7148pj6n0faz1s.jpeg" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fkxf4ie8r9m55dep363dr.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fkxf4ie8r9m55dep363dr.jpeg" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/luchoPenafiel/roomba-garage" rel="noopener noreferrer"&gt;Here you can find the code of this project&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Design and print the final PCB and the enclosure.
&lt;/h3&gt;

&lt;p&gt;Once the system was tested and I was happy with it, I decided to design a PCB for it. This was my first time, so don't judge me. As I said, I'm not a pro, just a hobbyist.&lt;/p&gt;

&lt;p&gt;After getting all the components mounted on the PCB, I designed the enclosure and 3D-printed it.&lt;/p&gt;

&lt;p&gt;The final result turned out pretty good, and I'm more than happy with it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fb251xmr1qxopo1sbgyo2.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fb251xmr1qxopo1sbgyo2.jpeg" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Flyi41wwa2lanondbuzgw.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Flyi41wwa2lanondbuzgw.jpeg" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fwxlyi89iaxc3tx43j4k5.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fwxlyi89iaxc3tx43j4k5.jpeg" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2F9csln00t5bst05vhfpkb.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F9csln00t5bst05vhfpkb.jpeg" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>arduino</category>
      <category>automation</category>
      <category>esp32</category>
      <category>cpp</category>
    </item>
    <item>
      <title>Cómo usar Intersection Observer API en Next.js</title>
      <dc:creator>Lucho Peñafiel</dc:creator>
      <pubDate>Mon, 18 Jul 2022 13:34:51 +0000</pubDate>
      <link>https://forem.com/luchopenafiel/como-usar-intersection-observer-api-en-nextjs-38ml</link>
      <guid>https://forem.com/luchopenafiel/como-usar-intersection-observer-api-en-nextjs-38ml</guid>
      <description>&lt;p&gt;¡Hola! En este artículo vamos a ver cómo usar Intersection Observer API. Es una API del navegador que nos permite detectar cuando un elemento es visible en pantalla, o (y acá está lo bueno) cuando el elemento está por serlo, y con esto poder realizar alguna acción.&lt;/p&gt;

&lt;p&gt;Hay varios casos de uso para esta API, como lazy loading de imágenes o implementar "infinite scrolling" pero en este artículo vamos a usar esta API para interactuar con elementos de nuestra UI a medida que el usuario va haciendo scroll.&lt;/p&gt;

&lt;p&gt;En concreto 🧐 nuestro proyecto va a tener una serie de artículos y a medida que vamos avanzando por ellos, vamos a ir marcando como "activo" el título que corresponda.&lt;/p&gt;

&lt;p&gt;Te dejo links a la &lt;a href="https://intersection-observer.lucho.codes/"&gt;demo del proyecto&lt;/a&gt; y al &lt;a href="https://github.com/luchoPenafiel/intersection-observer"&gt;repositorio completo del proyecto en GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Empecemos
&lt;/h2&gt;

&lt;p&gt;Lo primero que tenemos que hacer es crear nuestro proyecto en Next.js, y eso lo hacemos con el comando &lt;code&gt;yarn create next-app&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Una vez que tenemos nuestro proyecto corriendo vamos a crear un directorio &lt;code&gt;/components&lt;/code&gt; en el cual vamos a agregar dos componentes: &lt;code&gt;Title&lt;/code&gt; y &lt;code&gt;Article&lt;/code&gt;. De tal manera que queden así:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Title.js&lt;/code&gt;&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="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;styles&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../styles/Title.module.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isActive&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;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&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;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&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;isActive&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;active&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="s2"&gt;`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&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="nx"&gt;Title&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;Article.js&lt;/code&gt;&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="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;styles&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../styles/Article.module.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Article&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;content&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;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
       &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;article&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;article&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
           &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
           &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
       &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;article&lt;/span&gt;&lt;span class="p"&gt;&amp;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;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;Article&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Usando nuestros componentes
&lt;/h2&gt;

&lt;p&gt;Una vez que tenemos nuestros componentes, vamos a usarlos en el archivo &lt;code&gt;index.js&lt;/code&gt; de tal manera que quede así:&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="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Head&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/head&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;styles&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../styles/Home.module.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Title&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../components/Title&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Article&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../components/Article&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../data/data.json&lt;/span&gt;&lt;span class="dl"&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Home&lt;/span&gt;&lt;span class="p"&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;activeArticle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setActiveArticle&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;01&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="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;main&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;titles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&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;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Title&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;isActive&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;activeArticle&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;articles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;content&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;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Article&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;main&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;)}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Agregando la Intersection Observer API
&lt;/h2&gt;

&lt;p&gt;Lo primero que tenemos que hacer es crear, en&lt;code&gt;index.js&lt;/code&gt;, nuestro &lt;code&gt;observer&lt;/code&gt;, el cual recibe dos parámetros:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;El primero es el call back que queremos ejecutar cuando la API detecte que el scroll está cerca del elemento a observar&lt;/li&gt;
&lt;li&gt;El segundo es un objeto que nos permite configurar nuestro observer, podemos indicar qué tan pronto o tarde disparar nuestro call back, es decir, con qué porcentaje de visibilidad de nuestro elemento se debe ejecutar el call back.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Una vez creado nuestro observer, tenemos que indicarle qué elementos observar. Y como nuestro proyecto tiene varios artículos a observar, cada uno de ellos va a recibir por prop un observer, de tal manera que nuestro &lt;code&gt;index.js&lt;/code&gt; quede así:&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="c1"&gt;// imports..&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Home&lt;/span&gt;&lt;span class="p"&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;activeArticle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setActiveArticle&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;01&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;handleIntersect&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;entries&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;entries&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;isIntersecting&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;setActiveArticle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;entries&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;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;createObserver&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;target&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;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;threshold&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;1.0&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;observer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;IntersectionObserver&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;handleIntersect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nx"&gt;observer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;observe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;target&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="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;main&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;titles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&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;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Title&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;isActive&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;activeArticle&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;articles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;content&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;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Article&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;createObserver&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;createObserver&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;main&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;)}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Analicemos este código 🤔 .&lt;/p&gt;

&lt;p&gt;La función &lt;code&gt;handleIntersect&lt;/code&gt; es nuestro call back, esto quiere decir que es la función que se va a ejecutar cada vez que &lt;code&gt;observer&lt;/code&gt; detecte que el elemento observado sea en visible.&lt;/p&gt;

&lt;p&gt;Lo que hace este call back es tomar el ID del elemento observado y guardarlo en el state de la aplicación, el cual nos sirve para saber qué artículo es visible y así marcar como activo el título correspondiente.&lt;/p&gt;

&lt;p&gt;Ya tenemos nuestro observer y call back creados, ahora solo nos queda usarlos. Y para eso, como dijimos anteriormente, debemos enviar por propiedad nuestro observer a cada artículo y ejecutarlo. Nuestro &lt;code&gt;Article.js&lt;/code&gt; nos quedará de la siguiente manera:&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="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useRef&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;styles&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../styles/Article.module.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Article&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;createObserver&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;el&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;createObserver&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&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="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="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;article&lt;/span&gt; &lt;span class="na"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;article&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;article&lt;/span&gt;&lt;span class="p"&gt;&amp;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;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;Article&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Y &lt;em&gt;voilá&lt;/em&gt;, eso es todo 🥳.&lt;/p&gt;

&lt;p&gt;Ya tenemos creado y configurado nuestro observer, y ya está siendo usado por cada elemento a observar.&lt;/p&gt;

&lt;p&gt;Espero que puedas aplicar lo aprendido en este artículo en tus proyecto.&lt;/p&gt;

&lt;p&gt;Eso es todo por ahora, nos vemos pronto 👋🏻.&lt;/p&gt;

</description>
      <category>spanish</category>
    </item>
    <item>
      <title>¿Por dónde empezar a programar?</title>
      <dc:creator>Lucho Peñafiel</dc:creator>
      <pubDate>Mon, 18 Jul 2022 13:34:41 +0000</pubDate>
      <link>https://forem.com/luchopenafiel/por-donde-empezar-a-programar-ioh</link>
      <guid>https://forem.com/luchopenafiel/por-donde-empezar-a-programar-ioh</guid>
      <description>&lt;p&gt;&lt;em&gt;"Quiero aprender a programar, ¿por dónde empiezo?"&lt;/em&gt; Esa pregunta me la hacen muy seguido y en este post voy a dejarte algunos consejos en base a mi experiencia.&lt;/p&gt;

&lt;p&gt;Pero antes de eso, veamos algunos puntos a tener en cuenta.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mitos y barreras
&lt;/h2&gt;

&lt;p&gt;Existen mitos y creencias sobre la programación que alejan a la gente de este maravilloso mundo.&lt;/p&gt;

&lt;h3&gt;
  
  
  "Programar requiere mucha matemática."
&lt;/h3&gt;

&lt;p&gt;Falso. La programación tiene muchas ramas o areas de especialidad, como la medicina (cirugía, dermatología, traumatología, etc.), y solo algunas de ellas requieren un mayor uso de cálculos matemáticos.&lt;/p&gt;

&lt;p&gt;Hace unos días, en la app en la que estoy trabajando, tuve que realizar el cálculo matemático más complejo de mucho tiempo, y fue simplemente una regla de tres 😂.&lt;/p&gt;

&lt;h3&gt;
  
  
  "Para ser un programador/a necesitas ser súper inteligente."
&lt;/h3&gt;

&lt;p&gt;Falso, total y completamente falso. Soy soy la prueba viviente de ello, soy bastante bol***. Todos podemos programar, lo único que necesitamos es tener ganas de aprender.&lt;/p&gt;

&lt;h3&gt;
  
  
  "Necesitas un título universitario para conseguir trabajo."
&lt;/h3&gt;

&lt;p&gt;Falso. Una vez más, soy la prueba viviente de ello. Soy un desarrollador autodidacta, no tengo ningún título relacionado con ciencias de la computación y sin embargo tengo el trabajo de mis sueños ✨.&lt;/p&gt;

&lt;p&gt;Ahora bien, esto podría verse como un caso aislado. Voy decirte que no lo es. Hoy cada vez son más las empresas que en sus ofertas de trabajo no incluyen como requisito tener un título relacionado a las ciencias de la computación. Esto es porque las empresas antes de contratarte necesitan que demuestres tus conocimientos y habilidades, y no que un título lo haga por vos. ¿Cómo se logra esto? Generalmente las empresas te van a pedir un portfolio con tus trabajos o te va a dar un challenge para resolver, o incluso ¡ambas cosas!&lt;/p&gt;

&lt;p&gt;Lo que quiero decir con todo esto, no es que no tienes que ir a la universidad, en absoluto. Lo que digo es que hoy existe otra alternativa, y es 100% válida. Y una pequeña aclaración, no es el camino fácil, vas a necesitar estudiar, y mucho, pero vas a poder hacerlo a tu tiempo y ritmo.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Por qué querés programar?
&lt;/h2&gt;

&lt;p&gt;¿Qué es lo que te motiva a querer programar? ¿Tienes una idea que quieres llevar a delante? ¿Querés hacer un cambio en tu carrera profesional?&lt;/p&gt;

&lt;p&gt;No importa cuál es el motivo por el cual querés aprender a programar, todos son válidos. Incluso si lo querés hacer porque escuchaste que los salarios suelen ser altos. ¡Está perfecto!&lt;/p&gt;

&lt;p&gt;Pero sí es importante que tengas claro que es lo que te motiva o qué querés hacer. Como dije antes, hay muchas ramas dentro del mundo de la programación, algunas con más oferta laboral que otra, algunas con curvas de aprendizaje más chica que otras, algunas con salarios más altos que otras.&lt;/p&gt;

&lt;p&gt;Insisto, no es importante el motivo, pero si es importante que lo tengas claro, porque eso te va a ayudar a al principio.&lt;/p&gt;

&lt;p&gt;Ahora si...&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Por dónde empezar?
&lt;/h2&gt;

&lt;p&gt;El mejor consejo que puedo darte es que encuentres un mentor/a que te guíe en tus primeros pasos. Para eso existen un montón de comunidades a las que te puedes unir y encontrar un mentor en función de lo quieres hacer, como &lt;a href="https://frontend.cafe/mentorias"&gt;Frontend Cafe&lt;/a&gt;, una comunidad de habla hispana que está en crecimiento o el &lt;a href="http://www.chicasprogramadoras.club/"&gt;Club de Chicas programadoras&lt;/a&gt; del cual soy parte.&lt;/p&gt;

&lt;p&gt;Si no sabes muy bien qué es lo que querés, la programación web es un muy buen primer paso, ya que con pocas herramientas puedes ver resultados en poco tiempo. Esto es importante porque ver el resultado de las cosas que vas creando te va a dar motivación para seguir aprendiendo más y más cosas y quién te dice, a lo mejor la programación web es lo tuyo! 😉&lt;/p&gt;

&lt;p&gt;Pero, si después de un tiempo, te das cuenta que definitivamente no lo es y decides cambiar, ¡puedes hacerlo! Puedes seguir probando con otros lenguajes u otras herramientas hasta que encuentres con lo que realmente te sientes más cómodo o cómoda. Y todo ese tiempo no es tiempo perdido, aprendiste muchas cosas y por sobre todo, aprendiste a identificar qué es lo que te gusta.&lt;/p&gt;

&lt;p&gt;Eso es todo por ahora, nos vemos pronto 👋🏻.&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>programming</category>
      <category>discuss</category>
      <category>spanish</category>
    </item>
    <item>
      <title>Frontend developer: ¿Sólo debe maquetar?</title>
      <dc:creator>Lucho Peñafiel</dc:creator>
      <pubDate>Mon, 18 Jul 2022 13:34:27 +0000</pubDate>
      <link>https://forem.com/luchopenafiel/frontend-developer-solo-debe-maquetar-3a07</link>
      <guid>https://forem.com/luchopenafiel/frontend-developer-solo-debe-maquetar-3a07</guid>
      <description>&lt;p&gt;¡Hola! En este post quiero hablar sobre la pregunta &lt;strong&gt;¿un frontend developer, sólo debe maquetar?&lt;/strong&gt; y mi opinión sobre ella.&lt;/p&gt;

&lt;p&gt;Antes de responder la pregunta, veamos algo de historia y de dónde surge esta duda. Hasta hace unos años, cuando el 99.99% de los sitios webs estaban construidos en PHP, el desarrollador tenía un perfil más fullstack (tema que veremos en otro post). Generalmente se construían web apps monolíticas donde PHP se usaba como generador de plantillas. Entonces, en ese contexto, o eras un desarrollador que hacía la maqueta y la lógica, o solo te encargabas del HTML y CSS, y el backend developer se encarga de desmenuzar ese código y ponerlo en las vistas de la aplicación.&lt;/p&gt;

&lt;p&gt;Pero hoy, en la mayoría de los casos y para alegría de muchos, la cosa es diferente. ¿Un frontend developer debe maquetar? ¡Por supuesto! Debe sentirse extremadamente cómodo con HTML y CSS, pero desde mi punto de vista, eso es solo la base. Veamos algunas tecnologías y responsabilidades que entiendo que un frontend developer hoy en día debe dominar:&lt;/p&gt;

&lt;h2&gt;
  
  
  HTML
&lt;/h2&gt;

&lt;p&gt;Lucho, ¿me estas tomando el pelo no? Pues no, HTML es un lenguaje sencillo de aprender pero que tiene muchos detalles, y no todos los conocen y dominan el arte de usarlos correctamente. Cuando digo "usarlo correctamente" me refiero desde definir el lenguaje de la página hasta evitar cosas como la divitis (divitis: dícese del uso indiscriminado del tag HTML &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt;)y escribir HTML semánticamente correcto.&lt;/p&gt;

&lt;h2&gt;
  
  
  CSS
&lt;/h2&gt;

&lt;p&gt;Parece una obviedad que CSS esté en esta lista, pero como dije más arriba, junto con HTML son las bases de un frontend developer. Debes sentirte cómodo usando media-queries, flex-box y grid.&lt;/p&gt;

&lt;h2&gt;
  
  
  JavaScript
&lt;/h2&gt;

&lt;p&gt;Ahora sí se va poniendo interesante. Cuando digo JavaScript no me refiero a algún framework de moda como React, Angular, Vue, etc, me refiero a entender cómo funciona el lenguaje, entender &lt;em&gt;the good parts&lt;/em&gt; y &lt;em&gt;the tough parts&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;No me mal interpretes, no estoy diciendo que no sea importante saber React, lo que digo es que tal vez en unos años estemos hablando de React como hoy lo hacemos de jQuery, y ¿qué tienen en común esas dos tecnologías? JavaScript.&lt;/p&gt;

&lt;p&gt;Hoy JavaScript no solo se usa en la web, tiene muchos usos y ¡cada vez son más! Por lo que recomiendo que entiendas cómo funciona este lenguaje. Para esto a continuación dejo dos recursos que a mi me ayudaron bastante a lograr eso:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/leonardomso/33-js-concepts"&gt;33 Concepts Every JavaScript Developer Should Know&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/getify/You-Dont-Know-JS/blob/1st-ed/README.md"&gt;You Don't Know JS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  SEO
&lt;/h2&gt;

&lt;p&gt;¿Por qué necesitas saber de SEO (del inglés Search Engine Optimization)? Porque en el 99% de los casos vas a querer que la web que estas construyendo sea visitada por la mayor cantidad de usuarios posibles.&lt;/p&gt;

&lt;p&gt;Probablemente hayas entrado en discusiones eternas con equipos de marketing sobre SEO o algún cliente te haya dicho algo como "quiero que mi web aparezca primero en Google", y lograr que un sitio web se encuentre entre los primeros puestos de los resultados de búsquedas depende de muchos factores y de un gran y largo trabajo en equipo.&lt;/p&gt;

&lt;p&gt;En este post no entraremos en detalle sobre todos los aspectos del SEO, pero es importante que conozcan los aspectos básicos del mismo y las buenas prácticas que contribuyen a un buen SEO. Comparto una &lt;a href="https://moz.com/beginners-guide-to-seo"&gt;guía de MOZ&lt;/a&gt; para ayudarles con esto.&lt;/p&gt;

&lt;p&gt;Y en el caso de que luego quieras dar un salto más profundo sobre este tema, te recomiendo leer sobre &lt;a href="https://schema.org/"&gt;datos estructurados&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Performance
&lt;/h2&gt;

&lt;p&gt;A mí me gusta usar la frase "cuando navego un sitio web, me gusta sentir el viento en la cara" haciendo alusión a que el sitio web debe andar muy rápido. Pero la performance no es solo hacer que los sitios webs sean rápidos, sino también consiste en hacer que los procesos lentos parezcan rápidos.&lt;/p&gt;

&lt;p&gt;Probablemente pienses que tu sitio web anda muy rápido, y tal vez así sea, pero debes entender que siempre hay margen para mejorar, la performance es algo con lo que debes estar comprometido a largo plazo. Para esto hay un muchas cosas que se deben optimizar, como imágenes, videos, fonts, renderizado, request y largo etc. A continuación dejo dos guías, con contenido de excelente calidad, que van desde conceptos básicos (cómo funciona internet) a detalles súper minúsculos pero súper importantes.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Learn/Performance"&gt;Web performance - MDN Web Docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://web.dev/fast/"&gt;Fast load times - web.dev&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Accesibilidad
&lt;/h2&gt;

&lt;p&gt;La accesibilidad no debe entenderse como una feature de tu sitio web, sino como algo integral del mismo.&lt;/p&gt;

&lt;p&gt;Te invito a que mires mi post &lt;a href="https://dev.to/luchopenafiel/accesibilidad-breve-introduccion-hacia-una-web-inclusiva-3eb3"&gt;Accesibilidad: breve introducción hacia una web inclusiva&lt;/a&gt; en el cual introduzco los conceptos básicos y dejo recursos para profundizar más sobre el tema.&lt;/p&gt;

&lt;h2&gt;
  
  
  Nice to have
&lt;/h2&gt;

&lt;p&gt;De mas está decir que todo lo que puedas aprender siempre es bienvenido, pero para ir terminando este post dejo una lista con otros temas que al dominarlos harán que des un salto de calidad como frontend developer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Unit testing&lt;/li&gt;
&lt;li&gt;Docker&lt;/li&gt;
&lt;li&gt;CI/CD&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Mejora cada día
&lt;/h2&gt;

&lt;p&gt;Estudiar y dominar los temas mencionados anteriormente es un camino largo y puede llevar tiempo, mi intención no es agobiar, sino darles una guía con los temas y herramientas que a mí me hubiera gustado tener cuando entré en este mundo.&lt;/p&gt;

&lt;p&gt;Y como último consejo que puedo darte es que seas curiosa/o, investiga, lee y aprende algo nuevo cada día. Como reza la famosa frase, nuca pares de aprender.&lt;/p&gt;

&lt;p&gt;Eso es todo por ahora, nos vemos pronto 👋🏻.&lt;/p&gt;

</description>
      <category>frontend</category>
      <category>beginners</category>
      <category>webdev</category>
      <category>spanish</category>
    </item>
    <item>
      <title>Cómo implementar variable fonts</title>
      <dc:creator>Lucho Peñafiel</dc:creator>
      <pubDate>Mon, 18 Jul 2022 13:03:32 +0000</pubDate>
      <link>https://forem.com/luchopenafiel/como-implementar-variable-fonts-32ek</link>
      <guid>https://forem.com/luchopenafiel/como-implementar-variable-fonts-32ek</guid>
      <description>&lt;p&gt;Antes de aprender a implementar variable fonts, tenemos que entender qué son, y para esto primero debemos entender la diferencia entre estilo tipográfico y familia tipográfica.&lt;/p&gt;

&lt;p&gt;Un estilo tipográfico es un tipo de letra único y específico, como puede ser regular o &lt;strong&gt;bold&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Un estilo tipográfico es un tipo de letra único y específico, como puede ser regular, o regular italic, o bold italic.&lt;/p&gt;

&lt;p&gt;Dicho esto, podemos definir a las variable fonts como un solo archivo que contiene todos los estilos. Es decir, podemos tener la familia entera, dentro de un solo archivo.&lt;/p&gt;

&lt;p&gt;Ahora si, vamo a codea.&lt;/p&gt;

&lt;h2&gt;
  
  
  1) Descargar una variable fonts.
&lt;/h2&gt;

&lt;p&gt;Para este ejemplo vamos a descargar &lt;a href="https://fonts.google.com/specimen/Roboto+Mono?query=roboto&amp;amp;preview.text_type=custom"&gt;Roboto Mono desde Google Fonts&lt;/a&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hacemos click en el botón "Download family", eso descargará un archivo comprimido.&lt;/li&gt;
&lt;li&gt;Descomprimimos el archivo.&lt;/li&gt;
&lt;li&gt;Vamos a tener un folder llamado Roboto_Mono y en su raíz un archivo RobotoMono-VariableFont_wght.ttf. Ese es nuestro archivo!&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  2) Definir la variable fonts.
&lt;/h2&gt;

&lt;p&gt;Una vez que tengamos descargada nuestra font, necesitamos definirlas en nuestro proyecto y para eso usamos la regla &lt;code&gt;@font-face&lt;/code&gt; de CSS de tal manera que nos quede algo así:&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="k"&gt;@font-face&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;font-family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;'Roboto Mono'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;src&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sx"&gt;url('/fonts/RobotoMono-VariableFont.ttf')&lt;/span&gt; &lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;'truetype-variations'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;font-weight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt; &lt;span class="m"&gt;700&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;Del código anterior, tienes que en cuenta dos cosas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Si bien es un archivo &lt;code&gt;.ttf&lt;/code&gt; el format es levemente distinto al que estamos acostumbrados.&lt;/li&gt;
&lt;li&gt;En la property &lt;code&gt;font-weight&lt;/code&gt; definimos el rango en el cual podemos mover el peso de la font. Acá no podemos definir cualquier valor, sino los que la font acepte. Google Fonts nos indica cuales son estos límites.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg6pdu8ipxvk6dn94blao.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg6pdu8ipxvk6dn94blao.jpg" alt="font weight limits" width="800" height="301"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  3) Usar las font definida.
&lt;/h2&gt;

&lt;p&gt;Ya descargamos nuestra font y ya está definida, lo que resta simplemente es utilizarla y esto se hace igual que con cualquier otra font.&lt;/p&gt;

&lt;p&gt;Por ejemplo:&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;p&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;font-family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;'Roboto Mono'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;font-weight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;548&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c"&gt;/* Acá podemos usar cualquier valor entre 100 y 700 */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  4) Optimizar, siempre optimizar.
&lt;/h2&gt;

&lt;p&gt;Si llegaste a este punto sin problemas y ya tienes tus variable fonts andando, te recomiendo que pases por el post en el que doy algunos consejos sobre &lt;a href="https://dev.to/luchopenafiel/web-performance-fonts-hpo"&gt;cómo optimizar tus fonts&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>webdev</category>
      <category>performance</category>
      <category>spanish</category>
    </item>
    <item>
      <title>Web Performance: Imágenes</title>
      <dc:creator>Lucho Peñafiel</dc:creator>
      <pubDate>Mon, 18 Jul 2022 10:39:18 +0000</pubDate>
      <link>https://forem.com/luchopenafiel/web-performance-imagenes-1n6a</link>
      <guid>https://forem.com/luchopenafiel/web-performance-imagenes-1n6a</guid>
      <description>&lt;p&gt;Las imágenes representan al rededor del 50% del ancho de banda de un sitio web (&lt;a href="https://developer.mozilla.org/en-US/docs/Learn/Performance/Multimedia"&gt;ref.&lt;/a&gt;), por eso es que en este artículo vamos a hablar de ellas.&lt;/p&gt;

&lt;p&gt;Veamos algunos puntos a tener en cuenta.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Realmente necesitas una imagen ahí?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Una imagen vale más que mil palabras&lt;/strong&gt;. Seguramente escuchaste esa frase, y es una gran verdad, como también lo es el hecho de que un diseño simple y concreto transmite mejor lo que queremos decir, y performa mejor 😉.&lt;/p&gt;

&lt;p&gt;Entonces, lo primero que debemos preguntarnos (o preguntarle a nuestros diseñadores) es si ese componente necesita de forma imperativa una imagen para funcionar.&lt;/p&gt;

&lt;p&gt;Tal vez esa imagen podría ser reemplazada por un color plano, o un gradiente, y en ambos casos podríamos generar esto con CSS y ahorrarnos un montón de bytes de esa imagen.&lt;/p&gt;

&lt;p&gt;Ojo, no estoy diciendo que elimines todas las imágenes de tu sitio web, sino que encuentres un equilibro entre el uso de las mismas y otros recursos.&lt;/p&gt;

&lt;p&gt;Si luego de analizar las alternativas, llegas a la conclusión de que si o si necesitas una imagen ahí, perfecto, ¡tienes mucho trabajo que hacer!&lt;/p&gt;

&lt;h2&gt;
  
  
  Formatos
&lt;/h2&gt;

&lt;p&gt;Cuando decidimos trabajar con imágenes, es muy importante que definamos el formato de la misma. Veamos algunos formatos y sus características:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;JPG&lt;/strong&gt;: se trata de un formato de imágenes optimizado. Tiene perdida de calidad.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PNG&lt;/strong&gt;: se trata de un formato que además de admitir transparencias preserva la calidad de la imagen, pero suelen ser archivos muy pesados.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;WebP&lt;/strong&gt;: se trata de un formato relativamente moderno que fue impulsado por Google. Este formato acepta transparencias, no tiene perdida de calidad y se trata de archivos muy pequeños. Es el formato altamente recomendado y ya la mayoría de los browsers lo implementan. &lt;a href="https://caniuse.com/webp"&gt;Ver compatibilidad&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Para asegurarte de que todos tus usuarios van a visualizar correctamente las imágenes, incluso los que visiten el sitio desde navegadores antiguos, puedes darle opciones de carga al browser mediante la etiqueta &lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt; de la siguiente manera:&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;picture&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;source&lt;/span&gt;
    &lt;span class="na"&gt;srcset=&lt;/span&gt;&lt;span class="s"&gt;"gatitos.webp"&lt;/span&gt;
    &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"image/webp"&lt;/span&gt;
  &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;source&lt;/span&gt;
    &lt;span class="na"&gt;srcset=&lt;/span&gt;&lt;span class="s"&gt;"gatitos.jpg"&lt;/span&gt;
    &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"image/jpg"&lt;/span&gt;
  &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt;
    &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"gatitos.jpg"&lt;/span&gt;
    &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"Gatitos jugando con una pelota."&lt;/span&gt;
    &lt;span class="err"&gt;{&lt;/span&gt;&lt;span class="na"&gt;*&lt;/span&gt; &lt;span class="err"&gt;¡&lt;/span&gt;&lt;span class="na"&gt;SPOILER&lt;/span&gt; &lt;span class="na"&gt;ALERT&lt;/span&gt;&lt;span class="err"&gt;!&lt;/span&gt; &lt;span class="na"&gt;*&lt;/span&gt;&lt;span class="err"&gt;}&lt;/span&gt;
    &lt;span class="na"&gt;loading=&lt;/span&gt;&lt;span class="s"&gt;"lazy"&lt;/span&gt; 
  &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/picture&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Dimensiones&lt;/p&gt;

&lt;p&gt;Cómo las imágenes se cargan de forma asincrónica y continúan cargándose después de la primera pintura del DOM, si sus dimensiones no se definen antes de la carga, pueden provocar saltos o "reflujos" en el contenido de la página. Y esto tiene dos implicancias negativas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;El navegador debe volver a pintar el DOM y a realizar nuevos cálculos de los elementos que están a continuación de la imagen cargada.&lt;/li&gt;
&lt;li&gt;Estos saltos son molestos para el usuario y generan una mala experiencia.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ejemplos:&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc9nhmh2f03bt1wf5wlai.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc9nhmh2f03bt1wf5wlai.gif" alt='Imagen sin definición de tamaños genera "reflow" en el contenido.' width="674" height="398"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Imagen sin definición de tamaños genera "reflow" en el contenido.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frdghyoc6f0icox2qpfoa.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frdghyoc6f0icox2qpfoa.gif" alt='Imagen con tamaños definidos no genera "reflow".' width="674" height="398"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Imagen con tamaños definidos no genera "reflow".&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Carga diferida
&lt;/h2&gt;

&lt;p&gt;Supongamos que nuestra página tiene tanto contenido que el usuario necesita hacer varios scrolls antes de llegar al final de la misma. Supongamos también que el usuario al ingresar, hizo click en alguna de las opciones del menú y navegó hacía otra página.&lt;/p&gt;

&lt;p&gt;Entonces las imágenes que están en los componentes que solo se visualizan al hacer scroll el usuario nunca las vio, pero las tuvo que descargar igual, ¿no? Hm 🤔.&lt;/p&gt;

&lt;p&gt;Para resolver este problema es qué tenemos que hacer uso de la carga diferida de imágenes, es decir, indicarle al browser que cargue las imágenes solo si el usuario las necesita. ¿Cómo hacemos esto? Tenemos dos maneras:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Los navegadores modernos (&lt;a href="https://caniuse.com/loading-lazy-attr"&gt;ver compatibilidad&lt;/a&gt;) implementan de forma nativa la carga diferida de imágenes, y para esto debemos usar el atributo &lt;code&gt;&amp;lt;img loading="lazy" src="gatitos.jpg" alt="Gatitos jugando con una pelota" /&amp;gt;&lt;/code&gt;. De esta manera, el browser solo cargará dicha imagen cuando el usuario se encuentre cerca de ella.&lt;/li&gt;
&lt;li&gt;Haciendo uso de la API del navegador &lt;strong&gt;Interserction Observer&lt;/strong&gt;, la cual nos permite hacer lo mismo que el punto anterior pero "programáticamente". Te dejo un link para que veas la &lt;a href="https://developer.mozilla.org/es/docs/Web/API/Intersection_Observer_API"&gt;documentación de esta API&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  CSS
&lt;/h2&gt;

&lt;p&gt;Muchas veces usamos imágenes como fondos desde CSS. No está mal hacer eso, en absoluto, pero te dejo algunas recomendaciones a tener en cuenta para cuando lo hagas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;El browser asigna una prioridad de carga más alta a las imágenes referenciadas en elementos &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; que las imágenes referenciadas desde CSS.&lt;/li&gt;
&lt;li&gt;Las imágenes referenciadas desde CSS son invisibles a los lectores de pantalla, por lo tanto dichas imágenes no existirán para algunos usuarios.&lt;/li&gt;
&lt;li&gt;Si el navegador ha determinado que una regla CSS que involucra un recurso externo no se aplica al documento como está construido actualmente, el navegador no lo solicita. Es decir, si defines una imagen dentro de una media query, esta solo se cargará cuando se aplique esa regla.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Y eso es todo por ahora, nos vemos pronto 👋🏻. &lt;/p&gt;

</description>
      <category>webdev</category>
      <category>performance</category>
      <category>spanish</category>
    </item>
    <item>
      <title>Web Performance - Cómo optimizar tus tipografías</title>
      <dc:creator>Lucho Peñafiel</dc:creator>
      <pubDate>Fri, 20 Nov 2020 10:47:44 +0000</pubDate>
      <link>https://forem.com/luchopenafiel/web-performance-fonts-hpo</link>
      <guid>https://forem.com/luchopenafiel/web-performance-fonts-hpo</guid>
      <description>&lt;p&gt;¿Por qué vamos a hablar de fuentes? Las fuentes y tipografías están en la web desde sus inicios, porque para esto fue creada, para compartir documentos.&lt;/p&gt;

&lt;p&gt;Con el paso del tiempo se fueron agregando elementos de diseño como imágenes, grillas y fuentes personalizadas. Hoy en día no existe sitio web que no contenga texto, y en la gran mayoría estos se renderizan con fuentes personalizadas.&lt;/p&gt;

&lt;p&gt;Entonces podemos afirmar con bastante seguridad que las fuentes son un recurso importante y debemos prestarle atención.&lt;/p&gt;

&lt;p&gt;Pero, ¿cómo podemos hacer para mejorar la performance sobre este tema? Veamos algunos puntos a trabajar.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Self-hosted&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Las fuentes deben ser self-hosted. Es decir, las fuentes deben ser parte de nuestro proyecto y debemos tratar de evitar a toda costa cargar fuentes de CND externas como por ejemplo de Google Fonts.&lt;/p&gt;

&lt;p&gt;¿Por qué? Porque traer recursos desde orígenes externos genera nuevas conexiones HTTP y varios viajes de ida y vuelta a ese origen.&lt;/p&gt;

&lt;p&gt;¿Viajes de ida y vuelta? What? 🤔 Te recomiendo &lt;a href="https://developer.mozilla.org/en-US/docs/Web/Performance/How_browsers_work"&gt;este artículo&lt;/a&gt; si no sabes de que estoy hablando.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Subsetting &amp;amp; convert format&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Los archivos de fuentes suelen ser super pesados. Cuando se descargan de Google Fonts generalmente una sola variante tipográfica pesa aproximadamente 250kb. Si necesitamos 4 variantes como regular, light, regular italic y bold por ejemplo, nuestro usuario debe descargar 1mb solo para leer el contenido. 😱&lt;/p&gt;

&lt;p&gt;Entonces, lo primero que podemos hacer es un subsetting de las fuentes, es decir, eliminar todos lo glifos o caracteres que nada tienen que ver con el idioma del sitio que estemos construyendo. EJ: generalmente todo lo que no sea latín.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fpkv4br1dg7j9v7zf8iv0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fpkv4br1dg7j9v7zf8iv0.png" alt="Captura de Pantalla 2020-11-19 a la(s) 07.22.43" width="800" height="299"&gt;&lt;/a&gt;&lt;br&gt;
&lt;small&gt;&lt;em&gt;Ejemplo de la fuente Roboto&lt;/em&gt;&lt;/small&gt;&lt;/p&gt;

&lt;p&gt;En &lt;a href="https://everythingfonts.com/subsetter"&gt;este link&lt;/a&gt; te dejo una herramienta en linea para esto.&lt;/p&gt;

&lt;p&gt;Una vez que &lt;em&gt;limpiamos&lt;/em&gt; nuestras fuentes, podemos convertirla a formatos que estén optimizados para web, como WOFF y WOFF2. &lt;/p&gt;

&lt;p&gt;Siempre debemos evitar el uso de fuentes TTF y EOT porque son archivos que por defecto no están comprimidos. El uso de este tipo de fuentes debe ser solo como fallback para dar soporte a navegadores antiguos.&lt;/p&gt;

&lt;p&gt;Acá dejo otra &lt;a href="https://everythingfonts.com/ttf-to-woff2"&gt;herramienta&lt;/a&gt; en línea para esto.&lt;/p&gt;

&lt;p&gt;Luego de aplicar un subsetting y convertidas a un formato optimizado para web, un archivo va a estar pesando entre 15kb y 20kb, una reducción impresionante. 😎&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;strong&gt;Preload&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Bien, pasamos de tener un archivo de 250kb a un archivo que no supera los 20kb. OK, pero esos 20kb de todavía nuestro usuario tiene que descargarlos.&lt;/p&gt;

&lt;p&gt;Para que esta descarga suceda lo antes posible, podemos hacer  un preload a nuestro archivo de fuente para indicarle al navegador que se trata de un recurso prioritario y que empiece a cargarlo cuanto antes.&lt;/p&gt;

&lt;p&gt;Ejemplo:&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;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"preload"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/fonts/roboto.woff2"&lt;/span&gt; &lt;span class="na"&gt;as=&lt;/span&gt;&lt;span class="s"&gt;"font"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"font/woff2"&lt;/span&gt; &lt;span class="na"&gt;crossOrigin=&lt;/span&gt;&lt;span class="s"&gt;"anonymous"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;font-display&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Ya tenemos nuestras fuentes optimizadas e hicimos un preload de las mismas para que estén disponible lo antes posible.&lt;/p&gt;

&lt;p&gt;Pero puede pasar que el contenido se pinte y por algún motivo la fuente todavía no se cargó. Entonces ¿el usuario no va a poder leer el contenido de nuestro sitio hasta que la fuente se cargue?. Y, ¿si la fuente se demora? o ¿nunca se carga?&lt;/p&gt;

&lt;p&gt;Veamos un poco cómo funcionan los distintos navegadores en cuanto a la estrategia de renderizado de fuentes.&lt;/p&gt;

&lt;p&gt;Safari oculta el texto hasta que la fuente se haya descargado. Chrome y Firefox ocultan el texto por 3 segundos, si en ese tiempo la fuente no se cargó, renderizan el texto con la fuente del sistema hasta que la fuente personalizada esté cargada.&lt;/p&gt;

&lt;p&gt;En cualquiera de estos casos el usuario va a ver la pantalla en blanco por un tiempo.&lt;/p&gt;

&lt;p&gt;¿Cómo podemos resolver este problema? ¡CSS al rescate! 🦸&lt;/p&gt;

&lt;p&gt;La propiedad &lt;code&gt;font-face&lt;/code&gt; sirve para indicarle al navegador qué estrategia seguir en cuanto a al renderizado de fuentes.&lt;/p&gt;

&lt;p&gt;Los valores que acepta esta propiedad son auto, block, swap, fallback, optional. Pero el valor que nos interesa es &lt;code&gt;swap&lt;/code&gt;, porque le indica al navegador que muestre el texto de manera inmediata con las fuentes del sistema, y cuando la fuente personaliza esté lista para usarse, haga el reemplazo.&lt;/p&gt;

&lt;p&gt;Ejemplo:&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="k"&gt;@font-face&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;font-family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;'Roboto Mono'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;src&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sx"&gt;url('/fonts/RobotoMono-Regular.woff2')&lt;/span&gt; &lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;'woff2'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;font-weight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;400&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;font-display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;swap&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;De esta manera nuestro usuario va a poder leer el contenido de nuestro sitio de manera inmediata, sin tener que esperar.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Variable fonts&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Y cuando creías que ya no podías optimizar más, aparecen las &lt;em&gt;variable fonts&lt;/em&gt; o fuentes variables.&lt;/p&gt;

&lt;p&gt;Pero antes de definir que son las variable fonts, debemos entender la diferencia entre estilo tipográfico y familia tipográfica.&lt;/p&gt;

&lt;p&gt;Un &lt;strong&gt;estilo tipográfico&lt;/strong&gt; es un tipo de letra &lt;strong&gt;único y específico&lt;/strong&gt;, como puede ser regular, o &lt;em&gt;regular italic&lt;/em&gt;, o &lt;strong&gt;&lt;em&gt;bold italic&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Una &lt;strong&gt;familia tipográfica&lt;/strong&gt; es el conjunto de estilos.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ftzg39f8qtctnwz7vpupv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ftzg39f8qtctnwz7vpupv.png" alt="roboto-family-specimen" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ahora que ya tenemos claro está diferencia, podemos definir a las variable fonts como un solo archivo que contiene todos los estilos. Es decir, podemos tener la familia entera, dentro de un solo archivo.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fua7o1jyvi8krzi3p5y57.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fua7o1jyvi8krzi3p5y57.gif" alt="Grabación de pantalla 2020-11-20 a la(s) 09.09.33" width="800" height="213"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Eso es todo por ahora, voy a estar subiendo más artículos de web performance ⚡️&lt;/p&gt;

&lt;p&gt;Nos vemos pronto 👋🏻&lt;/p&gt;

</description>
      <category>css</category>
      <category>performance</category>
      <category>webdev</category>
      <category>spanish</category>
    </item>
    <item>
      <title>Accesibilidad: breve introducción hacia una web inclusiva</title>
      <dc:creator>Lucho Peñafiel</dc:creator>
      <pubDate>Sat, 24 Oct 2020 09:51:18 +0000</pubDate>
      <link>https://forem.com/luchopenafiel/accesibilidad-breve-introduccion-hacia-una-web-inclusiva-3eb3</link>
      <guid>https://forem.com/luchopenafiel/accesibilidad-breve-introduccion-hacia-una-web-inclusiva-3eb3</guid>
      <description>&lt;p&gt;Muchas veces al hablar de accesibilidad lo primero que pensamos es en hacer una sitio para personas con capacidad visual totalmente nula. Esto es correcto, pero solo en parte. ¿Por qué? Porque la accesibilidad consiste en que cualquier persona pueda usar e interactuar con nuestra web, sin depender de sus capacidades físicas.&lt;/p&gt;

&lt;p&gt;En este artículo vamos a hablar sobre 4 puntos importantes en los que puedes trabajar para mejorar la accesibilidad de un sitio web:&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;1. Color y contraste&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Trabajar sobre este punto significa lograr que el contraste de luminosidad entre el texto y el color del fondo sea lo suficientemente bueno para que el texto se pueda leer sin dificultad alguna.&lt;/p&gt;

&lt;p&gt;Para medir si los textos son accesibles puedes usar las herramientas de desarrollador que provee Google Chrome.&lt;/p&gt;

&lt;p&gt;Al posicionarte sobre un texto, Chrome te indica el de puntaje de contraste y con una marca verde si &lt;em&gt;pasa accesibilidad&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fgufo4w1fxnxivtps9oms.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fgufo4w1fxnxivtps9oms.png" alt="Captura de Pantalla 2020-10-22 a la(s) 14.09.42" width="241" height="258"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Puntos a tener en cuenta:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Revisa tus textos y ajusta el color o tamaño de los mismos.&lt;/li&gt;
&lt;li&gt;Puedes agregar sombras o fondos a los textos para generar más contraste.&lt;/li&gt;
&lt;li&gt;No uses únicamente el color para transmitir información. Por ejemplo: si quieres indicar que hay un error en un input, no solo pintes sus bordes de rojo, sino también agrega un icono o algún mensaje.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;2. Navegación por teclado&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Cualquier usuario de nuestro sitio debe poder navegar e interactuar con él solo con el teclado, es decir, sin mouse o trackpad.&lt;/p&gt;

&lt;p&gt;Abre tu sitio y pulsa la tecla tab para ir pasando de elemento en elemento y vas a comprobar si todo lo que haces con el mouse, puedes hacerlo con el teclado.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fhc4f4c5nnwvd834dgtyz.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fhc4f4c5nnwvd834dgtyz.gif" alt="Navegación por teclado" width="508" height="530"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Puntos a tener en cuenta:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Nunca quites los estilos por defecto del &lt;em&gt;focus&lt;/em&gt;. Si no te gustan, cámbialos por otros, pero nunca los quites.&lt;/li&gt;
&lt;li&gt;Sí tienes un modal, arma un array con los elementos &lt;em&gt;focuseables&lt;/em&gt; y genera un loop entre ellos. Al cerrar el modal vuelve el focus al mismo elemento que lo abrió.&lt;/li&gt;
&lt;li&gt;Intenta diseñar la navegación por teclado.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;3. HTML semántico&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Debemos usar las configuraciones correctas y etiquetas apropiadas para el contenido apropiado.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Puntos a tener en cuenta:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Definir el lenguaje correcto del documento es muy importante  para los lectores de pantalla.&lt;/li&gt;
&lt;li&gt;Usar heading (&lt;code&gt;h1&lt;/code&gt;, &lt;code&gt;h2&lt;/code&gt;, &lt;code&gt;h3&lt;/code&gt;, etc) de manera correcta, es decir, que el título sea &lt;em&gt;grande&lt;/em&gt; no significa que siempre va a ser un &lt;code&gt;h1&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;El atributo alt de la etiqueta &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; debe contener un texto descriptivo de la imagen, ya que esto es lo que leerá el screen reader. Si el texto se coloca todo en mayúsculas, el lector de pantalla leerá letra por letra, y si se deja vació, el lector de pantalla omitirá esta imagen.&lt;/li&gt;
&lt;li&gt;Usar las etiquetas &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt; solo para navegaciones, no para acciones.&lt;/li&gt;
&lt;li&gt;Usar &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt; para acciones (abrir un modal, play de un video, etc) y no para navegar.&lt;/li&gt;
&lt;li&gt;Evita bloquear el zoom en dispositivos móviles, piensa en mí, que ayer me recetaron anteojos nuevos 🤓.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;4. Mejora día a día&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Mejorar la accesibilidad de un sitio web no es algo que se logre de un día para otro, ni es algo que se hace una sola vez y ya. Debemos tomar la responsabilidad de mejorar continuamente la accesibilidad de nuestro sitio, ¡tus usuarios lo van a agradecer!&lt;/p&gt;

&lt;p&gt;Para esto, les comparto una &lt;a href="https://wave.webaim.org/"&gt;herramienta para analizar la accesibilidad de un sitio&lt;/a&gt; y una &lt;a href="https://www.accessibility-developer-guide.com/"&gt;guía en la que puedes profundizar sobre estos y más temas de accesibilidad&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Eso es todo por ahora, nos vemos pronto 👋🏻.&lt;/p&gt;

</description>
      <category>a11y</category>
      <category>html</category>
      <category>webdev</category>
      <category>spanish</category>
    </item>
    <item>
      <title>Docker 101: ¿Qué es Docker y para que se usa?</title>
      <dc:creator>Lucho Peñafiel</dc:creator>
      <pubDate>Mon, 28 Sep 2020 22:42:49 +0000</pubDate>
      <link>https://forem.com/luchopenafiel/docker-101-que-es-docker-y-para-que-se-usa-3k71</link>
      <guid>https://forem.com/luchopenafiel/docker-101-que-es-docker-y-para-que-se-usa-3k71</guid>
      <description>&lt;p&gt;Antes de definir qué es Docker, quiero contarles un problema que tuvimos en un proyecto en el que estuve trabajando.&lt;/p&gt;

&lt;p&gt;Con el equipo empezamos configurando nuestro proyecto, definiendo la arquitectura, luego pasamos a la etapa de desarrollo de componentes, test, etc etc. Cuando llegó el momento de hacer un deploy en los ambientes del cliente, nos enteramos que todo ese proceso lo hacían a mano. Entonces, con la idea de que quién vaya a realizar esos deploy lo haga de la manera más fácil posible generamos una documentación de cómo clonar el proyecto, cómo instalar las dependencias y como ejecutarlo.&lt;/p&gt;

&lt;p&gt;Una vez realizado el deploy, nos encontramos con la sorpresa de que nuestra app no corría como debía correr. Luego de debuggear un rato detectamos que el servidor donde estaba corriendo la app tenía instalado la v.14 de Node.js, y nuestra app tenía un lockdown a la v.12 lo que generaba algunos problemas de compatibilidad.&lt;/p&gt;

&lt;p&gt;¿Por qué les cuento esto? Porque esto es uno de los típicos problemas que Docker viene a prevenir que sucedan.&lt;/p&gt;

&lt;p&gt;Ahora si...&lt;/p&gt;

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

&lt;p&gt;Docker puede definirse como una forma de empaquetar software para que pueda ejecutarse en cualquier hardware.&lt;/p&gt;

&lt;p&gt;Siguiendo el caso anterior, Docker nos permite generar un &lt;em&gt;paquete&lt;/em&gt; que contiene todo lo necesario, código fuente, configuraciones y las dependencias, para que nuestra aplicación funcione de la manera adecuada.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sus principales partes
&lt;/h2&gt;

&lt;p&gt;Docker tiene un montón de partes muy interesantes y útiles, como los &lt;em&gt;volumens&lt;/em&gt;, pero en este artículo nos enfocaremos solo en las principales, que son:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Dockerfile&lt;/strong&gt;: el Dockerfile es un archivo que sirve para indicarle a Docker cómo se debe construir la imagen del proyecto. En otras palabras, es la receta que Docker usa para generar un paquete con nuestra aplicación.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Image&lt;/strong&gt;: es un template para ejecutar el proyecto en cualquier contenedor. Una imagen de Docker es nuestro &lt;em&gt;paquete&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Container&lt;/strong&gt;: un container es básicamente, una imagen en ejecución.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  ¿Cómo &lt;em&gt;dockerizar&lt;/em&gt;?
&lt;/h2&gt;

&lt;p&gt;Lo primero que tenemos que hacer es generar nuestro proyecto. Vamos a generar un simple archivo html y un server en express para servir este archivo.&lt;/p&gt;

&lt;p&gt;Para esto, dentro del directorio donde vamos a trabajar, iniciamos un nuevo proyecto con &lt;code&gt;npm init&lt;/code&gt; y dejamos todas las configuraciones por defecto, de tal manera que nos quede un &lt;code&gt;package.json&lt;/code&gt; así:&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;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"docker101"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.0.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"description"&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;"main"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"index.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&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;"test"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"echo &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;Error: no test specified&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; &amp;amp;&amp;amp; exit 1"&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;"author"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Luciano Peñafiel"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"license"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ISC"&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;Lo siguiente que vamos a hacer es crear un archivo &lt;code&gt;index.html&lt;/code&gt; con un simple encabezado y lo colocaremos en un directorio que lo vamos a llamar &lt;code&gt;build&lt;/code&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="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"es"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Docker 101&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Hola mundo!&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A continuación instalamos express ejecutando &lt;code&gt;npm i express&lt;/code&gt; y creamos un archivo &lt;code&gt;server.js&lt;/code&gt; que va a ser el encargado de servir nuestro html y agregamos un script en nuestro &lt;code&gt;package.json&lt;/code&gt; para levantar este server.&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;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;express&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;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;express&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;static&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;build&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/&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="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="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ok&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="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3000&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="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="s2"&gt;`App listening on port http://localhost:3000`&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 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;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"docker101"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.0.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"description"&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;"main"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"index.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&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;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node server.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"echo &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;Error: no test specified&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; &amp;amp;&amp;amp; exit 1"&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;"author"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Luciano Peñafiel"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"license"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ISC"&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;Listo, ya tenemos nuestra app. Ahora solo ejecutamos el comando &lt;code&gt;npm start&lt;/code&gt; y vamos a tener ver nuestra app corriendo en el puerto 3000.&lt;/p&gt;

&lt;h2&gt;
  
  
  ¿Y Docker?
&lt;/h2&gt;

&lt;p&gt;Ahora llegó el momento de trabajar con Docker, y lo primero que tenemos que hacer es instalarlo desde la &lt;a href="https://www.docker.com/"&gt;web oficial de Docker&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Una vez instalado y corriendo, ejecutamos en nuestra terminal el comando &lt;code&gt;docker ps&lt;/code&gt; para ver todas las imágenes que están corriendo actualmente. De momento, no deberíamos tener ninguna, y obtener una respuesta así:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fejiqwqo351imy71kbh1f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fejiqwqo351imy71kbh1f.png" alt="docker ps" width="800" height="127"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Lo siguiente es construir nuestro Dockerfile y para esto creamos en la raíz de nuestro repositorio un archivo con ese nombre (y sin extensión) con el siguiente contenido:&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="s"&gt;FROM node:12-alpine&lt;/span&gt;

&lt;span class="s"&gt;WORKDIR /usr/src/app&lt;/span&gt;

&lt;span class="s"&gt;COPY package*.json ./&lt;/span&gt;

&lt;span class="s"&gt;RUN npm ci&lt;/span&gt;

&lt;span class="s"&gt;COPY . ./&lt;/span&gt;

&lt;span class="s"&gt;CMD ["npm", "start"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Entendamos un poco este archivo. Primero que nada es muy importante entender que cada instrucción funciona como una capa, y Docker intentará mantener en caché cada una de ellas si nada se ha modificado, por lo tanto es recomendable poner primero aquellas capas que menos van a cambiar a lo largo del proyecto.&lt;/p&gt;

&lt;p&gt;Todo Dockerfile empieza con el comando &lt;code&gt;FROM&lt;/code&gt; que sirve para indicarle a Docker cuál va a ser la imagen base de nuestra imagen. Sí, cada imagen parte de otra imagen.&lt;/p&gt;

&lt;p&gt;Lo siguiente que tenemos hacer es agregar el código fuente de nuestra app a la imagen. Para eso primero definimos la raíz del directorio usando la instrucción &lt;code&gt;WORKDIR&lt;/code&gt;. Todo lo siguiente que hagamos va a comenzar desde esa ruta.&lt;/p&gt;

&lt;p&gt;Luego vamos a instalar todas nuestras dependencias usando el comando &lt;code&gt;COPY&lt;/code&gt; que recibe dos argumentos, primero lo que queremos copiar y al último la ubicación donde queremos copiar esos archivos. &lt;/p&gt;

&lt;p&gt;Luego vamos a instalar todo lo que tenemos en nuestro &lt;code&gt;package.json&lt;/code&gt; con el comando &lt;code&gt;RUN npm ci&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Una vez instaladas todas nuestra dependencias, copiamos el código fuente de nuestra app. En este punto se presenta un problema, y es que en los pasos anteriores instalamos nuestras dependencias, lo que generó dentro de la imagen un directorio &lt;code&gt;node_modules&lt;/code&gt; y al copiar todo lo que tenemos en nuestro código fuente, vamos a sobre escribir esos módulos y no es algo que queremos que suceda. Para esto creamos un archivo &lt;code&gt;.dockerignore&lt;/code&gt; (si, igual que un .gitignore) y colocamos dentro &lt;code&gt;node_modules&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Y por último le indicamos a Docker como debe inicializar nuestra app con la instrucción &lt;code&gt;CMD&lt;/code&gt;, que es la instrucción por defecto de Docker para iniciar una imagen.&lt;/p&gt;

&lt;p&gt;Una vez creado nuestro &lt;code&gt;Dockerfile&lt;/code&gt;, ahora sí vamos a generar una imagen del proyecto, y esto lo hacemos con el comando &lt;code&gt;docker build -t docker101:v1 .&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F9d6ahdrp41b4tdno6cxk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F9d6ahdrp41b4tdno6cxk.png" alt="docker build -t docker101-v1" width="800" height="299"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;¿Qué hace esto? Bien, &lt;code&gt;docker build&lt;/code&gt; va a generar nuestra imagen, y con el flag &lt;code&gt;-t docker101:v1&lt;/code&gt; le asignamos una etiqueta a nuestra imagen y le indicamos que está en la versión 1.&lt;/p&gt;

&lt;p&gt;Ahora si corremos el comando &lt;code&gt;docker images&lt;/code&gt; vamos a ver todas las imágenes que tenemos en nuestro Docker con sus respectivos IDs.&lt;/p&gt;

&lt;p&gt;Y por fin llegó la hora de ejecutar nuestra app dentro de un contenedor, esto lo hacemos con el comando &lt;code&gt;docker run -p 3000:3000 docker101:v1&lt;/code&gt; y &lt;em&gt;voila,&lt;/em&gt; tenemos nuestra app corriendo en el puerto 3000.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fe33rd0ksq17q5yjh78o2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fe33rd0ksq17q5yjh78o2.png" alt="Hola mundo" width="800" height="509"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;La idea, siguiendo el ejemplo del principio, es entregarle a nuestro cliente todo empaquetado. Y ¿cómo hacemos esto? Bueno, hay muchas maneras de hacerlo, pero la más usada es subiendo nuestra imagen a un &lt;em&gt;registry&lt;/em&gt; de imágenes como los es Docker Hub o GitHub Packages para que luego nuestro cliente pueda descargar la imagen.&lt;/p&gt;

&lt;p&gt;Eso es todo por ahora, nos vemos pronto 👋🏻.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>devops</category>
      <category>spanish</category>
    </item>
  </channel>
</rss>
