<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ Node.js - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Descubre miles de cursos de programación escritos por expertos. Aprende Desarrollo Web, Ciencia de Datos, DevOps, Seguridad y obtén asesoramiento profesional para desarrolladores. ]]>
        </description>
        <link>https://www.freecodecamp.org/espanol/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ Node.js - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/espanol/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Sat, 16 May 2026 13:48:29 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/espanol/news/tag/node-js/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ Cómo escribir Pruebas usando el Ejecutor de Pruebas de Node.js y mongodb-memory-server ]]>
                </title>
                <description>
                    <![CDATA[ Recientemente migré algunas pruebas de Jest al ejecutor de pruebas de Node.js en dos de mis proyectos que usan MongoDB. En uno de esos proyectos, el tiempo de ejecución de las pruebas fue reducido de 107 segundos a 25 segundos (captura de pantalla abajo). En el otro proyecto, el tiempo ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/como-escribir-pruebas-usando-el-ejecutor-de-pruebas-de-node-js-y-mongodb-memory-server/</link>
                <guid isPermaLink="false">67bd1d95f9cd6804c5816fa9</guid>
                
                    <category>
                        <![CDATA[ nodejs ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Node ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Node.js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ MongoDB ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Mongo ]]>
                    </category>
                
                    <category>
                        <![CDATA[ pruebas unitarias ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Elias Ezequiel Pereyra Gomez ]]>
                </dc:creator>
                <pubDate>Tue, 15 Apr 2025 14:27:15 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2025/02/Captura-desde-2025-02-24-22-33-31.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artículo original:</strong> <a href="https://www.freecodecamp.org/news/how-to-write-tests-using-the-nodejs-test-runner-and-mongodb-memory-server/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">How to Write Tests Using the Node.js Test Runner and mongodb-memory-server</a>
      </p><p>Recientemente migré algunas pruebas de Jest al ejecutor de pruebas de Node.js en dos de mis proyectos que usan MongoDB. En uno de esos proyectos, el tiempo de ejecución de las pruebas fue reducido de 107 segundos a 25 segundos (captura de pantalla abajo). En el otro proyecto, el tiempo de ejecución de las pruebas fue reducido cerca de un 66%.</p><figure class="kg-card kg-image-card"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1738830673460/1560f7a3-38c1-42f3-8944-df06b40d73e4.png" class="kg-image" alt="76% reduction in time taken to run tests in Jest vs Node.js test runner" width="560" height="478" loading="lazy"></figure><p>Decidí compartirte cómo pude implementarlo. Pienso que te será de utilidad, ya que es más rentable (en términos de reducir dinero gastado en ejecutar pruebas en CI/CD), y también mejora tu experiencia de desarrollo.</p><h2 id="tabla-de-contenidos"><strong>Tabla de Contenidos</strong></h2><ul><li><a href="#pre-requisitos">Pre-requisitos</a></li><li><a href="#ejecutor-pruebas-nodejs">El Ejecutor de Pruebas de Node.js</a></li><li><a href="#servidor-memoria-mongodb">El Servidor en memoria de MongoDB</a></li></ul><!--kg-card-begin: markdown--><ul>
<li><a href="#como-escribir-pruebas">Cómo escribir las Pruebas</a>
<ol>
<li><a href="#configurar-proyecto">Configurar el Proyecto</a></li>
<li><a href="#configurar-esquema-mongoose">Configurar el Esquema de Mongoose</a></li>
<li><a href="#configurar-servicios">Configurar los Servicios</a></li>
<li><a href="#configurar-pruebas">Configurar las Pruebas</a></li>
<li><a href="#escribir-pruebas">Escribir las Pruebas</a></li>
<li><a href="#pasar-pruebas">Pasar las Pruebas</a></li>
<li><a href="#usa-typescript-opcional">Usar TypeScript (Opcional)</a></li>
</ol>
</li>
</ul>
<!--kg-card-end: markdown--><ul><li><a href="#conclusion">Conclusión</a></li></ul><!--kg-card-begin: html--><h2 id="pre-requisitos">Pre-requisitos</h2><!--kg-card-end: html--><p>Para seguir esta guía, deberías de tener experiencia trabajando con Node.js, MongoDB y Mongoose (o cualquier otro mapeador de datos de objetos de MongoDB). Deberías también tener instalado Node.js (al menos la versión 20.18.2) y MongoDB (Compass la versión GUI) en tu computadora.</p><!--kg-card-begin: html--><h2 id="ejecutor-pruebas-nodejs">El Ejecutor de Pruebas de Node.js</h2><!--kg-card-end: html--><p>El ejecutor de pruebas de Node.js fue introducido como una característica experimental en la versión 18 de Node.js. Se volvió disponible oficialmente en la versión 20. Te da la habilidad de:</p><ol><li>Ejecutar pruebas</li><li>Reportar resultados de las pruebas</li><li>Reportar cobertura de las pruebas (todavía experimental en la versión 23)</li></ol><p>Es una buena idea el usar el ejecutor de pruebas incorporado cuando se escriban pruebas en Node.js porque significa que tienes que usar menos dependencias externas. No necesitas instalar una librería externa (y sus dependencias entre pares) para ejecutar las pruebas.</p><p>El mejor ejecutor incorporado también es el más rápido. Basado en mi experiencia usándolo en dos proyectos (los cuales usaron Jest), vi mejoras de al menos una reducción del 66% en el tiempo que tomó ejecutar las pruebas completamente.</p><p>Y a diferencia de otros frameworks o librerías de pruebas, el ejecutor de pruebas de Node.js fue construido especialmente para proyectos de Node.js. No trata de acomodar las especificaciones de otros entornos de programación como el navegador. Las especificaciones de Node.js son su principal y única prioridad.</p><!--kg-card-begin: html--><h2 id="servidor-memoria-mongodb">El Servidor en memoria de MongoDB</h2><!--kg-card-end: html--><p>Para las pruebas que involucran el hacer peticiones a una base de datos, algunos desarrolladores prefieren imitar las peticiones para evitar hacer peticiones a una base de datos real. Hacen esto porque hacer una petición a una base de datos real requiere un montón de configuraciones que puede costar tiempo y recursos.</p><p>Escribir y solicitar datos usando una base de datos real es más lento <a href="https://www.mongodb.com/resources/basics/databases/in-memory-database">comparado con escribir y solicitar datos de la memoria</a>. Cuando se ejecutan pruebas automatizadas, usando un servidor de MongoDB real será más lento que usar un servidor de base de datos en memoria, y ahí es donde <a href="https://github.com/typegoose/mongodb-memory-server">mongodb-memory-server</a> se vuelve útil.</p><figure class="kg-card kg-image-card"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1738832586702/62360547-70e8-4e74-854f-c7ad74d182ea.png" class="kg-image" alt="Comparison between memory and database communication with CPU" width="631" height="256" loading="lazy"></figure><p>Según su documentación, mongodb-memory-server crea y comienza un servidor de MongoDB real de forma programática desde dentro de Node.js, pero usa una base de datos en memoria por defecto. También te permite conectar el servidor de base de datos que crea usando tu mapeador de datos de objetos preferido tales como Mongoose, Prisma, o TypeORM. En esta guía, usaremos <a href="https://mongoosejs.com/">Mongoose</a> (v.8.9.6).</p><p>Ya que los datos almacenados por mongodb-memory-server reside en la memoria por defecto, es más rápido leer y escribir en él que cuando se usa una base de datos real. mongodb-memory-server también es más fácil de configurar. Estos beneficios lo hace una buena elección para usarlo como un servidor de base de datos para escribir pruebas.</p><p><strong>Nota</strong>: asegúrate de instalar la versión 9.1.6 de mongodb-memory-server para seguir esta guía. La versión 10 actualmente tiene problemas con limpiar los recursos después que se hacen las pruebas. Mira este problema con el título "<a href="https://github.com/typegoose/mongodb-memory-server/issues/912">Node forking will include any <code>--import</code> from the original command</a>".</p><p>El problema ha sido resuelto al tiempo de escribir este artículo, pero el arreglo no ha sido fusionado para las instalaciones.</p><!--kg-card-begin: html--><h2 id="como-escribir-pruebas">Cómo escribir las Pruebas</h2><!--kg-card-end: html--><p>Ahora te guiaré a través de los siguientes pasos para que comiences a escribir las pruebas:</p><ol><li>Configurar el proyecto</li><li>Configurar el esquema de Mongoose</li><li>Configurar los servicios</li><li>Configurar las pruebas</li><li>Escribir las pruebas</li><li>Pasar las pruebas</li><li>Usa TypeScript (Opcional)</li></ol><!--kg-card-begin: html--><h3 id="configurar-proyecto">1. Configurar el Proyecto</h3><!--kg-card-end: html--><p>Creé un repositorio de Github para facilitarte que sigas esta guía. Clona este repositorio en <a href="https://github.com/orimdominic/nodejs-test-runner-mongoose">nodejs-test-runner-mongoose</a> y dirígete a la rama <code>01-setup</code>. </p><p>En <code>01-setup</code>, las dependencias para el proyecto están el archivo <code>package.json</code>. Instala las dependencias usando el comando <code>npm install</code> para configurar el proyecto. Asegúrate de que la configuración esté completa y correcta, ejecuta el comando <code>node .</code> en la terminal de tu proyecto. Deberías ver tu versión de Node.js &nbsp;como una salida en la terminal.</p><pre><code class="language-bash"># instala las dependencias
npm install
...
# ejecuta el comando node
node .
# la salida
You are running Node.js v22.13.1
</code></pre><!--kg-card-begin: html--><h3 id="configurar-esquema-mongoose">2. Configurar el Esquema de Mongoose</h3><!--kg-card-end: html--><p>Configuraremos el esquema para dos colecciones (Task y User) en la rama <code>02-setup-schema</code> usando Mongoose. Los archivos <code>task/model.mjs</code> y <code>user/model.mjs</code> contienen el esquema para las colecciones Task y User, respectivamente. También configuraremos una conexión de base de datos en <code>index.mjs</code> para asegurar que la configuración del esquema funcione correctamente.</p><p>No iré en detalle sobre los modelos y esquemas de Mongoose en este artículo porque están fuera de su alcance.</p><p>Cuando ejecutas el comando <code>node .</code> después de implementar los cambios en <code>02-setup-schema</code>, deberías de ver un resultado similar en la consola como en el fragmento de abajo:</p><pre><code class="language-bash">node .
You are running Node.js v22.13.1
Created user with id 679f1d7f73fbeaf23b2007df
Created task "Task title" for user with id "679f1d7f73fbeaf23b2007df"
</code></pre><p>Puedes ver las diferencias entre <code>01-setup</code> y <code>02-setup-schema</code> a través de la <a href="https://github.com/orimdominic/nodejs-test-runner-mongoose/compare/01-setup...02-setup-schema">diferencia 01-setup &lt;&gt; 02-setup-schema en Github</a>. </p><!--kg-card-begin: html--><h3 id="configurar-servicios">3. Configurar los Servicios</h3><!--kg-card-end: html--><p>Luego, creamos los archivos de servicio (<code>task/service.mjs</code> y <code>user/service.mjs</code>) en la rama <code>03-setup-services</code>. Ambos archivos actualmente contienen funciones vacías en el que escribiremos las pruebas más tarde. Estas funciones contendrán la lógica de negocio y también se comunicará con la base de datos. Estamos usando comentarios de <a href="https://jsdoc.app/">JSDoc</a> para escribir parámetros y regresar valores.</p><p>Haz clic en la <a href="https://github.com/orimdominic/nodejs-test-runner-mongoose/compare/01-setup...02-setup-schema">diferencia de 02-setup-schema &lt;&gt; 03-setup-services</a> para ver los cambios de código entre <code>02-setup-schema</code> y <code>03-setup-services</code>.</p><!--kg-card-begin: html--><h3 id="configurar-pruebas">4. Configurar las Pruebas</h3><!--kg-card-end: html--><p>En la rama <code>04-set-up-tests</code>, configuramos la base de código para ejecutar las pruebas. Creamos <code>test.setup.mjs</code> el cual contiene el código que será ejecutado antes de que cada archivo de prueba se ejecute.</p><p>En <code>test.setup.mjs</code>, la función <code>connect</code> crea un servidor de MongoDB en memoria y lo conecta con Mongoose para ejecutar las pruebas. La función <code>closeDatabase</code> cierra la conexión de la base de datos y limpia todos los recursos para liberar memoria.</p><p>Las funciones <code>connect</code> y <code>closeDatabase</code> se ejecutan en el hook <code>t.before</code> y en el hook <code>t.after</code> respectivamente. Esto asegura eso, antes que un archivo test se ejecute, una conexión de base de datos se establece a través <code>t.before</code>. Luego de que se hayan ejecutado las pruebas del archivo, la conexión de la base de datos se cae y los recursos usados se limpian a través de <code>t.after</code>.</p><p>En <code>package.json</code>, actualizaremos el script de npm <code>test</code> a <code>node --test --import ./test.setup.mjs</code>. Este comando asegura que Módulo Es <code>test.setup.mjs</code> se pre-cargue y se ejecute a través del comando <code>--import</code> del CLI antes de que cada archivo de prueba se ejecute.</p><p>Luego crearemos los archivos de prueba con pruebas vacías en las carpetas <code>__tests__</code> para <code>user</code> y <code>task</code>. Después de implementar los <a href="https://github.com/orimdominic/nodejs-test-runner-mongoose/compare/03-setup-services...04-set-up-tests">nuevos cambios en 04-set-up-tests</a>, ejecutar el script <code>test</code> con <code>npm run test</code> debería de mostrar la salida similar al fragmento de abajo:</p><pre><code class="language-bash">npm run test

&gt; nodejs-test-runner-mongoose@1.0.0 test
&gt; node --test --import ./test.setup.mjs

...

ℹ tests 8
ℹ suites 5
ℹ pass 8
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 941.768873
</code></pre><p>Todas las pruebas actualmente pasan porque no hay aserciones que fallen. Escribiremos las pruebas con aserciones en la siguiente sección.</p><!--kg-card-begin: html--><h3 id="escribir-pruebas">5. Escribir Pruebas</h3><!--kg-card-end: html--><p>Ahora es tiempo de escribir las pruebas para las funciones en los archivos de service en la rama <code>05-write-tests</code>. Estamos usando la librería de aserción de Node.js para asegurar que los valores regresados de las funciones sean lo que esperamos. Puedes ver las pruebas que hemos escrito cuando comparas <a href="https://github.com/orimdominic/nodejs-test-runner-mongoose/compare/04-set-up-tests...05-write-tests">las diferencias entre 04-set-up-tests y 05-write-tests</a>.</p><p>Cuando el script <code>tests</code> se ejecute, todas las pruebas fallan porque no hemos escritos las funciones en los archivos de service todavía. Debería de ver una salida similar al fragmento de abajo cuando ejecutes el script <code>test</code>:</p><pre><code class="language-bash">npm run test

&gt; nodejs-test-runner-mongoose@1.0.0 test
&gt; node --test --import ./test.setup.mjs

...

ℹ tests 8
ℹ suites 5
ℹ pass 0
ℹ fail 8
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 1202.031961
</code></pre><!--kg-card-begin: html--><h3 id="pasar-pruebas">6. Pasar las Pruebas</h3><!--kg-card-end: html--><p>En <code>06-pass-tests</code>, escribimos las funciones en los archivos de service que pasen las pruebas. Solamente 6 de 7 pruebas pasan cuando el script <code>test</code> se ejecuta porque salteamos la prueba para la función <code>getById</code> en <code>user/service.mjs</code> con <code>t.skip</code>. No hemos terminado la función <code>getById</code> en <code>user/service.mjs</code>. Supuse que podríamos dejarlo como ejercicio.</p><p>Cuando ejecutas el script <code>test</code>, deberías obtener una salida similar en la terminal como el de abajo:</p><pre><code class="language-bash">ℹ tests 7
ℹ suites 4
ℹ pass 6
ℹ fail 0
ℹ cancelled 0
ℹ skipped 1
ℹ todo 0
ℹ duration_ms 1287.564918
</code></pre><p>Puedes ver el código que escribimos para pasar las pruebas en los <a href="https://github.com/orimdominic/nodejs-test-runner-mongoose/compare/05-write-tests...06-pass-tests">cambios de código entre 05-write-tests y 06-pass-tests</a>.</p><!--kg-card-begin: html--><h3 id="usa-typescript-opcional">7. Usa TypeScript (Opcional)</h3><!--kg-card-end: html--><p>Si tu intención es ejecutar las pruebas con TypeScript, puedes cambiar a la rama <code>07-with-typescript</code>. Necesitas tener Node.js <code>&gt;=22.6.0</code> instalado porque estamos usando la opción <code>--experimental-strip-types</code> en el <code>test</code>. Para configurar las pruebas que se ejecuten con TypeScript, sigue los siguientes pasos:</p><ol><li>Instala TypeScript usando el comando <code>npm install typescript --save-dev</code> </li><li>Instala tsx usando el comando <code>npm install tsx</code></li><li>Crea un archivo predeterminado <code>tsconfig.json</code> en la raíz del proyecto usando el comando <code>npx tsc --init</code> </li></ol><p>En &nbsp;<code>package.json</code>, actualiza el script <code>test</code> a esto:</p><pre><code class="language-bash">"test": "node --test --experimental-strip-types --import tsx --import ./test.setup.mjs"
</code></pre><ul><li><a href="https://nodejs.org/docs/latest-v22.x/api/cli.html#--experimental-strip-types"><code>--experimental-strip-types</code></a> ayuda a eliminar tipos antes de cada archivo de prueba se ejecute.</li></ul><p>Pre-cargar <code>tsx</code> con el <code>--import</code> ayuda a ejecutar el archivo de TypeScript. Sin él, el ejecutor de pruebas no será capaz de encontrar archivos importados sin la extensión <code>.ts</code>. Por ejemplo, <code>user/model.ts</code> importado con el fragmento de código de abajo no será encontrado.</p><pre><code class="language-typescript">  import { UserModel } from "./model";
</code></pre><p>El resto de los <a href="https://github.com/orimdominic/nodejs-test-runner-mongoose/compare/06-pass-tests...07-with-typescript">cambios desde 06-pass-tests a 07-with-typescript</a> involucran actualizar los tipos, cambiar las extensiones de archivo de <code>.mjs</code> a <code>.ts</code> y actualizar las declaraciones import.</p><!--kg-card-begin: html--><h2 id="conclusion">Conclusión</h2><!--kg-card-end: html--><p>En esta guía, has aprendido cómo usar el ejecutor de pruebas incorporado de Node.js y por qué es frecuentemente una mejor elección sobre otras librerías y frameworks de pruebas. También has aprendido cómo usar mongodb-memory-server como un reemplazo de un servidor real de MongoDB, así también como por qué es una buena idea usarlo en vez de un servidor real de MongoDB para las pruebas.</p><p>Lo más importante, has aprendido cómo configurar y ejecutar las pruebas en Node.js usando el ejecutor de pruebas de Node.js y mongodb-memory-server. Ahora deberías de saber cómo configurar tus proyectos para que ejecuten las pruebas si usas TypeScript.</p><p>Si encuentras útil a este repositorio <a href="https://github.com/orimdominic/nodejs-test-runner-mongoose">nodejs-test-runner-mongoose</a>, por favor dale una estrella. Me anima mucho. Gracias.</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Cómo construir una Aplicación de Chat en Tiempo Real con React, Node, Socket.io, y HarperDB ]]>
                </title>
                <description>
                    <![CDATA[ En este artículo, estaremos usando Socket.io y HarperDB para construir una aplicación chat fullstack de tiempo real con salas de chat. Este será un gran proyecto para aprender cómo armar las aplicaciones fullstack, y cómo crear una aplicación donde el back-end puede comunicarse con el front-end en tiempo real. Normalmente, ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/como-construir-una-aplicacion-de-chat-en-tiempo-real-con-react-node-socket-io-y-harperdb/</link>
                <guid isPermaLink="false">675af63196d716043ef3d8e3</guid>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Node.js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Socket.io ]]>
                    </category>
                
                    <category>
                        <![CDATA[ HarperDB ]]>
                    </category>
                
                    <category>
                        <![CDATA[ full stack ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Elias Ezequiel Pereyra Gomez ]]>
                </dc:creator>
                <pubDate>Fri, 24 Jan 2025 16:28:21 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2024/12/pexels-keira-burton-6146929.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>En este artículo, estaremos usando Socket.io y HarperDB para construir una aplicación chat fullstack de tiempo real con salas de chat.</p><p>Este será un gran proyecto para aprender cómo armar las aplicaciones fullstack, y cómo crear una aplicación donde el back-end puede comunicarse con el front-end en tiempo real.</p><p>Normalmente, usando solicitudes HTTP, el servidor no puede enviar datos al cliente en tiempo real. Pero al usar Socket.io, el servidor es capaz de enviar información en tiempo real al cliente sobre algunos eventos que sucedieron en el servidor.</p><p>La aplicación que estaremos construyendo tiene dos páginas:</p><p>Una página <code>join-a-chat-room</code>:</p><figure class="kg-card kg-image-card"><img src="https://lh6.googleusercontent.com/SyHBvbkVavSJTxNV1nOi2-V_YYXm3upFOJvAzBXwd1VNu10SKV4WBSyQS1tdf4OhiDbqlq3sLqCxWRSJafZwhfcsp72DSKEy3-hk3JvNVGcmsSgkHHpEH69pnBDVKCv6bXiMza4cC4BZiLCOiqKPAIk" class="kg-image" alt="How our app home page will look: a form with username input, select room dropdown and Join Room button" width="475" height="468" loading="lazy"></figure><p>Y una página <code>chat-room</code>:</p><figure class="kg-card kg-image-card"><img src="https://lh6.googleusercontent.com/uRkjeHOuGGGf9HnK7bZ1Zd6WeNMo8kaR6Py0_RiEDx1VUuTPx4oYNvfmPlOxNLAicM7bnr9rm0oY0E7k0fwfaZIEz4K1V-5ejOM3ztmrmjIjC8OsRyzNf0HZurxMWUMzdLgic7o8oC-RQxELo8vdcVw" class="kg-image" alt="The finished chat page" width="1216" height="678" loading="lazy"></figure><p>Aquí está lo que estaremos usando para construir este aplicación:</p><ul><li><strong><strong>Front</strong>-<strong>end</strong></strong>: <a href="https://reactjs.org/docs/create-a-new-react-app.html">React</a> (Un framework de front-end de JavaScript para construir aplicaciones interactvias)</li><li><strong><strong>Back</strong>-<strong>end</strong></strong>: <a href="https://nodejs.org/en/">Node</a> y <a href="https://expressjs.com/">Express</a> (Express es un framework muy popular de NodeJS que nos permite crear fácilmente APIs y back-ends)</li><li><strong>Base de Datos</strong>: <a href="https://harperdb.io/">HarperDB</a> (una plataforma de datos + aplicación que te permite solicitar datos usando SQL o NoSQL. HarperDB también tiene una API integrada, ahorrándonos el escribir mucho código de back-end)</li><li><strong>Comunicación en Tiempo Real</strong>: <a href="https://socket.io/docs/v3/">Socket.io</a> (¡ve abajo!)</li></ul><p><a href="https://github.com/DoableDanny/Realtime-chat-app-with-rooms">Aquí está el código fuente</a> (recuerda de darle una estrella ⭐).</p><h2 id="tabla-de-contenidos"><strong>Tabla de Contenidos</strong></h2><ol><li>¿<a href="#que-es-socketio">Qué es Socket.io?</a></li><li><a href="#configuracion-proyecto">Configuración del Proyecto</a></li><li><a href="#como-construir-pagina-join-a-room">Cómo construir la Página "Join a Room"</a></li><li><a href="#como-configurar-servidor">Cómo configurar el Servidor</a></li><li><a href="#como-crear-primer-escucha-evento-socketio">Cómo crear nuestro primer Escucha de Evento de Socket.io en el Servidor</a></li><li><a href="#como-funcionan-salas-socketio">Cómo funcionan las Salas en Socket.io</a></li><li><a href="#como-construir-pagina-chat">Cómo construir la Página Chat</a></li><li><a href="#como-crear-componente-messages">Cómo crear el componente Messages (B)</a></li><li><a href="#como-crear-esquema-y-tabla-harperdb">Cómo crear un Esquema y una Tabla en HarperDB</a></li><li><a href="#como-crear-componente-send-message">Cómo crear el Componente Send Message (C)</a></li><li><a href="#como-configurar-variables-entorno-harperdb">Cómo configurar las Variables de Entorno de HarperDB</a></li><li><a href="#como-permitir-a-usuarios-envien-mensajes-con-socketio">Cómo permitir a los Usuarios que se envíen Mensajes con Socket.io</a></li><li><a href="#como-obtener-mensajes-desde-harperdb">Cómo obtener los Mensajes desde HarperDB</a></li><li><a href="#como-mostrar-ultimos-100-mensajes-en-el-cliente">Cómo mostrar los Últimos 100 Mensajes en el Client</a>e</li><li><a href="#como-mostrar-sala-y-usuarios">Cómo mostrar la Sala y los Usuarios (A)</a></li><li><a href="#como-quitar-un-usuario-de-sala-socketio">Cómo quitar a un Usuario de una Sala de Socket.io</a></li><li><a href="#como-agregar-escucha-evento-disconnect">Cómo agregar el Escucha de Evento Disconnect de Socket.io</a></li></ol><!--kg-card-begin: html--><h2 id="que-es-socketio">¿Qué es Socket.io?</h2><!--kg-card-end: html--><p>Socket.io permite al servidor enviar información al cliente en tiempo real, cuando los eventos ocurren en el servidor.</p><p>Por ejemplo, si estuvieras jugando un juego de múltiple jugador, un evento podría ser tu "amigo" que consiguió un gol espectacular en contra tuya.</p><p>Con Socket.io, sabrías (casi) instantáneamente sobre conceder un gol.</p><p>Sin Socket.io, el cliente tendría que hacer múltiples llamadas <em>polling</em> de AJAX para verificar que el evento ha ocurrido en el servidor. Por ejemplo, el cliente podría usar JavaScript para verificar un evento en el servidor cada 5 segundos.</p><p>Socket.io significa que el cliente no tiene que hacer múltiples llamadas polling de AJAX para verificar si algunos eventos han ocurrido en el servidor. Más bien, el servidor envía la información al cliente tan pronto como lo obtenga. Mucho mejor.👌</p><p>Así que, Socket.io nos permite construir fácilmente aplicaciones de tiempo real, tales comos aplicaciones de chat y juegos multijugador.</p><!--kg-card-begin: html--><h2 id="configuracion-proyecto">Configuración del Proyecto</h2><!--kg-card-end: html--><h3 id="1-c-mo-configurar-nuestras-carpetas"><strong>1. Cómo configurar nuestras carpetas</strong></h3><p>Comienza un nuevo proyecto en tu editor de texto de prefrencia (VS Code para mí), y crea dos carpetas a nivel raíz llamados client y server.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/07/folder-structure.JPG" class="kg-image" alt="Realtime chat app folder structure" width="600" height="400" loading="lazy"></figure><p>Crearemos nuestra aplicación React Front-end &nbsp;en la carpeta client, y nuestro backend con Node/express en la carpeta server.</p><h3 id="2-c-mo-instalar-nuestras-dependencias-de-client"><strong>2. Cómo instalar nuestras dependencias de client</strong></h3><p>Abre una terminal en la raíz del proyecto (en VS Code, puedes hacer esto al presionar Ctrl + ' o al ir a <em>terminal-&gt;new terminal</em>).</p><p>Luego, instalaremos React en nuestra carpeta client:</p><pre><code class="language-bash">$ npx create-react-app client
</code></pre><p>Después de que React se haya instalado, ve hacia la carpeta client, e instala las siguientes dependencias:</p><pre><code class="language-bash">$ cd client
$ npm i react-router-dom socket.io-client
</code></pre><p>React-router-dom nos permitirá configurar las rutas a nuestros distintos componentes de React – esencialmente creando diferentes páginas.</p><p>Socket.io-client es la versión cliente de socket.io, que nos permite "emitir" eventos al servidor. Una vez que el servidor lo recibe, podemos usar la versión del servidor de socket.io para hacer cosas como enviar mensajes a los usuarios en la misma sala como el emisor, o unirse con un usuario a una sala de socket.</p><p>Ganarás un mejor entendimiento de esto más tarde cuando lleguemos a implementar estas ideas con código.</p><h3 id="3-c-mo-iniciar-la-aplicaci-n-de-react"><strong>3. Cómo iniciar la aplicación de React </strong></h3><p>Vamos a asegurarnos que todo está funcionando bien ejecutando el siguiente comando desde la carpeta client:</p><pre><code class="language-bash">$ npm start
</code></pre><p>Webpack construirá la aplicación de React y lo servirá en `http://localhost:3000`:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/07/react-is-running.JPG" class="kg-image" alt="Create react app up and running on localhost" width="600" height="400" loading="lazy"></figure><p>Ahora configuremos nuestra base de datos de HarperDB que usaremos para guardar mensajes de forma permanente enviados por los usuarios.</p><h3 id="c-mo-configurar-harperdb"><strong>Cómo configurar HarperDB</strong></h3><p>Primero, crea una <a href="https://studio.harperdb.io/">cuenta con HarperDB</a>.</p><p>Luego crea una nueva instancia en la nube de HarperDB.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/03/harper_instance.JPG" class="kg-image" alt="create HarperDB instance" width="600" height="400" loading="lazy"></figure><p>Para hacer las cosas fáciles, selecciona la instancia cloud:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/03/instance-type.JPG" class="kg-image" alt="select HarperDB instance type" width="600" height="400" loading="lazy"></figure><p>Selecciona el proveedor del cloud (Yo escojo AWS):</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/03/cloud_provider.JPG" class="kg-image" alt="select HarperDB cloud provider" width="600" height="400" loading="lazy"></figure><p>Brinda un nombre a tu instancia de la nube, y crea tus credenciales de la instancia:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/03/instance_credentials.JPG" class="kg-image" alt="select HarperDB instance credentials" width="600" height="400" loading="lazy"></figure><p>HarperDB tiene una capa gratuita generosa que podemos usar para este proyecto, así que selecciona ese:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/03/instance_specs.JPG" class="kg-image" alt="select HarperDB instance specs" width="600" height="400" loading="lazy"></figure><p>Verifica que tus detalles son correctos, luego crea la instancia.</p><p>Tomará unos pocos minutos para crear la instancia, así que continuemos y, ¡hagamos nuestro primer componente de React!</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/03/instance_loading.JPG" class="kg-image" alt="HarperDB instance loading" width="600" height="400" loading="lazy"></figure><!--kg-card-begin: html--><h2 id="como-construir-pagina-join-a-room">Cómo construir la Página "Join a Room"</h2><!--kg-card-end: html--><p>Nuestra página principal va a terminar luciendo así:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/07/home-page.JPG" class="kg-image" alt="How our app home page will look: a form with username input, select room dropdown and Join Room button" width="600" height="400" loading="lazy"></figure><p>El usuario ingresará un nombre de usuario, selecciona una sala de chat desde el despegable, luego haz clic en "Join Room". El usuario será dirigido a la página de la sala de chat.</p><p>Así que, hagamos esta página principal.</p><h3 id="1-c-mo-crear-el-formulario-html-y-agregar-estilos"><strong>1. Cómo crear el formulario HTML y agregar estilos</strong></h3><p>Crea un nuevo archivo en <code>src/pages/home/index.js</code>.</p><p>Agregaremos estilos básicos a nuestra aplicación usando módulos de CSS, así que crea un nuevo archivo: <code>src/pages/home/styles.module.css</code>.</p><p>Nuestra estructura de carpeta debería ahora lucir así:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/07/pages-folder-structure.JPG" class="kg-image" alt="pages folder with home page component" width="600" height="400" loading="lazy"></figure><p>Ahora creemos el formulario básico HTML:</p><pre><code class="language-jsx">// client/src/pages/home/index.js

import styles from './styles.module.css';

const Home = () =&gt; {
  return (
    &lt;div className={styles.container}&gt;
      &lt;div className={styles.formContainer}&gt;
        &lt;h1&gt;{`&lt;&gt;DevRooms&lt;/&gt;`}&lt;/h1&gt;
        &lt;input className={styles.input} placeholder='Username...' /&gt;

        &lt;select className={styles.input}&gt;
          &lt;option&gt;-- Select Room --&lt;/option&gt;
          &lt;option value='javascript'&gt;JavaScript&lt;/option&gt;
          &lt;option value='node'&gt;Node&lt;/option&gt;
          &lt;option value='express'&gt;Express&lt;/option&gt;
          &lt;option value='react'&gt;React&lt;/option&gt;
        &lt;/select&gt;

        &lt;button className='btn btn-secondary'&gt;Join Room&lt;/button&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  );
};

export default Home;
</code></pre><p>Arriba, tenemos un input de texto sencillo para capturar el nombre de usuario, y un despegable seleccionable con algunas opciones por defecto para que el usuario seleccione una sala de chat para unirse.</p><p>Ahora importemos este componente en <code>App.js</code> y configuremos una ruta para el componente usando el paquete <code>react-router-dom</code>. Este será nuestra página principal, así que la ruta será <code>/</code>:</p><pre><code class="language-jsx">// client/src/App.js

import './App.css';
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import Home from './pages/home';

function App() {
  return (
    &lt;Router&gt;
      &lt;div className='App'&gt;
        &lt;Routes&gt;
          &lt;Route path='/' element={&lt;Home /&gt;} /&gt;
        &lt;/Routes&gt;
      &lt;/div&gt;
    &lt;/Router&gt;
  );
}

export default App;
</code></pre><p>Ahora agreguemos algunos estilos básicos para hacer que nuestra aplicación luzca mas presentable:</p><pre><code class="language-css">/* client/src/App.css */

html * {
  font-family: Arial;
  box-sizing: border-box;
}
body {
  margin: 0;
  padding: 0;
  overflow: hidden;
  background: rgb(63, 73, 204);
}
::-webkit-scrollbar {
  width: 20px;
}
::-webkit-scrollbar-track {
  background-color: transparent;
}
::-webkit-scrollbar-thumb {
  background-color: #d6dee1;
  border-radius: 20px;
  border: 6px solid transparent;
  background-clip: content-box;
}
::-webkit-scrollbar-thumb:hover {
  background-color: #a8bbbf;
}
.btn {
  padding: 14px 14px;
  border-radius: 6px;
  font-weight: bold;
  font-size: 1.1rem;
  cursor: pointer;
  border: none;
}
.btn-outline {
  color: rgb(153, 217, 234);
  border: 1px solid rgb(153, 217, 234);
  background: rgb(63, 73, 204);
}
.btn-primary {
  background: rgb(153, 217, 234);
  color: rgb(0, 24, 111);
}
.btn-secondary {
  background: rgb(0, 24, 111);
  color: #fff;
}
</code></pre><p>También agreguemos los estilos específicos a nuestro componente de la página principal:</p><pre><code class="language-css">/* client/src/pages/home/styles.module.css */

.container {
  height: 100vh;
  width: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  background: rgb(63, 73, 204);
}
.formContainer {
  width: 400px;
  margin: 0 auto 0 auto;
  padding: 32px;
  background: lightblue;
  border-radius: 6px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 28px;
}
.input {
  width: 100%;
  padding: 12px;
  border-radius: 6px;
  border: 1px solid rgb(63, 73, 204);
  font-size: 0.9rem;
}
.input option {
  margin-top: 20px;
}
</code></pre><p>También hagamos que el botón "Join Room" tenga el ancho completo agregando un atributo de estilo:</p><pre><code class="language-jsx">// client/src/pages/home/index.js

&lt;button className='btn btn-secondary' style={{ width: '100%' }}&gt;Join Room&lt;/button&gt;
</code></pre><p>Nuestra página principal ahora se ve sólido:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/07/home-page-html.JPG" class="kg-image" alt="Fully-styled home page" width="600" height="400" loading="lazy"></figure><h3 id="2-c-mo-agregar-funcionalidad-al-formulario-join-room"><strong>2. Cómo agregar funcionalidad al formulario Join Room</strong></h3><p>Ahora tenemos un formulario básico y estilos, así que es tiempo de agregar algo de funcionalidad.</p><p>Esto es lo que queremos que suceda cuando el usuario haga clic en el botón "Join Room":</p><ol><li>Verificar que el nombre de usuario y los campos de la sala sean rellenados.</li><li>Si es así, emitimos un evento de socket a nuestro servidor.</li><li>Redireccionar al usuario a la página Chat (el cual crearemos luego).</li></ol><p>Vamos a necesitar crear algo de estado para almacenar los valores <em>nombre de usuario</em> y <em>room</em>. También necesitamos crear una instancia del socket.</p><p>Podríamos crear estos estados directamente dentro de nuestro componente <em>home</em>, pero nuestra página <em>Chat</em> también necesitará acceder al <em>username, <em>room</em> y <em>socket</em></em>. Así que elevaremos el estado al <code>App.js</code>, donde podemos pasar estas variables a las páginas <em>HomePage</em> y <em>Chat</em>.</p><p>Así que, creemos nuestro estado y configuremos un socket en <code>App.js</code>, y pasemos estas variables como props al componente. También pasaremos la función <code>setState</code> de forma que podamos alterar el estado:</p><pre><code class="language-jsx">// client/src/App.js

import './App.css';
import { useState } from 'react'; // Add this
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import io from 'socket.io-client'; // Add this
import Home from './pages/home';

const socket = io.connect('http://localhost:4000'); // Add this -- our server will run on port 4000, so we connect to it from here

function App() {
  const [username, setUsername] = useState(''); // Add this
  const [room, setRoom] = useState(''); // Add this

  return (
    &lt;Router&gt;
      &lt;div className='App'&gt;
        &lt;Routes&gt;
          &lt;Route
            path='/'
            element={
              &lt;Home
                username={username} // Add this
                setUsername={setUsername} // Add this
                room={room} // Add this
                setRoom={setRoom} // Add this
                socket={socket} // Add this
              /&gt;
            }
          /&gt;
        &lt;/Routes&gt;
      &lt;/div&gt;
    &lt;/Router&gt;
  );
}

export default App;
</code></pre><p>Ahora podemos acceder a estos props en nuestro componente <em>Home</em>. Usaremos la <a href="https://www.freecodecamp.org/espanol/news/como-usar-la-desestructuracion-de-arreglos-y-objetos-en-javascript/">destructuración</a> para obtener estas props:</p><pre><code class="language-jsx">// client/src/pages/home/index.js

import styles from './style.module.css';

const Home = ({ username, setUsername, room, setRoom, socket }) =&gt; {
  return (
    // ...
  );
};

export default Home;
</code></pre><p>Cuando el usuario ingrese su nombre de usuario o seleccione una sala, necesitamos actualizar las variables de estado <code>username</code> y <code>room</code><em>:</em></p><pre><code class="language-jsx">// client/src/pages/home/index.js

// ...

const Home = ({ username, setUsername, room, setRoom, socket }) =&gt; {
  return (
    &lt;div className={styles.container}&gt;
      // ...
        &lt;input
          className={styles.input}
          placeholder='Username...'
          onChange={(e) =&gt; setUsername(e.target.value)} // Add this
        /&gt;

        &lt;select
          className={styles.input}
          onChange={(e) =&gt; setRoom(e.target.value)} // Add this
        &gt;
         // ...
        &lt;/select&gt;

        // ...
    &lt;/div&gt;
  );
};

export default Home;
</code></pre><p>Ahora estamos capturamos los datos ingresados por el usuario, podemos crear una función <a href="https://www.freecodecamp.org/espanol/news/funciones-callback-en-javascript-que-son-los-callback-en-js-y-como-usarlos/">callback</a> <em>joinRoom()</em> para cuando el usuario haga clic en el botón "Join Room":</p><pre><code class="language-jsx">// client/src/pages/home/index.js

// ...

const Home = ({ username, setUsername, room, setRoom, socket }) =&gt; {

  // Add this
  const joinRoom = () =&gt; {
    if (room !== '' &amp;&amp; username !== '') {
      socket.emit('join_room', { username, room });
    }
  };

  return (
    &lt;div className={styles.container}&gt;
      // ...

        &lt;button
          className='btn btn-secondary'
          style={{ width: '100%' }}
          onClick={joinRoom} // Add this
        &gt;
          Join Room
        &lt;/button&gt;
      // ...
    &lt;/div&gt;
  );
};

export default Home;
</code></pre><p>Arriba, cuando el usuario haga clic en el botón, un evento del socket llamado <code>joinroom</code> se emite, juntamente con un objeto conteniendo el nombre de usuario y la sala seleccionada. Este evento será recibido por nuestro servidor un poco más tarde cuando haremos algo de magia.</p><p>Para terminar nuestra página principal, necesitamos agregar una redirección al final de nuestra función <code>joinRoom()</code> para llevar al usuario a la página <em>/chat</em>:</p><pre><code class="language-jsx">// client/src/pages/home/index.js

// ...
import { useNavigate } from 'react-router-dom'; // Agrega esto

const Home = ({ username, setUsername, room, setRoom, socket }) =&gt; {
  const navigate = useNavigate(); // Agrega esto

  const joinRoom = () =&gt; {
    if (room !== '' &amp;&amp; username !== '') {
      socket.emit('join_room', { username, room });
    }

    // Redirecciona a /chat
    navigate('/chat', { replace: true }); // Agrega esto
  };

 // ...
</code></pre><p>Pruébalo: escribe un nombre de usuario y selecciona una sala, luego haz clic en <em>Join Room</em>. Deberías ser dirigido a la ruta <code>http://localhost:3000/chat</code> – actualmente una página vacía.</p><p>Pero antes que creemos nuestra Página <em>Chat</em>, tengamos algo ejecutándose en el servidor.</p><!--kg-card-begin: html--><h2 id="como-configurar-servidor">Cómo configurar el Servidor</h2><!--kg-card-end: html--><p>En el servidor, vamos a escuchar los eventos del socket que son emitidos desde el frontend. Actualmente, solamente tenemos un evento <code>join_room</code> siendo emitido desde React, así que agregaremos este escucha de evento primero.</p><p>Pero antes de eso, necesitamos instalar nuestras dependencias del servidor y tener el servidor activo y ejecutándose.</p><h3 id="1-c-mo-instalar-las-dependencias-del-servidor"><strong>1. Cómo instalar las dependencias del servidor</strong></h3><p>Abre una nueva terminal (en VS Code: <code>Terminal-&gt;Nueva Terminal</code>), cambia la carpeta a nuestra carpeta de servidor, inicializa un archivo package.json, e instala las siguientes dependencias:</p><pre><code class="language-bash">$ cd server
$ npm init -y
$ npm i axios cors express socket.io dotenv
</code></pre><ul><li><strong>Axios</strong> es un paquete usado comunmente para hacer solicitudes fácilmente a APIs.</li><li><strong>Cors</strong> permite a nuestro cliente hacer solicitudes a otros orígenes – necesario para socket.io para que funcione de forma apropiada. Ve ¿<a href="https://aws.amazon.com/es/what-is/cross-origin-resource-sharing/">Qué es el CORS?</a> si no has escuchado de CORS antes.</li><li><strong>Express</strong> es un framework de Node.js que nos permite escribir nuestro backend más fácilmente con menos código.</li><li><strong>Socket.io</strong> es una librería que permite que el cliente y el servidor se comunique a tiempo real – el cual no es posible con solicitudes estándares de HTTP.</li><li><strong>Dotenv</strong> es un módulo que nos permite almacenar claves privadas y contraseñas de forma segura, y cargarlos en nuestro códio cuando sea necesario.</li></ul><p>También instalaremos <strong>nodemon</strong> como una dependencia dev, así no tenemos que reiniciar nuestro servidor cada vez que hagamos un cambio al código – ahorrándonos tiempo y energía:</p><pre><code class="language-bash">$ npm i -D nodemon
</code></pre><h3 id="2-c-mo-iniciar-nuestro-servidor"><strong>2. Cómo iniciar nuestro servidor</strong></h3><p>Crea un archivo <code>index.js</code> en la raíz de nuestra carpeta server, y agrega el siguiente código para iniciar el servidor:</p><pre><code class="language-javascript">// server/index.js

const express = require('express');
const app = express();
const http = require('http');
const cors = require('cors');

app.use(cors()); // Add cors middleware

const server = http.createServer(app);

server.listen(4000, () =&gt; 'Server is running on port 4000');
</code></pre><p>Abre el archivo <code>package.json</code> en nuestro servidor, y agrega un script que nos permitirá usar nodemon en desarrollo:</p><pre><code class="language-json">{
  ...
  "scripts": {
    "dev": "nodemon index.js"
  },
  ...
}
</code></pre><p>Ahora, iniciemos nuestro servidor al ejecutar el siguiente comando:</p><pre><code class="language-bash">$ npm run dev
</code></pre><p>Podemos verificar rápidamente que nuestro servidor se está ejecutando correctamente al agregar un manejador de solicitudes get:</p><pre><code class="language-javascript">// server/index.js

const express = require('express');
const app = express();
http = require('http');
const cors = require('cors');

app.use(cors()); // Agrega cors middleware

const server = http.createServer(app);

// Agrega esto
app.get('/', (req, res) =&gt; {
  res.send('Hello world');
});

server.listen(4000, () =&gt; 'El servidor está ejecutándose en el puerto 3000');
</code></pre><p>Ahora ve a <a href="http://localhost:4000/"><code>http://localhost:4000/</code></a>:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/07/localhost4000.JPG" class="kg-image" alt="Image" width="600" height="400" loading="lazy"></figure><p>Nuestro servidor está activo y en ejecución. ¡Ahora es tiempo de hacer cosas de Socket.io en el servidor!</p><!--kg-card-begin: html--><h2 id="como-crear-primer-escucha-evento-socketio">Cómo crear nuestro primer Escucha de Evento de Socket.io en el Servidor</h2><!--kg-card-end: html--><p>Recuerda que cuando emitimos un evento <code>joinroom</code> desde el cliente? Bueno, pronto vamos a estar escuchar ese evento en el servidor y agregar el usuario a una sala del socket.</p><p>Pero primero, necesitamos escuchar cuando un cliente se conecte al servidor a través de <code>socket.io-client</code>.</p><pre><code class="language-javascript">// server/index.js

const express = require('express');
const app = express();
http = require('http');
const cors = require('cors');
const { Server } = require('socket.io'); // Agrega esto

app.use(cors()); // Agrega cors middleware

const server = http.createServer(app); // Agrega esto

// Agrega esto
// Crea un servidor io y permite CORS desde http://localhost:3000 con metodos GET y POST
const io = new Server(server, {
  cors: {
    origin: 'http://localhost:3000',
    methods: ['GET', 'POST'],
  },
});

// Agrega esto
// Escucha cuando el cliente se conecta a traves de socket.io-client
io.on('connection', (socket) =&gt; {
  console.log(`User connected ${socket.id}`);

  // Podemos escribir nuestro our socket event listeners in here...
});

server.listen(4000, () =&gt; 'El servidor está ejecutándose en el puerto 3000');
</code></pre><p>Ahora, cuando el cliente se conecta desde el frontend, el backend captura el evento de la conexión, y registrará <code>User connected</code> con el id único del socket para ese cliente particular.</p><p>Probemos si el servidor ahora está captrando el evento de la conección desde el cliente. Ve a tu aplicación de React en <code>http://localhost:3000/</code> y refresca la página.</p><p>Deberías ver el siguiente registro en tu consola de terminal del servidor:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/07/user-connected.JPG" class="kg-image" alt="Image" width="600" height="400" loading="lazy"></figure><p>Genial, nuestro cliente se ha conectado a nuestro servidor a través de socket.io. Nuestro cliente y servidor ahora se pueden comunicar en, ¡tiempo real!</p><!--kg-card-begin: html--><h2 id="como-funcionan-salas-socketio">Cómo funcionan las Salas en Socket.io</h2><!--kg-card-end: html--><p>Desde la documentación de <a href="https://socket.io/docs/v3/rooms/">Socket.io</a> (no está disponible en español todavía):</p><blockquote><em><em>"</em>Una<em> </em>sala<em> </em>e<em>s </em>u<em>n</em> canal<em> </em>arbitrario<em> </em>al que<em> sockets </em>se puede unir (<em><code>join</code></em>)<em> </em>y abandonar (<em><code>leave</code></em>)<em>. </em>Puede ser usado<em> </em>para emitir<em> event</em>o<em>s </em>a<em> </em>un<em> </em>subconjunto<em> </em>de<em> client</em>e<em>s."</em></em></blockquote><p>Así que, podemos unir el usuario a una sala, y luego el servidor puede enviar mensajes a todos los usuarios en esa sala – permitiendo a los usuarios enviarse mensajes en tiempo real. ¡Genial! </p><h3 id="c-mo-unir-el-usuario-a-una-sala-de-socket-io"><strong>Cómo unir el usuario a una sala de Socket.io</strong></h3><p>Una vez que el usuario se ha conectado a través de Socket.io, podemos agregar nuestros escuchas de eventos del socket en el servidor para escuchar eventos emitidos desde el cliente. También, podemos emitir eventos en el servidor, y esucharlos en el cliente.</p><p>Ahora escuchemos por el evento <code>joinroom</code>, que capture los datos (nombre de usuario y sala), y agregue al usuario a una sala de socket:</p><pre><code class="language-javascript">// server/index.js

// Escuchar cuando el cliente se conecta a través de socket.io-client
io.on('connection', (socket) =&gt; {
  console.log(`User connected ${socket.id}`);

  // Agrega esto
  // Agrega un usuario a una sala
  socket.on('join_room', (data) =&gt; {
    const { username, room } = data; // Datos enviados desde el cliente cuando el evento join_room se emite
    socket.join(room); // Une el usuario a una sala de socket
  });
});
</code></pre><h3 id="c-mo-enviar-un-mensaje-a-los-usuarios-en-una-sala"><strong>Cómo enviar un mensaje a los usuarios en una sala</strong></h3><p>Ahora enviemos un mensaje a todos los usuarios en la sala, aparte del usuario que se acaba de unir, para notificarlos que un nuevo usuario se ha unido:</p><pre><code class="language-javascript">// server/index.js

const CHAT_BOT = 'ChatBot'; // Agrega esto
// Escucha cuando el cliente se conecta a través de socket.io-client
io.on('connection', (socket) =&gt; {
  console.log(`User connected ${socket.id}`);

  // Agrega un usuario a una sala
  socket.on('join_room', (data) =&gt; {
    const { username, room } = data; // Datos enviados desde el cliente cuando el evento join_room se emite
    socket.join(room); // Une el usuario a una sala de socket

    // Agrega esto
    let __createdtime__ = Date.now(); // Marcas de tiempo actuales
    // Envía un mensaje a todos los usuario en la sala, aparte del usuario que se acaba de unir
    socket.to(room).emit('receive_message', {
      message: `${username} has joined the chat room`,
      username: CHAT_BOT,
      __createdtime__,
    });
  });
});
</code></pre><p>Arriba, estamos emitiendo un evento <code>receive_message</code> a todos los clientes en la sala en el que el usuario se acaba de unir, juntamente con algo de dato: el mensaje, el nombre de usuario quien envió el mensaje, y el tiempo en que el mensaje fue enviado.</p><p>Agregaremos un escucha de evento en nuestra aplicación de React un poco después para capturar este evento, y muestra el mensaje en la pantalla.</p><p>También enviemos un mensaje de bienvenida al nuevo usuario recién unido:</p><pre><code class="language-javascript">// server/index.js

io.on('connection', (socket) =&gt; {
  // ...

    // Agrega esto
    // Envía el msg de bienvenida al usuario que se acaba de unir
    socket.emit('receive_message', {
      message: `Welcome ${username}`,
      username: CHAT_BOT,
      __createdtime__,
    });
  });
});
</code></pre><p>Cuando agregamos un usuario a una sala de Socket.io, Socket.io solamente almacena los ids de los sockets para cada usuario. Pero necesitaremos los nombres de usuario de todos en la sala, así también como el nombre de sala. Así que, almacenemos esos datos en variables en el servidor:</p><pre><code class="language-javascript">// server/index.js

// ...

const CHAT_BOT = 'ChatBot';
// Agrega esto
let chatRoom = ''; // Ej. javascript, node,...
let allUsers = []; // Todos los usuarios en la sala de chat actual

// Escucha cuando el cliente se conecta a través de socket.io-client
io.on('connection', (socket) =&gt; {
    // ...

    // Agrega esto
    // Guarda el nuevo usuario a la sala
    chatRoom = room;
    allUsers.push({ id: socket.id, username, room });
    chatRoomUsers = allUsers.filter((user) =&gt; user.room === room);
    socket.to(room).emit('chatroom_users', chatRoomUsers);
    socket.emit('chatroom_users', chatRoomUsers);
  });
});
</code></pre><p>Arriba, también estamos enviando un arreglo de todo el chatRoomUsers de nuevo al cliente a través del evento <code>chatroomusers</code>, así que podemos listar todos los nombres de usuario en el frontend.</p><p>Antes que agreguemos cualquier otro código a nuestro servidor, volvamos a nuestro frontend y creamos la página <em>Chat</em> – así podemos probar si estamos recibiendo los eventos <code>receivemessage</code>.</p><!--kg-card-begin: html--><h2 id="como-construir-pagina-chat">Cómo construir la Página Chat</h2><!--kg-card-end: html--><p>En tu carpeta cliente, crea dos nuevos archivos:</p><ol><li><code>src/pages/chat/index.js</code></li><li><code>src/pages/chat/styles.module.css</code></li></ol><p>Agreguemos algunos estilos que usaremos en nuestra página <em>Chat</em> y componentes:</p><pre><code class="language-css">/* client/src/pages/chat/styles.module.css */

.chatContainer {
  max-width: 1100px;
  margin: 0 auto;
  display: grid;
  grid-template-columns: 1fr 4fr;
  gap: 20px;
}

/* Room and users component */
.roomAndUsersColumn {
  border-right: 1px solid #dfdfdf;
}
.roomTitle {
  margin-bottom: 60px;
  text-transform: uppercase;
  font-size: 2rem;
  color: #fff;
}
.usersTitle {
  font-size: 1.2rem;
  color: #fff;
}
.usersList {
  list-style-type: none;
  padding-left: 0;
  margin-bottom: 60px;
  color: rgb(153, 217, 234);
}
.usersList li {
  margin-bottom: 12px;
}

/* Messages */
.messagesColumn {
  height: 85vh;
  overflow: auto;
  padding: 10px 10px 10px 40px;
}
.message {
  background: rgb(0, 24, 111);
  border-radius: 6px;
  margin-bottom: 24px;
  max-width: 600px;
  padding: 12px;
}
.msgMeta {
  color: rgb(153, 217, 234);
  font-size: 0.75rem;
}
.msgText {
  color: #fff;
}

/* Message input and button */
.sendMessageContainer {
  padding: 16px 20px 20px 16px;
}
.messageInput {
  padding: 14px;
  margin-right: 16px;
  width: 60%;
  border-radius: 6px;
  border: 1px solid rgb(153, 217, 234);
  font-size: 0.9rem;
}
</code></pre><p>Ahora, veamos cómo terminará luciendo nuestra página <em>Chat</em>:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/07/chat-page.JPG" class="kg-image" alt="The finished chat page" width="600" height="400" loading="lazy"></figure><p>Agregando todo el código y lógica para esta página en un archivo podría volverse confuso y difícil de manejar, así que aprovechemos el hecho de que estamos usando un framework de frontend fabuloso (React) y <strong>dividir nuestra página en componentes:</strong></p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/07/image-248.png" class="kg-image" alt="The chat page split into three components" width="600" height="400" loading="lazy"></figure><h3 id="los-componentes-de-la-p-gina-chat-"><strong>Los componentes de la página chat:</strong></h3><p><strong><strong>A</strong></strong>: Contiene el nombre de la sala, una lista de usuarios en esa sala, y un botón "Leave" que quitar al usuario desde la sala.</p><p><strong><strong>B</strong></strong>: Los mensajes enviados. Al inicio de la renderización, los últimos 100 mensajes enviados en esa sala será solicitado desde la base de datos y mostrado al usuario.</p><p><strong><strong>C</strong></strong>: Una entrada y botón para escribir y enviar un mensaje.</p><p>Primero crearemos el componente B, así podemos mostrar los mensajes al usuario.</p><!--kg-card-begin: html--><h2 id="como-crear-componente-messages">Cómo crear el Componente Messages (B)</h2><!--kg-card-end: html--><p>Crea un nuevo archivo en <code>src/pages/chat/messages.js</code> y agrega el siguiente código:</p><pre><code class="language-jsx">// client/src/pages/chat/messages.js

import styles from './styles.module.css';
import { useState, useEffect } from 'react';

const Messages = ({ socket }) =&gt; {
  const [messagesRecieved, setMessagesReceived] = useState([]);

  // Se ejecuta cuando sea que un evento del socket es recibido desde el servidor
  useEffect(() =&gt; {
    socket.on('receive_message', (data) =&gt; {
      console.log(data);
      setMessagesReceived((state) =&gt; [
        ...state,
        {
          message: data.message,
          username: data.username,
          __createdtime__: data.__createdtime__,
        },
      ]);
    });

    // Quita la escucha del evento al desmontar el componente
    return () =&gt; socket.off('receive_message');
  }, [socket]);

  // dd/mm/yyyy, hh:mm:ss
  function formatDateFromTimestamp(timestamp) {
    const date = new Date(timestamp);
    return date.toLocaleString();
  }

  return (
    &lt;div className={styles.messagesColumn}&gt;
      {messagesRecieved.map((msg, i) =&gt; (
        &lt;div className={styles.message} key={i}&gt;
          &lt;div style={{ display: 'flex', justifyContent: 'space-between' }}&gt;
            &lt;span className={styles.msgMeta}&gt;{msg.username}&lt;/span&gt;
            &lt;span className={styles.msgMeta}&gt;
              {formatDateFromTimestamp(msg.__createdtime__)}
            &lt;/span&gt;
          &lt;/div&gt;
          &lt;p className={styles.msgText}&gt;{msg.message}&lt;/p&gt;
          &lt;br /&gt;
        &lt;/div&gt;
      ))}
    &lt;/div&gt;
  );
};

export default Messages;
</code></pre><p>Ahora, tenemos un hook <em>useEffect</em> que se ejecuta cuando sea que el evento del socket se recibe. Luego recibimos los datos del mensaje en el escucha del evento <code>receivemessage</code>. Desde ahí, ponemos el estado <code>messagesReceived</code>, el cual es un arreglo de objetos de mensaje conteniendo el mensaje, nombre de usuario del emisor, y la fecha del mensaje que fue enviado.</p><p>Importemos nuestro nuevo componentes de mensajes en la página <em>Chat</em>, y luego creemos una ruta para la página <em>Chat</em> en <code>App.js</code>:</p><pre><code class="language-jsx">// client/src/pages/chat/index.js

import styles from './styles.module.css';
import MessagesReceived from './messages';

const Chat = ({ socket }) =&gt; {
  return (
    &lt;div className={styles.chatContainer}&gt;
      &lt;div&gt;
        &lt;MessagesReceived socket={socket} /&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  );
};

export default Chat;
</code></pre><pre><code class="language-jsx">// client/src/App.js

import './App.css';
import { useState } from 'react';
import Home from './pages/home';
import Chat from './pages/chat';
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import io from 'socket.io-client';

const socket = io.connect('http://localhost:4000');

function App() {
  const [username, setUsername] = useState('');
  const [room, setRoom] = useState('');

  return (
    &lt;Router&gt;
      &lt;div className='App'&gt;
        &lt;Routes&gt;
          &lt;Route
            path='/'
            element={
              &lt;Home
                username={username}
                setUsername={setUsername}
                room={room}
                setRoom={setRoom}
                socket={socket}
              /&gt;
            }
          /&gt;
          {/* Add this */}
          &lt;Route
            path='/chat'
            element={&lt;Chat username={username} room={room} socket={socket} /&gt;}
          /&gt;
        &lt;/Routes&gt;
      &lt;/div&gt;
    &lt;/Router&gt;
  );
}

export default App;
</code></pre><p>Probemos esto, ve a la página principal y únete a una sala:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/07/joining-a-room.JPG" class="kg-image" alt="Joining a room as Dan" width="600" height="400" loading="lazy"></figure><p>Deberíamos ser llevados a la página <em>Chat</em>, y recibir un mensaje de bienvenida del <em>ChatBot</em>:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/07/welcome-message.JPG" class="kg-image" alt="Welcome message received from ChatBot" width="600" height="400" loading="lazy"></figure><p>Los usuarios ahora pueden ver los mensajes que reciben. ¡Genial!</p><p>Próximo: configurar nuestra base de datos así podemos guardar los mensajes permanentemente.</p><!--kg-card-begin: html--><h2 id="como-crear-esquema-y-tabla-harperdb">Cómo crear un Esquema y una Tabla en HarperDB</h2><!--kg-card-end: html--><p>Vuelve a tu dashboard de HarperDB, y haz clic en "browser". Luego crea un nuevo esquemos llamado "realtime_chat_app". Un esquema es simplemente un grupo de tablas.</p><p>Dentro de ese esquema, crea una tabla llamada "messages", con un atributo hash de "id".</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/07/image-258.png" class="kg-image" alt="Creating our schema and table in HarperDB" width="600" height="400" loading="lazy"></figure><p>Ahora tenemos necestiamos donde almacenar los mensajes, así que creemos el componente <em>SendMessage</em>.</p><!--kg-card-begin: html--><h2 id="como-crear-componente-send-message">Cómo crear el componente Send Message (C)</h2><!--kg-card-end: html--><p>Crea el archivo <code>src/pages/chat/send-message.js</code> y agrega el siguiente código:</p><pre><code class="language-jsx">// client/src/pages/chat/send-message.js

import styles from './styles.module.css';
import React, { useState } from 'react';

const SendMessage = ({ socket, username, room }) =&gt; {
  const [message, setMessage] = useState('');

  const sendMessage = () =&gt; {
    if (message !== '') {
      const __createdtime__ = Date.now();
      // Envia un mensaje al servidor. No podemos especificar a quien enviamos el mensaje desde el frontend. Solamente podemos enviar al servidor. El servidor por lo tanto puede enviar un mensaje al resto de los usuarios en la sala
      socket.emit('send_message', { username, room, message, __createdtime__ });
      setMessage('');
    }
  };

  return (
    &lt;div className={styles.sendMessageContainer}&gt;
      &lt;input
        className={styles.messageInput}
        placeholder='Message...'
        onChange={(e) =&gt; setMessage(e.target.value)}
        value={message}
      /&gt;
      &lt;button className='btn btn-primary' onClick={sendMessage}&gt;
        Send Message
      &lt;/button&gt;
    &lt;/div&gt;
  );
};

export default SendMessage;
</code></pre><p>Arriba, cuando el usuario hace clic en el botón "Send Message", un evento del socket <code>send_message</code> se emite al servidor, junto con un objeto de mensaje. Manejaremos este evento en el servidor dentro de poco.</p><p>Importa <em>SendMessage</em> en nuestra página Chat:</p><pre><code class="language-js">// src/pages/chat/index.js

import styles from './styles.module.css';
import MessagesReceived from './messages';
import SendMessage from './send-message';

const Chat = ({ username, room, socket }) =&gt; {
  return (
    &lt;div className={styles.chatContainer}&gt;
      &lt;div&gt;
        &lt;MessagesReceived socket={socket} /&gt;
        &lt;SendMessage socket={socket} username={username} room={room} /&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  );
};

export default Chat;
</code></pre><p>La página <em>Chat</em> ahora luce así:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/07/image-259.png" class="kg-image" alt="Chat page now has a message input where a message can be typed and sent" width="600" height="400" loading="lazy"></figure><p>Luego necesitamos configurar nuestras variables de entorno de HarperDB así podemos comenzar a interactuar con la base de datos.</p><!--kg-card-begin: html--><h2 id="como-configurar-variables-entorno-harperdb">Cómo configurar las Variables de Entorno de HarperDB </h2><!--kg-card-end: html--><p>Para que seas capaz de guardar los mensajes en HarperDB, necesitarás tu URL de instancia de HarperDB, y tu contraseña API.</p><p>En tu dashboard de HarperDB, haz clic en tu instancia, luego ve a "config". Encontrarás tu URL de instancia, y la cabecera de Autenticación de API de tu instancia – eso es, tu contraseña "super_user" que te permite realizar cualquier solicitud a la base de datos – ¡PARA TUS OJOS SOLAMENTE!</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/07/image-263.png" class="kg-image" alt="HarperDB instance URL and API auth header" width="600" height="400" loading="lazy"></figure><p>Guardaremos estas variables en un archivo .env. <strong>Advertencia: ¡No empujes el archivo .env a Github!</strong> Este archivo no debería ser visible públicamente. Las variables se cargan a través del servidor por detrás.</p><p>Crea los siguientes archivos y agrega tu URL y contraseña de HarperDB:</p><pre><code class="language-bash">// server/.env

HARPERDB_URL="&lt;tu url va aqui&gt;"
HARPERDB_PW="Basic &lt;tu contraseña aqui&gt;"
</code></pre><p>También crearemos un archivo <code>.gitignore</code> para evitar que el .env se suba a Github, juntamente con la carpeta <code>node_modules</code>:</p><pre><code class="language-bash">// server/.gitignore

.env
node_modules
</code></pre><p><strong>Nota</strong>: ser bueno en Git y Github es 100% imprescindible para todos los desarrolladores. Revisa <a href="https://www.doabledanny.com/git-workflows">mi artículo de los flujos de trabajo de Git</a> si necesitas mejorar tu juego de Git.</p><p>O si constantemente te encuentras revisando los mismos comandos de Git, y quieres una forma rápida de verlos, y copiar/pegar los comandos – revisa mi <a href="https://doabledanny.gumroad.com/l/git-commands-cheat-sheet-pdf">hoja de trucos de los comandos de Git en PDF</a> y mi <a href="https://doabledanny.gumroad.com/l/git-cheat-sheet-poster">póster de hoja de trucos de Git físico</a>.</p><p>Finalmente, carguemos nuestras variables de entorno en nuestro servidor al agregar este código en la parte superior de nuestro archivo <code>main</code>:</p><pre><code class="language-js">// server/index.js

require('dotenv').config();
console.log(process.env.HARPERDB_URL); // quita esto despues que hayas visto que funcionó
const express = require('express');
// ...
</code></pre><!--kg-card-begin: html--><h2 id="como-permitir-a-usuarios-envien-mensajes-con-socketio">Cómo permitir a los Usuarios que se envíen mensajes con Socket.io</h2><!--kg-card-end: html--><p>En el servidor, escucharemos el evento <code>sendmessage</code>, luego enviaremos el mensaje a todos los usuarios dentro de la sala:</p><pre><code class="language-js">// server/index.js

const express = require('express');
// ...
const harperSaveMessage = require('./services/harper-save-message'); // Agrega esto

// ...

// Escucha cuando el cliente se conecta a través de socket.io-client
io.on('connection', (socket) =&gt; {

  // ...

  // Agrega esto
  socket.on('send_message', (data) =&gt; {
    const { message, username, room, __createdtime__ } = data;
    io.in(room).emit('receive_message', data); // Envia a todos los usuarios en la sala, incluyendo al emisor
    harperSaveMessage(message, username, room, __createdtime__) // Guarda el mensaje en la bd
      .then((response) =&gt; console.log(response))
      .catch((err) =&gt; console.log(err));
  });
});

server.listen(4000, () =&gt; 'El Servidor se está ejecutando en el puerto 3000');
</code></pre><p>Ahora necesitamos crear la función <code>harperSaveMessage</code>. Crea un nuevo archivo en <code>server/services/harper-save-message.js</code>, y agrega lo siguiente:</p><pre><code class="language-js">// server/services/harper-save-message.js

var axios = require('axios');

function harperSaveMessage(message, username, room) {
  const dbUrl = process.env.HARPERDB_URL;
  const dbPw = process.env.HARPERDB_PW;
  if (!dbUrl || !dbPw) return null;

  var data = JSON.stringify({
    operation: 'insert',
    schema: 'realtime_chat_app',
    table: 'messages',
    records: [
      {
        message,
        username,
        room,
      },
    ],
  });

  var config = {
    method: 'post',
    url: dbUrl,
    headers: {
      'Content-Type': 'application/json',
      Authorization: dbPw,
    },
    data: data,
  };

  return new Promise((resolve, reject) =&gt; {
    axios(config)
      .then(function (response) {
        resolve(JSON.stringify(response.data));
      })
      .catch(function (error) {
        reject(error);
      });
  });
}

module.exports = harperSaveMessage;
</code></pre><p>Arriba, guardar los datos podria tomar un poco de tiempo, así que devolvemos una promesa el cual será resuelto si los datos se guardan satisfactoriamente, o rechazada si no se guardan.</p><p>Si te estás preguntando donde obtuve el código de arriba, HarperDB provee una sección increíble de "<a href="https://studio.harperdb.io/resources/examples/QuickStart%20Examples/Create%20dev%20Schema">ejemplos de código</a>" en su dashboard studio, el cual nos facilita la vida:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/07/image-265.png" class="kg-image" alt="HarperDB code examples" width="600" height="400" loading="lazy"></figure><p>¡Tiempo de descanso! Únete a una sala como un usuario, luego envía un mensaje. Luego ve a HarperDB y haz clic en "browse", luego haz clic en la tabla "messages". Deberías ver tú mensaje en la base de datos:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/07/image-264.png" class="kg-image" alt="Our first messages in the database" width="600" height="400" loading="lazy"></figure><p>Genial 😎. Así que, ¿ahora qué? Bueno, sería bueno si los últimos 100 mensajes enviados en la sala fueran cargados cuando un usuario se una a &nbsp;una sala, ¿no?</p><!--kg-card-begin: html--><h2 id="como-obtener-mensajes-desde-harperdb">Cómo obtener los mensajes desde HarperDB</h2><!--kg-card-end: html--><p>En el servidor, creemos una función que solicite los últimos 100 mensajes enviados en una sala particular (fíjate cómo HarperDB también nos permite usar solicitudes de SQL 👌):</p><pre><code class="language-js">// server/services/harper-get-messages.js

let axios = require('axios');

function harperGetMessages(room) {
  const dbUrl = process.env.HARPERDB_URL;
  const dbPw = process.env.HARPERDB_PW;
  if (!dbUrl || !dbPw) return null;

  let data = JSON.stringify({
    operation: 'sql',
    sql: `SELECT * FROM realtime_chat_app.messages WHERE room = '${room}' LIMIT 100`,
  });

  let config = {
    method: 'post',
    url: dbUrl,
    headers: {
      'Content-Type': 'application/json',
      Authorization: dbPw,
    },
    data: data,
  };

  return new Promise((resolve, reject) =&gt; {
    axios(config)
      .then(function (response) {
        resolve(JSON.stringify(response.data));
      })
      .catch(function (error) {
        reject(error);
      });
  });
}

module.exports = harperGetMessages;
</code></pre><p>Llamaremos a esta función cuando sea que un usuario se una a una sala:</p><pre><code class="language-js">// server/index.js

// ...
const harperSaveMessage = require('./services/harper-save-message');
const harperGetMessages = require('./services/harper-get-messages'); // Add this

// ...

// Escucha cuando el cliente se conecta a través de socket.io-client
io.on('connection', (socket) =&gt; {
  console.log(`User connected ${socket.id}`);

  // Agrega un usuario a una sala
  socket.on('join_room', (data) =&gt; {

    // ...

    // Agrega esto
    // Obtiene los últimos 100 mensajes enviados en la sala chat
    harperGetMessages(room)
      .then((last100Messages) =&gt; {
        // console.log('ultimos mensajes', last100Messages);
        socket.emit('last_100_messages', last100Messages);
      })
      .catch((err) =&gt; console.log(err));
  });

 // ...
</code></pre><p>Arriba, si los mensajes se solicitan de forma exitosa, emitimos un evento de Socket.io llamado <code>last_100_messages</code>. Ahora escucharemos este evento en el frontend.</p><!--kg-card-begin: html--><h2 id="como-mostrar-ultimos-100-mensajes-en-el-cliente">Cómo mostrar los últimos 100 mensajes en el Cliente</h2><!--kg-card-end: html--><p>Abajo, agregamos un hook useEffect que contiene un escucha de evento de Socket.io para el evento <code>last_100_messages</code><em>. </em>Desde ahí, los mensajes son ordenados en orden de fecha, con el más reciente al final, y el estado <code>messagesReceived</code> se actualiza.</p><p>Cuando <code>messagesReceived</code> se actualiza, un useEffect se ejecuta para desplazar el div <code>messageColumn</code> al mensaje más reciente. Esto mejora la experiencia de usuario de nuestra aplicación 👍.</p><pre><code class="language-js">// client/src/pages/chat/messages.js

import styles from './styles.module.css';
import { useState, useEffect, useRef } from 'react';

const Messages = ({ socket }) =&gt; {
  const [messagesRecieved, setMessagesReceived] = useState([]);

  const messagesColumnRef = useRef(null); // Add this

  // Se ejecuta cuando sea que un evento del socket se reciba desde el servidor
  useEffect(() =&gt; {
    socket.on('receive_message', (data) =&gt; {
      console.log(data);
      setMessagesReceived((state) =&gt; [
        ...state,
        {
          message: data.message,
          username: data.username,
          __createdtime__: data.__createdtime__,
        },
      ]);
    });

    // Quita el escucha de eventos al desmontarse el componente 
    return () =&gt; socket.off('receive_message');
  }, [socket]);

  // Agrega esto
  useEffect(() =&gt; {
    // Ultimos 100 mensajes enviados en la sala chat (solicitados desde la bd en el backend)
    socket.on('last_100_messages', (last100Messages) =&gt; {
      console.log('Last 100 messages:', JSON.parse(last100Messages));
      last100Messages = JSON.parse(last100Messages);
      // Ordena estos mensajes por __createdtime__
      last100Messages = sortMessagesByDate(last100Messages);
      setMessagesReceived((state) =&gt; [...last100Messages, ...state]);
    });

    return () =&gt; socket.off('last_100_messages');
  }, [socket]);

  // Agrega esto
  // Se desplaza al mensaje más reciente
  useEffect(() =&gt; {
    messagesColumnRef.current.scrollTop =
      messagesColumnRef.current.scrollHeight;
  }, [messagesRecieved]);

  // Agrega esto
  function sortMessagesByDate(messages) {
    return messages.sort(
      (a, b) =&gt; parseInt(a.__createdtime__) - parseInt(b.__createdtime__)
    );
  }

  // dd/mm/yyyy, hh:mm:ss
  function formatDateFromTimestamp(timestamp) {
    const date = new Date(timestamp);
    return date.toLocaleString();
  }

  return (
    // Agrega ref a este div
    &lt;div className={styles.messagesColumn} ref={messagesColumnRef}&gt;
      {messagesRecieved.map((msg, i) =&gt; (
        &lt;div className={styles.message} key={i}&gt;
          &lt;div style={{ display: 'flex', justifyContent: 'space-between' }}&gt;
            &lt;span className={styles.msgMeta}&gt;{msg.username}&lt;/span&gt;
            &lt;span className={styles.msgMeta}&gt;
              {formatDateFromTimestamp(msg.__createdtime__)}
            &lt;/span&gt;
          &lt;/div&gt;
          &lt;p className={styles.msgText}&gt;{msg.message}&lt;/p&gt;
          &lt;br /&gt;
        &lt;/div&gt;
      ))}
    &lt;/div&gt;
  );
};

export default Messages;
</code></pre><!--kg-card-begin: html--><h2 id="como-mostrar-sala-y-usuarios">Cómo mostrar la Sala y los Usuarios (A)</h2><!--kg-card-end: html--><p>Hemos hecho los componentes B y C, así que terminemos todo al hacer A.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/07/image-248.png" class="kg-image" alt="The chat page split into three components" width="600" height="400" loading="lazy"></figure><p>En el servidor, cuando un usario se une a una sala, emitimos un evento <code>chatroomusers</code> que envía todos los usuarios de la sala a todos los clientes en esa sala. Escuchemos ese evento en un componente llamado <em>RoomAndUsers</em>.</p><p>Abajo, también hay un botón "Leave" que, cuando se presiona, hace la emisión de un evento <code>leaveroom</code> al servidor. Luego redirecciona el usuario devuelta a la página principal.</p><pre><code class="language-js">// client/src/pages/chat/room-and-users.js

import styles from './styles.module.css';
import { useState, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';

const RoomAndUsers = ({ socket, username, room }) =&gt; {
  const [roomUsers, setRoomUsers] = useState([]);

  const navigate = useNavigate();

  useEffect(() =&gt; {
    socket.on('chatroom_users', (data) =&gt; {
      console.log(data);
      setRoomUsers(data);
    });

    return () =&gt; socket.off('chatroom_users');
  }, [socket]);

  const leaveRoom = () =&gt; {
    const __createdtime__ = Date.now();
    socket.emit('leave_room', { username, room, __createdtime__ });
    // Redirecciona a la pagina principal
    navigate('/', { replace: true });
  };

  return (
    &lt;div className={styles.roomAndUsersColumn}&gt;
      &lt;h2 className={styles.roomTitle}&gt;{room}&lt;/h2&gt;

      &lt;div&gt;
        {roomUsers.length &gt; 0 &amp;&amp; &lt;h5 className={styles.usersTitle}&gt;Users:&lt;/h5&gt;}
        &lt;ul className={styles.usersList}&gt;
          {roomUsers.map((user) =&gt; (
            &lt;li
              style={{
                fontWeight: `${user.username === username ? 'bold' : 'normal'}`,
              }}
              key={user.id}
            &gt;
              {user.username}
            &lt;/li&gt;
          ))}
        &lt;/ul&gt;
      &lt;/div&gt;

      &lt;button className='btn btn-outline' onClick={leaveRoom}&gt;
        Leave
      &lt;/button&gt;
    &lt;/div&gt;
  );
};

export default RoomAndUsers;
</code></pre><p>Importemos este componente en la página <em>Chat</em>:</p><pre><code class="language-js">// client/src/pages/chat/index.js

import styles from './styles.module.css';
import RoomAndUsersColumn from './room-and-users'; // Add this
import SendMessage from './send-message';
import MessagesReceived from './messages';

const Chat = ({ username, room, socket }) =&gt; {
  return (
    &lt;div className={styles.chatContainer}&gt;
      {/* Agrega esto */}
      &lt;RoomAndUsersColumn socket={socket} username={username} room={room} /&gt;

      &lt;div&gt;
        &lt;MessagesReceived socket={socket} /&gt;
        &lt;SendMessage socket={socket} username={username} room={room} /&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  );
};

export default Chat;
</code></pre><!--kg-card-begin: html--><h2 id="como-quitar-un-usuario-de-sala-socketio">Cómo quitar a un Usuarío de una sala de Socket.io</h2><!--kg-card-end: html--><p>Socket.io provee un método <code>leave()</code> que puedes usar para quitar a un usuario de una sala de Socket.io. También estamos manteniendo un registro de nuestros usuarios en un arreglo en la memoria del servidor, así que quitaremos al usuario de ese arreglo también:</p><pre><code class="language-js">// server/index.js

const leaveRoom = require('./utils/leave-room'); // Add this

// ...

// Escucha cuando el cliente se conecta a través de socket.io-client
io.on('connection', (socket) =&gt; {

  // ...

  // Agrega esto
  socket.on('leave_room', (data) =&gt; {
    const { username, room } = data;
    socket.leave(room);
    const __createdtime__ = Date.now();
    // Quita a un usuario de la memoria
    allUsers = leaveRoom(socket.id, allUsers);
    socket.to(room).emit('chatroom_users', allUsers);
    socket.to(room).emit('receive_message', {
      username: CHAT_BOT,
      message: `${username} has left the chat`,
      __createdtime__,
    });
    console.log(`${username} has left the chat`);
  });
});

server.listen(4000, () =&gt; 'El Servidor se está ejecutando en el puerto 3000');
</code></pre><p>Ahora necesitamos crear la función <code>leaveRoom()</code>:</p><pre><code class="language-js">// server/utils/leave-room.js

function leaveRoom(userID, chatRoomUsers) {
  return chatRoomUsers.filter((user) =&gt; user.id != userID);
}

module.exports = leaveRoom;
</code></pre><p>¿Por qué poner esta función corta en una carpeta <code>utils</code> aparte, te preguntas? Porque lo estaremos usando luego y no queremos repetirnos (mantenemos nuestro código <a href="https://es.wikipedia.org/wiki/No_te_repitas">DRY</a>). </p><p>Probémoslo, abre dos ventanas lado a lado, y únete a ambos chats:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/07/image-266.png" class="kg-image" alt="Two windows chatting in realtime." width="600" height="400" loading="lazy"></figure><p>Luego haz clic en el botón leave en la ventana 2:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/07/image-267.png" class="kg-image" alt="The user is removed from the chat when they click the Leave button" width="600" height="400" loading="lazy"></figure><p>El usuario se quita del chat, y un mensaje se envía a los otros usuarios – notificándolos que se ha ido. ¡Bien!</p><!--kg-card-begin: html--><h2 id="como-agregar-escucha-evento-disconnect">Cómo agregar el Escucha de Evento Disconnect de Socket.io</h2><!--kg-card-end: html--><p>¿Qué pasa si el usuario de alguna manera se desconecta del servidor, como si su internet se cayera? Socket.io provee un escucha de evento adjunto <code>disconnects</code> para esto. Agreguémosle a nuestro servidor para quitar a un usuario de la memoria cuando se desconecta:</p><pre><code class="language-js">// server/index.js

// ...

// Escucha cuando el cliente se conecta a través de socket.io-client
io.on('connection', (socket) =&gt; {

  // ...

  // Agrega esto
  socket.on('disconnect', () =&gt; {
    console.log('El usuario se desconectó del chat');
    const user = allUsers.find((user) =&gt; user.id == socket.id);
    if (user?.username) {
      allUsers = leaveRoom(socket.id, allUsers);
      socket.to(chatRoom).emit('chatroom_users', allUsers);
      socket.to(chatRoom).emit('receive_message', {
        message: `${user.username} se ha desconectado del chat.`,
      });
    }
  });
});

server.listen(4000, () =&gt; 'El Servidor se está ejecutando en el puerto 3000');
</code></pre><p>Y ahí lo tienes – haz construido una aplicación de chat de tiempo real fullstack con un frontend de React, un backend de Node/Express, y una base de datos de HarperDB. ¡Buen trabajo!</p><p>Para la próxima, planeo en revisar nuestras <a href="https://harperdb.io/docs/custom-functions/">Funciones Personalizadas de HarperDB</a>, el cual permite a los usuarios definir sus propios endpoints de API dentro de HarperDB. Esto significa que podemos construir nuestra aplicación completa, ¡en un sólo lugar! Mira un ejemplo de cómo HarperDB está colapsando el stack <a href="https://www.harperdb.io/post/mean-stack-alternative">en este artículo</a>.</p><h2 id="un-desaf-o-para-ti-"><strong>Un desafío para ti 💪</strong></h2><p>Si refrescas la página Chat, el nombre de usuario del usuario y la sala desaparecerán. Mira si puedes prevenir que esta información se pierda cuando el usuario refresque la página. Pista: ¡el <a href="https://www.w3schools.com/html/html5_webstorage.asp">local storage</a> podría ser útil!</p><h2 id="-gracias-por-leer-"><strong>¡Gracias<strong><strong> </strong></strong>por<strong><strong> </strong></strong>leer<strong><strong>!</strong></strong></strong></h2><p>Si te pareció útil este artículo, puedes:</p><ul><li><a href="https://www.youtube.com/channel/UC0URylW_U4i26wN231yRqvA">Suscribirte a mi canal de YouTube</a>. Estaré subiendo tutoriales en profunidad y vídeos de proyectos sobre React/NextJS/Node/Express.</li><li><a href="https://twitter.com/doabledanny">Sígueme en Twitter</a> donde comparto tweets sobre mi jornada de freelancing, proyectos propios, y aprendizajes actuales.</li><li><a href="https://doabledanny.gumroad.com/">Revisa mi almacén de Gumroad</a> donde hago hojas de trucos y pósteres útiles y populares (8000 descargas al tiempo de escribir).</li><li><a href="https://www.doabledanny.com/blog/">Revisa mi blog</a></li></ul> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Curso API CRUD - Node.js, Express, MongoDB y Autenticación ]]>
                </title>
                <description>
                    <![CDATA[ Las operaciones CRUD son la base del desarrollo web backend. CRUD significa Crear, Leer, Actualizar y Eliminar. Son operaciones esenciales para el desarrollo web moderno ya que son utilizadas para gestionar datos en la mayoría de las aplicaciones web. Acabamos de publicar un curso en el canal de YouTube en ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/curso-api-crud-node-mongodb/</link>
                <guid isPermaLink="false">6723833462fb9a0442557990</guid>
                
                    <category>
                        <![CDATA[ Node.js ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Estefania Cassingena Navone ]]>
                </dc:creator>
                <pubDate>Tue, 05 Nov 2024 04:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2024/11/CRUD-Leonardo-Thumbnail.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Las operaciones CRUD son la base del desarrollo web backend. CRUD significa Crear, Leer, Actualizar y Eliminar. Son operaciones esenciales para el desarrollo web moderno ya que son utilizadas para gestionar datos en la mayoría de las aplicaciones web.</p><p>Acabamos de publicar un curso en el <a href="https://www.youtube.com/freecodecampespanol" rel="noopener noreferrer nofollow">canal de YouTube en español de </a><a href="http://freeCodeCamp.org" rel="noopener noreferrer nofollow">freeCodeCamp.org</a><a href="https://www.youtube.com/freecodecampespanol" rel="noopener noreferrer nofollow"> </a>que te enseñará a implementar APIs REST con Node.js, Express y MongoDB. Aprenderás a diseñar rutas, manejar solicitudes HTTP, interactuar con bases de datos NoSQL y proteger tus endpoints con autenticación basada en JSON Web Tokens.</p><p>El curso fue creado por Leonardo José Castillo Lacruz. Leonardo es desarrollador de software y creador de contenido a quien le encanta enseñar programación y compartir sus conocimientos.</p><h2 id="apis-y-bases-de-datos-no-relacionales"><strong>APIs y bases de datos no relacionales</strong></h2><p>Veamos algunos conceptos importantes para el curso.</p><p><strong>API</strong> significa “Application Programming Interface” en inglés. En español, podemos traducir este acrónimo como “Interfaz de programación de aplicaciones".</p><p>Una API es un conjunto de reglas y especificaciones que permiten que distintas aplicaciones se comuniquen entre sí. Las APIs permiten que el proceso de integración de sistemas y servicios sea mucho más fácil, permitiendo la creación de aplicaciones web más complejas.</p><p>En el mundo del desarrollo web, puedes considerar a las APIs como el puente entre el front-end y el back-end porque permiten que haya un intercambio fluido de datos entre ambas partes de la aplicación.</p><p>Las APIs y las bases de datos están muy relacionadas porque a menudo trabajan juntas. Una API puede interactuar con una base de datos para recuperar, almacenar y modificar datos.</p><p>Por ejemplo, una aplicación web puede usar una API para obtener o actualizar información de un usuario en una base de datos.</p><p>Durante el curso trabajarás con <strong>MongoDB</strong>, una base de datos no relacional. Este tipo de base de datos también es llamada NoSQL.</p><p>Las bases de datos no relacionales son un tipo de base de datos que no almacenan datos en tablas con filas y columnas. En cambio, tienen formas más flexibles de estructurar y almacenar los datos.</p><p>MongoDB los almacena en documentos similares al formato JSON, lo cual permite a los desarrolladores seguir un modelo más dinámico y adaptable.</p><p>Esto es ideal para aplicaciones que manejan grandes volúmenes de datos no estructurados o semi-estructurados.</p><p>Para modelar estos datos, también aprenderás a trabajar con una biblioteca de Node.js llamada <strong>Mongoose</strong>, que te ayuda a definir el esquema de una base de datos para simplificar la interacción entre Node.js y MongoDB.</p><p>Todas estas interacciones deberían tener algún tipo de autenticación para asegurarte de que sólo los usuarios adecuados puedan realizan operaciones en la base de datos a través de la API. Para ello, usarás JSON Web Tokens, una forma estandarizada de transmitir información de forma segura en formato JSON.</p><h2 id="curso-de-crud"><strong><strong><strong>Curso de </strong>CRUD</strong></strong></h2><p>Genial. Ahora que sabes más sobre estos conceptos, veamos lo que aprenderás durante el curso:</p><ul><li>Introducción a MongoDB</li><li>Instalar y configurar MongoDB</li><li>MongoDB Atlas</li><li>Conexión con MongoDB Shell</li><li>Cómo estructurar una API</li><li>Rutas y controladores</li><li>Conexión con MongoDB</li><li>Implementación del CRUD</li><li>Introducción de Mongoose</li><li>Ajustar el modelo de datos</li><li>Validar los datos y probar la API</li><li>Rutas públicas, privadas y de autenticación</li><li>Modelo de usuarios</li><li>JSON Web Tokens</li><li>Verificar los tokens</li><li>Y más...</li></ul><p>Durante el curso, crearás una API RESTful para un sistema de adopción de mascotas. 🐾</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1730379093222/fe12c1d2-bc45-4938-a8f2-b07e6b068d54.png" class="kg-image" alt="fe12c1d2-bc45-4938-a8f2-b07e6b068d54" width="1920" height="1080" loading="lazy"><figcaption>Captura de pantalla del curso. Implementando las rutas.</figcaption></figure><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1730379108002/b85f9232-f63c-461f-8d3e-fdb0494fd5a2.png" class="kg-image" alt="b85f9232-f63c-461f-8d3e-fdb0494fd5a2" width="1920" height="1080" loading="lazy"><figcaption>Captura de pantalla del curso. Implementando el CRUD.</figcaption></figure><p>Te invitamos a ver el curso en el canal de YouTube de <a href="https://www.youtube.com/freecodecampespanol">freeCodeCamp.org en español</a>:</p><figure class="kg-card kg-embed-card" data-test-label="fitted">
        <div class="fluid-width-video-container">
          <div style="padding-top: 56.49999999999999%;" class="fluid-width-video-wrapper">
            <iframe width="200" height="113" src="https://www.youtube.com/embed/Oa5blAV7Fyg?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" title="Curso API CRUD - Node.js, Express, MongoDB, Autenticación" name="fitvid0"></iframe>
          </div>
        </div>
      </figure><p>✍️ Curso creado por Leonardo José Castillo Lacruz.</p><ul><li>YouTube: <a href="https://www.youtube.com/leonardocastillo79" rel="noopener noreferrer nofollow">@LeonardoCastillo79</a></li><li>LinkedIn: <a href="https://www.linkedin.com/in/leonardo-castillo-4911571a/" rel="noopener noreferrer nofollow">Leonardo José Castillo Lacruz</a></li><li>Twitter: <a href="https://twitter.com/ljcl79" rel="noopener noreferrer nofollow">@ljcl79</a></li><li>GitHub: <a href="https://github.com/ljcl79" rel="noopener noreferrer nofollow">@ljcl79</a></li></ul> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Un vistazo rápido a Bun 1.0 - Una alternativa a Node.js ]]>
                </title>
                <description>
                    <![CDATA[ Un hombre sabio me dijo una vez: "Cuando empieces a comer Bun (panecillo), Node.js se sentirá insípido". Pero ¿por qué es eso relevante? JavaScript se volvió mucho más rápido con un nuevo entorno de ejecución de JavaScript llamado Bun, que ahora está listo para producción con su versión 1.0. ¿Cómo ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/un-vistazo-rapido-a-bun-1-0-una-alternativa-a-node-js/</link>
                <guid isPermaLink="false">65c24f33aa1f2203f0eb0f2e</guid>
                
                    <category>
                        <![CDATA[ nodejs ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Node ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Node.js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ bun ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Cristian Fernando Villca Gutierrez ]]>
                </dc:creator>
                <pubDate>Wed, 14 Feb 2024 19:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2024/02/But-why-is-that-relevant--2-.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <h3 id="un-hombre-sabio-me-dijo-una-vez-cuando-empieces-a-comer-bun-panecillo-node-js-se-sentir-ins-pido-">Un hombre sabio me dijo una vez: "Cuando empieces a comer Bun (panecillo), Node.js se sentirá insípido".</h3><p>Pero ¿por qué es eso relevante? JavaScript se volvió mucho más rápido con un nuevo entorno de ejecución de JavaScript llamado Bun, que ahora está listo para producción con su versión 1.0.</p><p>¿Cómo y por qué es más rápido que Node.js? Me vienen a la mente muchas preguntas.</p><p>Responderé algunas de esas preguntas en este artículo. Y lo haré rápidamente, ya que ahora soy más rápido, al igual que JavaScript, que se prepara con Bun 1.0.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2023/09/But-why-is-that-relevant--3-.gif" class="kg-image" alt="But-why-is-that-relevant--3-" width="600" height="400" loading="lazy"></figure><p><strong>Bun es un conjunto de herramientas rápidas todo en uno para ejecutar, crear, probar y depurar JavaScript y TypeScript</strong>, desde un único archivo hasta una aplicación <em>full-stack</em>.</p><p>A continuación algunas cosas que podemos hacer con Bun:</p><h2 id="ejecuta-tu-c-digo-m-s-r-pido-con-bun">Ejecuta tu código más rápido con Bun</h2><p>Ahora no necesitamos herramientas como <code>npm</code>, <code>pnpm</code> o <code>yarn</code> porque Bun es 17 veces mas rápido. Eche un vistazo a los datos mostrados a continuación:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2024/02/266451126-23cbde35-b859-41b5-9480-98b88bf40c44.png" class="kg-image" alt="266451126-23cbde35-b859-41b5-9480-98b88bf40c44" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2024/02/266451126-23cbde35-b859-41b5-9480-98b88bf40c44.png 600w, https://www.freecodecamp.org/espanol/news/content/images/size/w1000/2024/02/266451126-23cbde35-b859-41b5-9480-98b88bf40c44.png 1000w, https://www.freecodecamp.org/espanol/news/content/images/size/w1600/2024/02/266451126-23cbde35-b859-41b5-9480-98b88bf40c44.png 1600w, https://www.freecodecamp.org/espanol/news/content/images/size/w2400/2024/02/266451126-23cbde35-b859-41b5-9480-98b88bf40c44.png 2400w" sizes="(min-width: 720px) 720px" width="2680" height="1324" loading="lazy"><figcaption>Comparación de velocidades entre Bun, pnpm, npm y yarn</figcaption></figure><p>Bun tarda solo 0,36 segundos en compilar su código, mientras que tarda unos 6,44 segundos en el caso de pnpm, 10,58 segundos con npm y 12,08 segundos con yarn.</p><h2 id="bun-soporta-hot-reloading">Bun soporta <em>hot reloading</em></h2><p>Bun soporta <em>hot reloading</em> (recarga en caliente) desde el primer momento, por lo que no necesita herramientas como Nodemon. Actualizará automáticamente el servidor cuando se ejecute JavaScript o TypeScript.</p><p>Puede reemplazar el comando <code>npm run</code> con <code>bun run</code> para ahorrar más de 150 ms milisegundos cada vez que ejecuta un comando.</p><p>Aquí un gráfico completo:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2024/02/Screenshot-2023-09-14-at-7.17.45-PM-1.png" class="kg-image" alt="Screenshot-2023-09-14-at-7.17.45-PM-1" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2024/02/Screenshot-2023-09-14-at-7.17.45-PM-1.png 600w, https://www.freecodecamp.org/espanol/news/content/images/size/w1000/2024/02/Screenshot-2023-09-14-at-7.17.45-PM-1.png 1000w, https://www.freecodecamp.org/espanol/news/content/images/2024/02/Screenshot-2023-09-14-at-7.17.45-PM-1.png 1198w" sizes="(min-width: 720px) 720px" width="1198" height="434" loading="lazy"><figcaption>Promedio de tiempos de <em>hot realoding </em>usando diferentes paquetes</figcaption></figure><p>Según el cuadro anterior, el uso de <code>npm</code> tarda unos 176 ms en ejecutarse, <code>yarn</code> tarda unos 131 ms. En el caso de <code>pnpm</code>, se necesitan 259 ms. Sin embargo, en el caso de Bun, se necesitan unos 7 ms. Eso es rápido, ¿no?</p><h2 id="bun-es-un-empaquetador-javascript">Bun es un empaquetador JavaScript</h2><p>Bun también es un empaquetador de JavaScript con el mejor rendimiento de su clase y una API compatible con ESBuild, por lo que no necesitamos cosas como:</p><ul><li>ESBuild</li><li>Webpack</li><li>Parcel, .parcelrc</li><li>Rollup, rollup.config.js</li></ul><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/espanol/news/content/images/2024/02/But-why-is-that-relevant--2-.gif" class="kg-image" alt="But-why-is-that-relevant--2-" width="1920" height="1080" loading="lazy"></figure><p>Bun ahora soporta Next.js, Remix, Nuxt, Astro, SvelteKit, Nest, SolidStart y Vite.</p><h2 id="bun-es-compatible-con-esm-y-commonjs">Bun es compatible con ESM y CommonJS</h2><p>Otra gran característica de Bun es que podemos usar módulos ES6 y CommonJs juntos en el mismo archivo, lo que no era posible en Node.js.</p><p>Puedes usar <code>import</code> y <code>require()</code> en el mismo archivo:</p><figure class="kg-card kg-code-card"><pre><code class="language-js">import lodash from "lodash";
const _ = require("underscore");</code></pre><figcaption>ESM y CommonJs en el mismo archivo</figcaption></figure><p>Aparte de eso, Bun tiene soporte integrado para las API estándar web que están disponibles en los navegadores, como <code>fetch</code>, junto con la propia API de Bun como <code>Bun.file()</code> para leer un archivo de forma diferida y <code>Bun.Write()</code> para escribir un archivo al sistema de archivos local, que es mucho más simple que Node.js.</p><h2 id="ejemplo-bun-file-">Ejemplo <code>Bun.file()</code></h2><figure class="kg-card kg-code-card"><pre><code class="language-js">const archivo = Bun.file("package.json");
const contenido = await archivo.text();
</code></pre><figcaption>Leemos archivos del sistema de archivos con Bun</figcaption></figure><p>El código anterior leerá el contenido de un archivo <code>package.json</code> y transferirá su contenido a una nueva variable llamada <code>contenido</code>.</p><h2 id="ejemplo-bun-write-">Ejemplo <code>Bun.write()</code></h2><figure class="kg-card kg-code-card"><pre><code class="language-js">await Bun.write("index.html", "&lt;html/&gt;");
await Bun.write("index.html", Buffer.from("&lt;html/&gt;"));
await Bun.write("index.html", Bun.file("home.html"));
await Bun.write("index.html", 
await fetch("https://ejemplo.com/"));</code></pre><figcaption>Escribimos archivos en el sistema de archivos</figcaption></figure><p>En el código anterior, <code>Bun.write()</code> escribirá la cadena <code>"&lt;html/&gt;"</code>, o copiará el contenido del archivo <code>home.html</code> en el archivo <code>index.html</code>. Si tenemos que recuperar datos, obtendrá los resultados de una API web externa y escribirá el contenido en un archivo <code>index.html</code>.</p><h2 id="-por-que-bun-es-tan-r-pido">¿Por que Bun es tan rápido?</h2><p>Bun es rápido porque usa el motor JavaScriptCore, mientras que Node.js usa el motor JavaScript V8. El primero se ha optimizado para un tiempo de inicio más rápido.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2024/02/But-why-is-that-relevant.png" class="kg-image" alt="But-why-is-that-relevant" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2024/02/But-why-is-that-relevant.png 600w, https://www.freecodecamp.org/espanol/news/content/images/size/w1000/2024/02/But-why-is-that-relevant.png 1000w, https://www.freecodecamp.org/espanol/news/content/images/2024/02/But-why-is-that-relevant.png 1600w" sizes="(min-width: 720px) 720px" width="1600" height="900" loading="lazy"><figcaption>Bun usa JavaScriptCore | Node usa V8</figcaption></figure><p>Si deseas hacer las cosas más rápido, debería considerar reemplazar Node.js con Bun.</p><h2 id="-c-mo-empezar-a-usar-bun">¿Cómo empezar a usar Bun?</h2><p>Puedes instalar Bun en sistemas MacOS y Linux usando <code>npm</code>:</p><figure class="kg-card kg-code-card"><pre><code class="language-shell">npm install -g bun</code></pre><figcaption>Comando para instalar Bun en MacOs y distribuciones Linux</figcaption></figure><p>Ahora ya está todo listo. Para instalar un paquete <code>npm</code>, haz esto:</p><figure class="kg-card kg-code-card"><pre><code class="language-shell">bun install &lt;nombre-paquete&gt;</code></pre><figcaption>Comando para instalar paquetes usando Bun</figcaption></figure><p>Para iniciar una aplicación, haz esto:</p><figure class="kg-card kg-code-card"><pre><code class="language-shell">bun run dev</code></pre><figcaption>Ejecutar una app Next.js</figcaption></figure><p>Para todo lo que pueda necesitar solo reemplace <code>npm</code> con <code>bun</code>.</p><p>Sin embargo, Bun sólo está listo para producción en los sistemas operativos MacOS y Linux. La versión de Windows aún es experimental. Por el momento, solo se admite el entorno de ejecución de JavaScript para Windows, y no el administrador de paquetes, el empaquetador ni el entorno de pruebas. <a href="https://bun.sh/docs/installation#windows">Puedes leer más al respecto aquí</a>.</p><h1 id="conclusi-n">Conclusión</h1><p>Este artículo muestra cómo puedes utilizar Bun como alternativa a Node.js y acelerar su tiempo de desarrollo.</p><p>También puedes ver mi vídeo sobre <a href="https://www.youtube.com/watch?v=q5UKY_dCmh4"><strong>El asesino de Node.js está aquí — Primer vistazo a Bun 1.0</strong></a><strong> (en inglés)</strong>.</p><p>Gracias por leer.</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Cómo instalar Node.js en MacOS, Linux o Windows usando NVM ]]>
                </title>
                <description>
                    <![CDATA[ Antes de empezar a crear aplicaciones asombrosas con Node.js, debes instalarlo. Afortunadamente, instalar Node.js es supersimple. En este tutorial, vamos a cubrir cómo instalar NodeJS y NPM en:  * macO / Linux  * Windows Una vez hayas instalado NVM, puedes gestionar fácilmente tu versión de Node con un ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/como-instalar-node-js-en-macos-linux-o-windows-usando-nvm/</link>
                <guid isPermaLink="false">65b352b9b211ed048f3dd4c4</guid>
                
                    <category>
                        <![CDATA[ Node.js ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Jamer José ]]>
                </dc:creator>
                <pubDate>Mon, 05 Feb 2024 02:22:21 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2024/01/5f9c9a1a740569d1a4ca238a.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artículo original:</strong> <a href="https://www.freecodecamp.org/news/how-to-install-node-in-your-machines-macos-linux-windows/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">How to Install Node on a MacOS, Linux, or Windows Machine Using NVM</a>
      </p><p>Antes de empezar a crear aplicaciones asombrosas con Node.js, debes instalarlo. Afortunadamente, instalar Node.js es supersimple.</p><p>En este tutorial, vamos a cubrir cómo instalar NodeJS y NPM en:</p><ul><li>macO / Linux</li><li>Windows</li></ul><p>Una vez hayas instalado NVM, puedes gestionar fácilmente tu versión de Node con un solo comando. El siguiente videotutorial muestra como puedes descargar y ejecutar NVM en tu máquina:</p><h2 id="gu-a-de-instalaci-n-para-mac-os-y-linux"><strong>Guía de instalación para Mac OS y Linux</strong></h2><p>Entra a una nueva terminal y ejecuta el siguiente comando, este bajará la versión más reciente de NVM y paso seguido, ejecutará el script de instalación:</p><pre><code>curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
</code></pre><p>Reinicia tu terminal para que se apliquen los cambios (o abre una nueva) y ejecuta el siguiente comando:</p><pre><code>nvm ls
</code></pre><p>Verás una salida como esta:</p><pre><code>            N/A
iojs -&gt; N/A (default)
node -&gt; stable (-&gt; N/A) (default)
unstable -&gt; N/A (default)
</code></pre><p>Ahora podemos instalar cualquier versión con el siguiente comando, por ejemplo, para instalar la 12.18.1:</p><pre><code>nvm install 12.18.1
</code></pre><p>Una vez se instale, ya está lista para ser usada. Para utilizar la versión, solo debes ejecutar el siguiente comando:</p><pre><code>nvm use 12.18.1
</code></pre><p>Para verificar el procedimiento puedes ejecutar el siguiente comando que mostrará la versión de Node.js actual:</p><figure class="kg-card kg-code-card"><pre><code>node --v</code></pre><figcaption>Esto mostrará "v12.18.1" (la cuál es la versión de Node que acabamos de instalar)</figcaption></figure><p>Y eso es todo - has terminado. Pásala bien :P</p><p>Ahora, si por alguna razón futura deseas desinstalar NVM, simplemente abre la terminal y ejecuta lo siguiente:</p><pre><code>rm -rf $NVM_DIR
</code></pre><figure class="kg-card kg-embed-card" data-test-label="fitted">
        <div class="fluid-width-video-container">
          <div style="padding-top: 56.49999999999999%;" class="fluid-width-video-wrapper">
            <iframe width="200" height="113" src="https://www.youtube.com/embed/M_asn_Vr3Xs?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="" title="NVM | Node version Manager (Multiples versiones de Node)" name="fitvid0"></iframe>
          </div>
        </div>
      </figure><h2 id="gu-a-de-instalaci-n-para-windows"><strong>Guía de instalación para Windows</strong></h2><p>Primero, ve la sección de <code>releases</code> en el repositorio de NVM para Windows: <a href="https://github.com/coreybutler/nvm-windows/releases">https://github.com/coreybutler/nvm-windows/releases</a>. </p><p>Una vez ahí seleccionamos la última versión y descargamos el archivo <code>nvm-setup.zip</code></p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/espanol/news/content/images/2024/01/image.png" class="kg-image" alt="image" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2024/01/image.png 600w, https://www.freecodecamp.org/espanol/news/content/images/size/w1000/2024/01/image.png 1000w, https://www.freecodecamp.org/espanol/news/content/images/size/w1600/2024/01/image.png 1600w, https://www.freecodecamp.org/espanol/news/content/images/size/w2400/2024/01/image.png 2400w" sizes="(min-width: 720px) 720px" width="2649" height="2104" loading="lazy"></figure><p>Una vez hayas descargado el instalador, dale a ejecutar y sigue los pasos que se presentan, si has descargado el archivo zip, debes extraerlo primero, puedes usar <a href="https://www.7-zip.org/">7zip</a> que es totalmente gratis y de código libre.</p><p>Para verificar que <code>nvm</code> se ha instalado correctamente, abre una nueva terminal y ejecuta el comando <code>nvm</code>. Una vez verificado, puedes pasar al siguiente paso.</p><p>Para instalar una versión de Node.js usando <code>nvm</code> lo hacemos de esta manera:</p><pre><code>nvm install &lt;version_number&gt; // vamos a asumir que queremos la 12.18.1</code></pre><p>La versión puede ser una específica (ejemplo 18.7.1) o puedes utilizar también la palabra <code>latest</code> para descargar la última versión LTS.</p><p>Para usar una versión en específico simplemente utilizamos el comando <code>nvm use</code>:</p><pre><code>nvm use 12.18.1</code></pre><p>Puedes verificar la versión de node ejecutando <code>node -v</code> en tu terminal, esto debería mostrarte <code>v12.18.1</code>.</p><p>Ya con estos pasos deberías tener una versión de Node.js corriendo en tu máquina. Mucha suerte con tu código compañero. :)</p><figure class="kg-card kg-embed-card" data-test-label="fitted">
        <div class="fluid-width-video-container">
          <div style="padding-top: 56.49999999999999%;" class="fluid-width-video-wrapper">
            <iframe width="200" height="113" src="https://www.youtube.com/embed/Z-Ofqd2yBCc?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="" title="Cómo Instalar NodeJS, NPM y NVM en Windows - GRATIS [2023]" name="fitvid1"></iframe>
          </div>
        </div>
      </figure><p>Déjame saber si encontraste esta guía útil. Déjame un mensaje en <a href="https://twitter.com/adeelibr">twitter</a> (<a href="https://twitter.com/adeelibr">twitter.com/adeelibr</a>).</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Node.js Streams: Todo lo que necesitas saber ]]>
                </title>
                <description>
                    <![CDATA[ > Actualización: Este artículo es ahora parte de mi libro "Node.js Beyond The Basics". Lee la versión actualizada de este contenido y más sobre Node en  jscomplete.com/node-beyond-basics [https://github.com/samerbuna/efficient-node]. Los flujos de Node.js (streams)tienen la reputación de ser difíciles de trabajar, y aún más difíciles de entender. Bueno, tengo buenas ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/node-js-streams-todo-lo-que-necesitas-saber/</link>
                <guid isPermaLink="false">63c06ae5700708073437a503</guid>
                
                    <category>
                        <![CDATA[ Node.js ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Luis E. Alvarado ]]>
                </dc:creator>
                <pubDate>Thu, 02 Mar 2023 20:23:56 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2023/01/node_js_streams.gif" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artículo original:</strong> <a href="https://www.freecodecamp.org/news/node-js-streams-everything-you-need-to-know-c9141306be93/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">Node.js Streams: Everything you need to know</a>
      </p><blockquote>Actualización: Este artículo es ahora parte de mi libro "Node.js Beyond The Basics".<br><br>Lee la versión actualizada de este contenido y más sobre Node en <a href="https://github.com/samerbuna/efficient-node">jscomplete.com/node-beyond-basics</a>.</blockquote><p>Los flujos de Node.js (<em>streams</em>)tienen la reputación de ser difíciles de trabajar, y aún más difíciles de entender. Bueno, tengo buenas noticias para ti - ese ya no es el caso.</p><p>A lo largo de los años, los desarrolladores han creado montones de paquetes con el único propósito de facilitar el trabajo con flujos. Pero en este artículo, voy a centrarme en la API nativa de <a href="https://nodejs.org/api/stream.html">flujos de Node.js</a>.</p><blockquote>“Los flujos son la mejor y más incomprendida idea de Node.”<br><br>— Dominic Tarr</blockquote><h3 id="-qu-son-exactamente-los-flujos">¿Qué son exactamente los flujos?</h3><p>Los flujos son colecciones de datos, como las matrices o las cadenas de texto. La diferencia es que estos pueden no estar disponibles todos a la vez y no tienen por qué caber en la memoria. Esto hace que sean realmente potentes cuando se trabaja con grandes cantidades de datos, o con datos que vienen de una fuente externa de uno en uno.</p><p>Sin embargo, los flujos no sólo sirven para trabajar con grandes cantidades de datos. También nos ofrecen la posibilidad de componer nuestro código. Al igual que podemos componer poderosos comandos de Linux mediante la canalización de otros comandos más pequeños, podemos hacer exactamente lo mismo en Node con los flujos.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/1*Fp3dyVZckIUjPFOp58x-zQ.png" class="kg-image" alt="1*Fp3dyVZckIUjPFOp58x-zQ" width="800" height="102" loading="lazy"><figcaption>Compatibilidad con comandos Linux</figcaption></figure><pre><code class="language-js">const grep = ... // Un flujo para la salida de grep
const wc = ... // A stream for the wc input

grep.pipe(wc)</code></pre><p>Muchos de los módulos incorporados en Node implementan la interfaz de <em>streaming</em>:</p><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/1*lhOvZiDrVbzF8_l8QX3ACw.png" class="kg-image" alt="1*lhOvZiDrVbzF8_l8QX3ACw" width="800" height="473" loading="lazy"></figure><p>La lista anterior tiene algunos ejemplos de objetos nativos de Node.js que también son flujos legibles y escribibles. Algunos de estos objetos son flujos tanto legibles como escribibles, como los <em>sockets</em> TCP, zlib y flujos <em>crypto</em>.</p><p>Observa que los objetos también están estrechamente relacionados. Mientras que una respuesta HTTP es un flujo legible en el cliente, es un flujo escribible en el servidor. Esto se debe a que en el caso HTTP, básicamente leemos de un objeto (<code>http.IncomingMessage</code>) y escribimos en el otro (<code>http.ServerResponse</code>).</p><p>Observe también cómo los flujos <code>stdio</code> ( <code>stdin</code>, <code>stdout</code>, <code>stderr</code>) tienen los tipos de flujo inversos cuando se trata de procesos hijo. Esto permite una manera realmente fácil de canalizar hacia y desde estos flujos desde los flujos <code>stdio</code> del proceso principal.</p><h3 id="un-ejemplo-pr-ctico-de-flujos">Un ejemplo práctico de flujos</h3><p>La teoría está muy bien, pero a menudo no convence al 100%. Veamos un ejemplo que demuestra la diferencia que pueden marcar los flujos en el código en lo que respecta al consumo de memoria.</p><p>Primero vamos a crear un archivo grande:</p><pre><code class="language-js">const fs = require('fs');
const archivo = fs.createWriteStream('./big.file');

for(let i=0; i&lt;= 1e6; i++) {
  file.write('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n');
}

file.end();</code></pre><p>Mira lo que usé para crear ese gran archivo. ¡Un stream escribible!</p><p>El módulo <code>fs</code> se puede utilizar para leer y escribir en archivos utilizando una interfaz de flujo. En el ejemplo anterior, estamos escribiendo en ese <code>big.file</code> a través de un flujo escribible de 1 millón de líneas con un bucle.</p><p>Ejecutando el <em>script </em>de arriba se genera un archivo de unos ~400 MB.</p><p>Aquí hay un simple servidor web Node diseñado para servir exclusivamente el <code>big.file</code>:</p><pre><code class="language-js">const fs = require('fs');
const servidor = require('http').createServer();

servidor.on('request', (peticion, respuesta) =&gt; {
  fs.readFile('./big.file', (error, data) =&gt; {
    if (error) throw error;
  
    respuesta.end(data);
  });
});

servidor.listen(8000);</code></pre><p>Cuando el servidor reciba una petición, servirá el archivo grande usando el método asíncrono, <code>fs.readFile</code>. Pero bueno, no es que estemos bloqueando el bucle de eventos ni nada. Todo va genial, ¿verdad? ¿Verdad?</p><p>Bueno, veamos qué pasa cuando ejecutamos el servidor, nos conectamos a él, y monitorizamos la memoria mientras lo hacemos.</p><p>Cuando ejecuté el servidor, empezó con una cantidad normal de memoria, 8.7 MB:</p><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/1*125_8HQ4KzJkeBcj1LcEiQ.png" class="kg-image" alt="1*125_8HQ4KzJkeBcj1LcEiQ" width="800" height="422" loading="lazy"></figure><p>Luego me conecté al servidor. Observe lo que ocurrió con la memoria consumida:</p><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/1*SGJw31T5Q9Zfsk24l2yirg.gif" class="kg-image" alt="1*SGJw31T5Q9Zfsk24l2yirg" width="800" height="614" loading="lazy"></figure><p>Vaya, el consumo de memoria ha subido a 434,8 MB.</p><p>Básicamente ponemos todo el <code>big.file</code> en memoria antes de escribirlo en el objeto de respuesta. Esto es muy ineficiente.</p><p>El objeto de respuesta HTTP (<code>res</code> &nbsp;el objeto de respuesta HTTP) es también un flujo escribible. Esto significa que si tenemos un flujo legible que representa el contenido de <code>big.file</code>, podemos superponerlas y obtener prácticamente el mismo resultado sin consumir ~400 MB de memoria.</p><p>El módulo <code>fs</code> de Node puede proporcionarnos un flujo legible para cualquier archivo utilizando el método <code>createReadStream</code>. Podemos enviarlo al objeto de respuesta:</p><pre><code class="language-js">const fs = require('fs');
const servidor = require('http').createServer();

servidor.on('request', (peticion, respuesta) =&gt; {
  const src = fs.createReadStream('./big.file');
  src.pipe(respuesta);
});

servidor.listen(8000);</code></pre><p>Ahora, cuando te conectas a este servidor, ocurre algo mágico (fíjate en el consumo de memoria):</p><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/1*iWNNIMhF9QmD25Vho6-fRQ.gif" class="kg-image" alt="1*iWNNIMhF9QmD25Vho6-fRQ" width="800" height="615" loading="lazy"></figure><p>¿Qué es lo que ocurre?</p><p>Cuando un cliente pide un archivo tan grande, lo transmitimos de uno en uno, lo que significa que no lo almacenamos en memoria. El uso de memoria creció unos 25 MB y eso es todo.</p><p>Puedes llevar este ejemplo al límite. Regenera el archivo <code>big.file</code> con cinco millones de líneas en lugar de sólo un millón, lo que llevaría el archivo a más de 2 GB, y eso es realmente más grande que el límite de búfer por defecto en Node.</p><p>Si intentas servir ese archivo utilizando <code>fs.readFile</code>, simplemente no puedes, por defecto (puedes cambiar los límites). Pero con <code>fs.createReadStream</code>, no hay ningún problema en transmitir 2 GB de datos al solicitante, y lo mejor de todo es que el uso de memoria del proceso será aproximadamente el mismo.</p><p>¿Listo para aprender sobre flujos ahora?</p><h3 id="flujos-101"><strong>Flujos<strong> 101</strong></strong></h3><p>Hay cuatro tipos fundamentales de flujos en Node.js: Lectura, escritura, dúplex, y transformación de flujos.</p><ul><li>Un flujo legible es una abstracción de una fuente desde la que se pueden consumir datos. Un ejemplo de ello es el método <code>fs.createReadStream</code>.</li><li>Un flujo escribible es una abstracción de un destino en el que se pueden escribir datos. Un ejemplo de ello es el método <code>fs.createWriteStream</code>.</li><li>Un flujo dúplex es tanto legible como escribible. Un ejemplo de ello es un socket TCP.</li><li>Un flujo de transformación es básicamente un flujo dúplex que puede utilizarse para modificar o transformar los datos a medida que se escriben y se leen. Un ejemplo de ello es el flujo <code>zlib.createGzip</code> para comprimir los datos usando "gzip". Puedes pensar en un flujo de transformación como una función en la que la entrada es la parte del flujo que se puede escribir y la salida es la parte del flujo que se puede leer. También puedes oír referirse a los flujos de transformación como "flujos pasantes".</li></ul><p>Todos los flujos son instancias de <code>EventEmitter</code>. Emiten eventos que pueden utilizarse para leer y escribir datos. Sin embargo, podemos consumir los datos en los flujos de una forma más sencilla utilizando el método <code>pipe</code>.</p><h4 id="el-m-todo-pipe"><strong>El método "pipe"</strong></h4><p>Esta es la línea mágica que debes recordar:</p><pre><code class="language-js">fuenteLegible.pipe(destinoEscribible)</code></pre><p>En esta simple línea, estamos canalizando la salida de un flujo legible - la fuente de datos, como la entrada de un flujo escribible - el destino. La fuente tiene que ser un flujo legible y el destino uno escribible. Por supuesto, ambos pueden ser también flujos dúplex/transformados. De hecho, si estamos canalizando a un flujo dúplex, podemos encadenar llamadas de canalización como hacemos en Linux:</p><pre><code class="language-js">fuenteLegible
  .pipe(transformarFlujo1)
  .pipe(transformarFlujo2)
  .pipe(destinoEscribibleFinal)</code></pre><p>El método <code>pipe</code> &nbsp;retorna el flujo de destino, lo que nos permitió hacer el encadenamiento anterior. Para flujos <code>a</code> (legible), <code>b</code> and <code>c</code> (duplex), and <code>d</code> (escribible), podemos:</p><pre><code class="language-js">a.pipe(b).pipe(c).pipe(d)

# Que es equivalente a:
a.pipe(b)
b.pipe(c)
c.pipe(d)

# Que, en Linux, es equivalente a:
$ a | b | c | d</code></pre><p>El método <code>pipe</code> es la forma más sencilla de consumir flujos. Por lo general, se recomienda utilizar el método <code>pipe</code> o consumir flujos con eventos, pero evite mezclar estos dos. Usualmente cuando estás usando el método <code>pipe</code> no es necesario utilizar eventos, pero si necesita consumir los flujos de forma más personalizada, los eventos serían el camino a seguir.</p><h3 id="eventos-de-flujo">Eventos de flujo</h3><p>Además de leer de una fuente legible y escribir en un destino escribible, el método <code>pipe</code> gestiona automáticamente algunas cosas por el camino. Por ejemplo, gestiona los errores, el fin de los archivos y los casos en los que un flujo es más lento o más rápido que el otro.</p><p>Sin embargo, los flujos también se pueden consumir con eventos directamente. A continuación se muestra el código simplificado equivalente a un evento de lo que el método <code>pipe</code>hace principalmente para leer y escribir información:</p><pre><code class="language-js"># legible.pipe(escribible)

legible.on('data', (trozo) =&gt; {
  escribible.write(trozo);
});

legible.on('end', () =&gt; {
  escribible.end();
});</code></pre><p>He aquí una lista de los eventos y funciones importantes que pueden utilizarse con flujos legibles y escribibles:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/1*HGXpeiF5-hJrOk_8tT2jFA.png" class="kg-image" alt="1*HGXpeiF5-hJrOk_8tT2jFA" width="800" height="459" loading="lazy"><figcaption>Node.js avanzado</figcaption></figure><p>Los eventos y las funciones están relacionados de algún modo porque suelen utilizarse juntos.</p><p>Los eventos más importantes en un flujo legible son:</p><ul><li>El evento <code>data</code>, que se emite cada vez que el flujo pasa un trozo de datos al consumidor.</li><li>El evento <code>end</code>, que se emite cuando no hay más datos que consumir del flujo.</li></ul><p>Los eventos más importantes en un flujo escribible son:</p><ul><li>El evento <code>drain</code>, que es una señal de que el flujo escribible puede recibir más datos.</li><li>El evento <code>finish</code>, que se emite cuando todos los datos se han vaciado en el sistema subyacente.</li></ul><p>Los eventos y las funciones pueden combinarse para hacer un uso personalizado y optimizado de los flujos. Para consumir un flujo legible, podemos utilizar los métodos <code>pipe</code>/<code>unpipe</code>, o los métodos <code>read</code>/<code>unshift</code>/<code>resume</code>. Para consumir un flujo escribible, podemos convertirlo en el destino de <code>pipe</code>/<code>unpipe</code>, o simplemente escribir en él con la función <code>write</code> y llame al método <code>end</code> cuando hayamos terminado.</p><h4 id="modos-de-pausa-y-fluyente-en-flujos-legibles">Modos de pausa y fluyente en flujos legibles</h4><p>Los flujos legibles tienen dos modos principales que afectan a la forma en que podemos consumirlos:</p><ul><li>Puede estar en modo <strong>pausa</strong>.</li><li>O en <strong>modo fluido</strong>.</li></ul><p>Estos modos se denominan a veces "pull" y "push".</p><p>Todos los flujos legibles se inician por defecto en el modo pausado, pero pueden cambiarse fácilmente a fluido y de nuevo a pausado cuando sea necesario. A veces, el cambio se produce automáticamente.</p><p>Cuando un flujo legible está en modo de pausa, podemos utilizar la función <code>read()</code>para leer del flujo bajo demanda, sin embargo, para un flujo legible en el modo de flujo, los datos fluyen continuamente y tenemos que escuchar los eventos para consumirlos.</p><p>En el modo de flujo, los datos pueden perderse si no hay consumidores disponibles para manejarlos. Esta es la razón por la que, cuando tenemos un flujo legible en modo de flujo, necesitamos un manejador de eventos para la <code>data</code>. De hecho, solo añadiendo un manejador de eventos para la <code>data</code> cambia un flujo en pausa al modo de flujo y eliminar el manejador vuelve a poner el flujo en modo pausa. Parte de esto se hace por compatibilidad con la antigua interfaz de flujos de Node.</p><p>Para cambiar manualmente entre estos dos modos de flujo, puede utilizar la función <code>resume()</code> y <code>pause()</code>.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/1*HI-mtispQ13qm8ib5yey3g.png" class="kg-image" alt="1*HI-mtispQ13qm8ib5yey3g" width="800" height="445" loading="lazy"><figcaption>Node.js avanzado</figcaption></figure><p>Al consumir flujos legibles mediante la función <code>pipe</code>, no tenemos que preocuparnos de estos modos ya que <code>pipe</code> los gestiona automáticamente.</p><h3 id="implementando-flujos"><strong><strong>Implemen</strong>tando flujos</strong></h3><p>Cuando hablamos de streams en Node.js, hay dos tareas principales diferentes:</p><ul><li>La tarea de <strong>implantar</strong> los flujos.</li><li>La tarea de <strong>consumirlos</strong>.</li></ul><p>Hasta ahora sólo hemos hablado de consumir flujos. ¡Pongamos algunos en práctica!</p><p>Los ejecutores de los flujos suelen ser los que <code>requiere</code> el módulo <code>stream</code>.</p><h4 id="implementando-un-flujo-escribible"><strong><strong>Implement</strong>ando un flujo escribible</strong></h4><p>Para implementar un flujo con capacidad de escritura, necesitamos utilizar la función <code>Writable</code> del módulo de flujo.</p><pre><code>const { Escribible } = require('flujo');</code></pre><p>Podemos implementar un flujo escribible de muchas maneras. Podemos, por ejemplo, extender el constructor <code>Writable</code> si queremos:</p><pre><code class="language-js">class miFlujoEscribible extends Escribible {
}</code></pre><p>Sin embargo, prefiero el enfoque más simple del constructor. Simplemente creamos un objeto a partir del constructor <code>Writable</code> y pasarle una serie de opciones. La única opción obligatoria es la función <code>write</code> que expone el trozo de datos que se va a escribir.</p><pre><code class="language-js">const { Escribible } = require('flujo');

const outStream = new Escribible({
  write(trozo, codificacion, callback) {
    console.log(trozo.toString());
    callback();
  }
});

process.stdin.pipe(outStream);</code></pre><p>This write method takes three arguments.</p><ul><li>El trozo suele ser un <em>buffer </em>a no ser que configuremos el flujo de otra manera.</li><li>El argumento de codificación es necesario en ese caso, pero normalmente podemos ignorarlo.</li><li>El callback es una función que necesitamos llamar después de que hayamos terminado de procesar el trozo de datos. Es lo que señala si la escritura fue exitosa o no. Para señalar un fallo, llame a la devolución de llamada con un objeto de error.</li></ul><p>En <code>outStream</code>, nosotros simplemente imprimimos con la función <code>console.log</code> el trozo como una cadena y llamar a la devolución de llamada después de que sin un error para indicar el éxito. Este es un flujo de eco muy simple y probablemente no tan útil. Se hará eco de todo lo que reciba.</p><p>Para consumir este flujo, podemos utilizarlo simplemente con <code>process.stdin</code>, que es un flujo legible, por lo que podemos simplemente canalizar <code>process.stdin</code> hacia nuestro <code>outStream</code>.</p><p>Cuando ejecutamos el código anterior, cualquier cosa que escribamos en <code>process.stdin</code> se devolverá utilizando el método <code>outStream</code> <code>console.log</code>.</p><p>No es un flujo muy útil de implementar porque en realidad ya está implementado e incorporado. Esto es muy equivalente a <code>process.stdout</code>. Podemos canalizar <code>stdin</code> hacia <code>stdout</code> y obtendremos exactamente la misma función de eco con esta única línea:</p><pre><code class="language-js">process.stdin.pipe(process.stdout);</code></pre><h3 id="implementa-un-flujo-legible">Implementa un flujo legible</h3><p>Para implementar un flujo legible, necesitamos la interfaz <code>Readable</code>, y construir un objeto a partir de él, e implementar un método <code>read()</code> en el parámetro de configuración del flujo:</p><pre><code class="language-js">const { Legible } = require('flujo');

const enFlujo = new Legible({
  read() {}
});</code></pre><p>Hay una forma sencilla de implementar flujos legibles. Podemos utilizar directamente <strong><code>push</code> </strong>para insertar los datos que queremos que consuman los consumidores.</p><pre><code class="language-js">const { Legible } = require('flujo'); 

const enFlujo = new Legible({
  read() {}
});

enFlujo.push('ABCDEFGHIJKLM');
enFlujo.push('NOPQRSTUVWXYZ');

enFlujo.push(null); // No más datos

enFlujo.pipe(process.stdout);</code></pre><p>Cuando usamos <code>push</code> en un objeto <code>null</code>, que significa que queremos señalar que el flujo no tiene más datos.</p><p>Para consumir este simple flujo de lectura, podemos simplemente canalizarlo en el flujo de escritura <code>process.stdout</code>.</p><p>Cuando ejecutemos el código anterior, estaremos leyendo todos los datos de <code>enFlujo</code> y enviarlo a la salida estándar. Muy sencillo, pero también poco eficiente.</p><p>Básicamente estamos empujando todos los datos en el flujo antes de canalizarlos a <code>process.stdout</code>. La mejor manera de hacerlo es enviar los datos a petición del consumidor. Podemos hacerlo implementando la función <code>read()</code>en el objeto de configuración:</p><pre><code class="language-js">const enFlujo = new Legible({
  read(tamaño) {
    // hay una demanda de datos... alguien desea leerlos.
  }
});</code></pre><p>Cuando se llama al método de lectura en un flujo legible, la implementación puede enviar datos parciales a la cola. Por ejemplo, podemos empujar una letra a la vez, comenzando con el código de carácter 65 (que representa A), y el aumento que en cada empuje:</p><pre><code class="language-js">const enFlujo = new Legible({
  read(tamaño) {
    this.push(String.fromCharCode(this.currentCharCode++));
    if (this.currentCharCode &gt; 90) {
      this.push(null);
    }
  }
});

enFlujo.currentCharCode = 65;

enFlujo.pipe(process.stdout);</code></pre><p>Mientras el consumidor está leyendo un flujo legible, el método <code>read</code> continuará disparándose, y empujaremos más letras. Tenemos que detener este ciclo en algún lugar, y es por eso que una sentencia if para empujar <em>null </em>cuando el currentCharCode (código de carácter actual) es mayor que 90 (que representa Z).</p><p>Este código es equivalente al más simple con el que empezamos, pero ahora estamos empujando los datos bajo demanda cuando el consumidor lo pide. Usted siempre debe hacer eso.</p><h4 id="implementando-flujos-d-plex-transformaci-n"><strong><strong>Implement</strong>ando flujos Dúplex/Transformación</strong></h4><p>Con los flujos dúplex, podemos implementar tanto flujos de lectura como de escritura con el mismo objeto. Es como si heredáramos de ambas interfaces.</p><p>A continuación se muestra un ejemplo de flujo dúplex que combina los dos ejemplos de escritura y lectura implementados anteriormente:</p><pre><code class="language-js">const { Duplex } = require('flujo');

const inoutStream = new Duplex({
  write(trozo, codificacion, callback) {
    console.log(trozo.toString());
    callback();
  },

  read(tamaño) {
    this.push(String.fromCharCode(this.currentCharCode++));
    if (this.currentCharCode &gt; 90) {
      this.push(null);
    }
  }
});

inoutStream.currentCharCode = 65;

process.stdin.pipe(inoutStream).pipe(process.stdout);</code></pre><p>Combinando los métodos, podemos utilizar este flujo dúplex para leer las letras de la A a la Z y también podemos utilizarlo por su función de eco. Canalizamos el flujo legible <code>stdin</code> en este flujo dúplex para utilizar la función de eco y canalizamos el propio flujo dúplex en el archivo escribible <code>stdout</code> para ver las letras de la A a la Z.</p><p>Es importante entender que los lados legible y grabable de un flujo dúplex funcionan de forma completamente independiente el uno del otro. Se trata simplemente de una agrupación de dos características en un objeto.</p><p>Un flujo de transformación es el flujo dúplex más interesante porque su salida se calcula a partir de su entrada.</p><p>Para un flujo de transformación, no tenemos que implementar la función <code>read</code> o <code>write</code>, sólo necesitamos implementar un método <code>transform</code>, que combina ambos. Tiene la firma del método <code>write</code> y podemos utilizarlo para insertar con <code>push</code> los datos también.</p><p>Aquí tienes un simple flujo de transformación que devuelve cualquier cosa que escribas en él después de transformarla a formato de mayúsculas:</p><pre><code class="language-js">const { Transform } = require('flujo');

const aMayuscula = new Transform({
  transform(trozo, codificacion, callback) {
    this.push(trozo.toString().toUpperCase());
    callback();
  }
});

process.stdin.pipe(aMayuscula).pipe(process.stdout);</code></pre><p>En este flujo de transformación, que estamos consumiendo exactamente igual que en el ejemplo anterior de flujo dúplex, sólo implementamos el método <code>transform()</code>. En ese método, convertimos el <code>trozo</code> en su versión en mayúsculas y, a continuación, se usa el método <code>push</code> en esa versión como la parte legible.</p><h4 id="modo-de-flujos-como-objeto">Modo de flujos como objeto</h4><p>Por defecto, los flujos esperan valores <em>Buffer</em>/<em>String</em>. Hay un marcador <code>objectMode</code> que podemos configurar para que el flujo acepte cualquier objeto JavaScript.</p><p>He aquí un ejemplo sencillo para demostrarlo. La siguiente combinación de flujos de transformación permite mapear una cadena de valores separados por comas en un objeto JavaScript. Así <code>“a,b,c,d”</code> se cionvierte a <code>{a: b, c: d}</code>.</p><pre><code class="language-js">const { Transform } = require('flujo');

const separadorDeComa = new Transform({
  modoDeLecturaObjeto: true,
  
  transform(trozo, codificacion, callback) {
    this.push(trozo.toString().trim().split(','));
    callback();
  }
});

const arrayAObjeto = new Transform({
  modoDeLecturaObjeto: true,
  modoDeEscrituraObjeto: true,
  
  transform(trozo, codificacion, callback) {
    const objeto = {};
    for(let i=0; i &lt; trozo.length; i+=2) {
      objeto[trozo[i]] = trozo[i+1];
    }
    this.push(objeto);
    callback();
  }
});

const objetoAString = new Transform({
  modoDeEscrituraObjeto: true,
  
  transform(trozo, codificacion, callback) {
    this.push(JSON.stringify(trozo) + '\n');
    callback();
  }
});

process.stdin
  .pipe(separadorDeComa)
  .pipe(arrayAObjeto)
  .pipe(objetoAString)
  .pipe(process.stdout)</code></pre><p>Pasamos la cadena de entrada (por ejemplo, <code>“a,b,c,d”</code>) a través de <code>separadorDeComa</code> que empuja un array como sus datos legibles (<code>[“a”, “b”, “c”, “d”]</code>). Añadir el marcador <code>modoDeEscrituraObjeto</code> en ese flujo es necesario porque estamos empujando un objeto allí, no una cadena.</p><p>A continuación, tomamos la matriz y la introducimos en el archivo <code>arrayAObjeto</code>. Necesitamos un marcador <code>modoDeEscrituraObjeto</code>para hacer que ese flujo acepte un objeto. También empujará un objeto (el array de entrada mapeado en un objeto) y por eso también necesitábamos el marcador <code>modoDeLecturaObjeto</code> ahí también. El último flujo <code>objetoAString</code> acepta un objeto pero expulsa una cadena, y por eso sólo necesitábamos un botón <code>modoDeEscrituraObjeto</code> ahí. La parte legible es una cadena normal (el objeto que se convirtió a <em>string</em>).</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/1*u2kQzUD0ruPpt-xx0UOHoA.png" class="kg-image" alt="1*u2kQzUD0ruPpt-xx0UOHoA" width="482" height="210" loading="lazy"><figcaption>Uso del ejemplo anterior</figcaption></figure><h4 id="los-flujos-de-transformaci-n-incorporados-en-node-js">Los flujos de transformación incorporados en Node.js</h4><p>Node tiene algunos flujos de transformación incorporados muy útiles. A saber, los flujos "zlib" y "crypto".</p><p>He aquí un ejemplo que utiliza la función <code>zlib.createGzip()</code> combinados con los flujos <code>fs</code> que se pueden leer y escribir para crear un código para comprimir archivos:</p><pre><code class="language-js">const fs = require('fs');
const zlib = require('zlib');
const archivo = process.argv[2];

fs.crearFlujoDeLectura(archivo)
  .pipe(zlib.crearGzip())
  .pipe(fs.crearFlujoDeEscritura(archivo + '.gz'));</code></pre><p>Puedes usar este <em>script </em>para comprimir cualquier archivo que pases como argumento. Estamos canalizando un flujo legible para ese archivo en el flujo de transformación incorporado en "zlib" y luego en un flujo de escritura para el nuevo archivo comprimido. Simple.</p><p>Lo bueno de usar tuberías es que podemos combinarlas con eventos si lo necesitamos. Digamos, por ejemplo, que quiero que el usuario vea un indicador de progreso mientras el script está trabajando y un mensaje de "Hecho" cuando el script haya terminado. Ya que el método <code>pipe</code> devuelve el flujo de destino, podemos encadenar también el registro de manejadores de eventos:</p><pre><code class="language-js">const fs = require('fs');
const zlib = require('zlib');
const archivo = process.argv[2];

fs.crearFlujoDeLectura(archivo)
  .pipe(zlib.crearGzip())
  .on('data', () =&gt; process.stdout.write('.'))
  .pipe(fs.crearFlujoDeEscritura(archivo + '.zz'))
  .on('finish', () =&gt; console.log('Hecho'));</code></pre><p>Así que con el método <code>pipe</code>, conseguimos consumir flujos fácilmente, pero aún podemos personalizar más nuestra interacción con esos flujos utilizando eventos cuando sea necesario.</p><p>Lo que es genial del método <code>pipe</code> es que podemos utilizarlo para componer nuestro programa pieza a pieza, de una forma mucho más legible. Por ejemplo, en lugar de escuchar el evento <code>data</code> más arriba, podemos simplemente crear un flujo de transformación para informar del progreso, y reemplazar el método <code>.on()</code> &nbsp;con otra invocación del método <code>.pipe()</code>:</p><pre><code class="language-js">const fs = require('fs');
const zlib = require('zlib');
const archivo = process.argv[2];

const { Transform } = require('flujo');

const reportarProgreso = new Transform({
  transform(trozo, encoding, callback) {
    process.stdout.write('.');
    callback(null, trozo);
  }
});

fs.crearFlujoDeLectura(archivo)
  .pipe(zlib.crearGzip())
  .pipe(reportarProgreso)
  .pipe(fs.crearFlujoDeLectura(archivo + '.zz'))
  .on('finish', () =&gt; console.log('Hecho'));</code></pre><p>El flujo <code>reportProgress</code> es un simple flujo de paso, pero también informa del progreso a la salida estándar. Fíjate en cómo he utilizado el segundo argumento en el método <code>callback()</code> para empujar los datos dentro del método <code>transform()</code>. Esto equivale a empujar primero los datos.</p><p>Las aplicaciones de combinar flujos son infinitas. Por ejemplo, si necesitamos encriptar el archivo antes o después de gziparlo, todo lo que tenemos que hacer es canalizar otro flujo de transformación en ese orden exacto que necesitábamos. Podemos utilizar el módulo <code>crypto</code> de Node para eso:</p><pre><code class="language-js">const crypto = require('crypto');
// ...

fs.crearFluejoDeLectura(archivo)
  .pipe(zlib.crearGzip())
  .pipe(crypto.crearCipher('aes192', 'a_secret'))
  .pipe(reportarProgreso)
  .pipe(fs.crearFlujoDeEscritura(archivo + '.zz'))
  .on('finish', () =&gt; console.log('Hecho'));</code></pre><p>El <em>script </em>anterior comprime y luego encripta el archivo pasado y sólo aquellos que tienen el secreto pueden utilizar el archivo de salida. No podemos descomprimir este archivo con las utilidades normales de descompresión porque está cifrado.</p><p>Para poder descomprimir cualquier cosa comprimida con el <em>script </em>anterior, necesitamos utilizar los flujos opuestos para "crypto" y "zlib" en orden inverso, lo cual es sencillo:</p><pre><code class="language-js">fs.crearFlujoDeLectura(archivo)
  .pipe(crypto.crearDecifrador('aes192', 'a_secret'))
  .pipe(zlib.crearGunzip())
  .pipe(reportarProgreso)
  .pipe(fs.crearFlujoDeLectura(archivo.slice(0, -3)))
  .on('finish', () =&gt; console.log('Hecho'));</code></pre><p>Asumiendo que el archivo pasado es la versión comprimida, el código anterior creará un flujo de lectura a partir de él, lo canalizará en el flujo de "crypto" <code>createDecipher()</code> (utilizando el mismo secreto), canalice la salida de éste archivo en el flujo "fzlib" <code>createGunzip()</code>, y luego escribir las cosas de nuevo a un archivo sin la parte de la extensión.</p><p>Eso es todo lo que tengo para este tema. Gracias por leernos. Hasta la próxima.</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Cómo Construir una Aplicación de Chat en Tiempo Real en Node.js Usando Express, Mongoose y Socket.io ]]>
                </title>
                <description>
                    <![CDATA[ En este tutorial, utilizaremos la plataforma Node.js para crear una aplicación de chat en tiempo real que envíe y muestre mensajes a un destinatario al instante sin actualizar la página. Usaremos el framework de JavaScript Express.js y las bibliotecas Mongoose y Socket.io para lograr esto. Antes de comenzar, echemos un ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/como-construir-una-aplicacion-de-chat-en-tiempo-real-en-node-js-usando-express-mongoose-and-socket-io/</link>
                <guid isPermaLink="false">63ca76c9700708073437b56d</guid>
                
                    <category>
                        <![CDATA[ Node.js ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Vanessa Pineiro Morales ]]>
                </dc:creator>
                <pubDate>Tue, 24 Jan 2023 02:46:39 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2023/01/1-c4mV8Ppc8oe42XVQHfsjQw.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artículo original:</strong> <a href="https://www.freecodecamp.org/news/simple-chat-application-in-node-js-using-express-mongoose-and-socket-io-ee62d94f5804/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">How to build a real time chat application in Node.js using Express, Mongoose and Socket.io</a>
      </p><p>En este tutorial, utilizaremos la plataforma Node.js para crear una <strong>aplicación de chat en tiempo real</strong> que envíe y muestre mensajes a un destinatario al instante sin actualizar la página. Usaremos el framework de JavaScript Express.js y las bibliotecas Mongoose y Socket.io para lograr esto.</p><p>Antes de comenzar, echemos un vistazo rápido a los conceptos básicos de Node.js</p><h3 id="node-js"><strong><strong><strong>Node.js</strong></strong></strong></h3><p><a href="https://es.wikipedia.org/wiki/Node.js">Node.js</a> es un entorno de tiempo de ejecución de JavaScript, de código abierto y multiplataforma que ejecuta código JavaScript fuera del navegador. La ventaja más importante de usar Node es que podemos usar JavaScript como lenguaje tanto de front-end como de back-end.</p><p>Como sabemos, JavaScript se usó principalmente para secuencias de comandos del lado del cliente, en las que las secuencias de comandos se incrustaron en el HTML de una página web y se ejecutaron en el lado del cliente mediante un motor de JavaScript en el navegador web del usuario.</p><p>Node.js permite a los desarrolladores usar JavaScript para escribir herramientas de línea de comandos y para secuencias de comandos del lado del servidor —ejecutando secuencias de comandos del lado del servidor para producir contenido de página web dinámico antes de que la página se envíe al navegador web del usuario.</p><p>Para instalar node:</p><p><a href="https://nodejs.org/es/download/">https://nodejs.org/es/download</a>/</p><p>Aunque el node tiene un solo subproceso, aún es más rápido usar funciones asíncronas. Por ejemplo, Node puede procesar otras cosas mientras se lee un archivo del disco o mientras se espera que se complete una solicitud HTTP. El comportamiento asincrónico se puede implementar mediante devoluciones de callback. Además, JavaScript funciona bien con bases de datos JSON y No-SQL.</p><h3 id="m-dulos-npm"><strong>Módulos NPM</strong></h3><p>Nodejs permite incluir en la aplicación los módulos de las librerías. Estos módulos pueden ser módulos definidos por el usuario o de terceros.</p><p>Los módulos de terceros se pueden instalar con el siguiente comando:</p><pre><code class="language-bash">npm install nombre_del_módulo</code></pre><p>y los módulos instalados se pueden usar usando la función <strong>require()</strong>:</p><pre><code class="language-js">var módulo = require(‘nombre_del_módulo’)</code></pre><p>En las aplicaciones de Node, usaremos un archivo package.json para mantener las versiones del módulo. Este archivo se puede crear con este comando:</p><pre><code class="language-bash">npm init</code></pre><p>y los paquetes deben instalarse de la siguiente manera:</p><pre><code class="language-bash">npm install -s nombre_del_módulo</code></pre><p>Hay muchos frameworks que se pueden agregar como módulos a nuestra aplicación Node. Estos se explicarán más adelante según sea necesario.</p><h3 id="aplicaci-n-de-chat-simple"><strong>Aplicación de Chat Simple</strong></h3><p>La aplicación debe permitir que varios usuarios chateen juntos. Los mensajes deben actualizarse sin refrescar la página. Para simplificar, evitaremos la parte de autenticación.</p><p>Podemos empezar por crear un nuevo directorio de proyecto y pasar a él. Luego podemos iniciar nuestro proyecto con el siguiente comando:</p><pre><code class="language-bash">npm init</code></pre><p>Esto nos pedirá que ingresemos detalles sobre nuestro proyecto.</p><p>Después de esto, se creará un archivo <strong>package.json</strong>:</p><pre><code class="language-json">{
 “name”: “test”,
 “version”: “1.0.0”,
 “description”: “”,
 “main”: “index.js”,
 “scripts”: {
 “test”: “echo \”Error: no test specified\” &amp;&amp; exit 1"
 },
 “author”: “”,
 “license”: “ISC”
}</code></pre><p>Nuestro directorio de aplicaciones ya está configurado.</p><p>Lo primero que necesitamos crear es un servidor. Para crear eso, utilizaremos un framework llamado<strong> Express</strong>.</p><h4 id="express-js"><strong><strong><strong>Express.js</strong></strong></strong></h4><p>Express.js, o simplemente Express, es un framework de aplicación web para Node.js. <a href="https://expressjs.com/es/">Express ofrece </a><a href="https://expressjs.com/es/">un sólido conjunto de características para aplicaciones web y móviles</a>. Express ofrece una capa delgada de características fundamentales de aplicaciones web, sin encubrir las características de Node.js.</p><p>Instalaremos Express.js usando el siguiente comando:</p><pre><code class="language-bash">npm install -s express</code></pre><p>Dentro del archivo package.json se agregará una nueva línea:</p><pre><code class="language-json">dependencies”: {
 “express”: “⁴.16.3”
 }</code></pre><p>A continuación, crearemos un archivo<strong> server.js</strong>.</p><p>En este archivo necesitamos requerir Express y crear una referencia a una variable desde una instancia de Express. Los contenidos estáticos como HTML, CSS o JavaScript se pueden servir usando express.js:</p><pre><code class="language-js">var express = require(‘express’);

var app = express();</code></pre><p>y podemos comenzar a escuchar un puerto usando el código:</p><pre><code class="language-js">var servidor = app.listen(3000, () =&gt; {
 console.log(‘el servidor se está ejecutando en el puerto’, servidor.address().port);
});</code></pre><p>Ahora necesitamos crear un archivo HTML index.html que muestre nuestra interfaz de usuario. He agregado bootstrap y JQuery cdn.</p><pre><code class="language-html">//index.html

&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
 &lt;! — incluir bootstrap y jquery cdn →
&lt;/head&gt;
&lt;body&gt;
&lt;div class=”container”&gt;
 &lt;br&gt;
 &lt;div class=”jumbotron”&gt;
 &lt;h1 class=”display-4"&gt;Enviar mensaje&lt;/h1&gt;
 &lt;br&gt;
 &lt;input id = “nombre” class=”form-control” placeholder=”Nombre”&gt;
 &lt;br&gt;
 &lt;textarea id = “mensaje” class=”form-control” placeholder=”Su mensaje aquí”&gt;
&lt;/textarea&gt;
 &lt;br&gt;
 &lt;button id=”enviar” class=”btn btn-success”&gt;Enviar&lt;/button&gt;
 &lt;/div&gt;
 &lt;div id=”mensajes”&gt;
 
&lt;/div&gt;
&lt;/div&gt;
&lt;script&gt;

&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre><p>Tenga en cuenta que la etiqueta vacía <em><em>&lt;script&gt; &lt;</em></em>;/script&gt; será el lugar en el que escribiremos el código JavaScript del lado del cliente.</p><p>Para decirle a Express eso, usaremos un archivo estático. Agregaremos una nueva línea dentro de <strong>server.js</strong>:</p><pre><code class="language-js">app.use(express.static(__dirname));</code></pre><p>Nosotros podemos ejecutar el server.js usando el comando:</p><pre><code class="language-bash">node ./server.js</code></pre><p>O un paquete llamado <strong>nodemon</strong>, para que los cambios realizados en el código sean detectados automáticamente. Descargaremos nodemon usando el comando:</p><pre><code class="language-bash">npm install -g nodemon</code></pre><p>-g — global, para que sea accesible en todos los proyectos.</p><p>Ejecutaremos el código usando el comando:</p><pre><code class="language-bash">nodemon ./server.js</code></pre><p>Si vas a localhost:3000 podemos ver el archivo de index:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/caxmtV7tYzJ1EUU69TeX4YQVsC69EhgzcSL5" class="kg-image" alt="caxmtV7tYzJ1EUU69TeX4YQVsC69EhgzcSL5" width="800" height="500" loading="lazy"><figcaption>index.html</figcaption></figure><p>Ahora que nuestro servidor está funcionando, necesitamos crear nuestra base de datos. Para esta aplicación, tendremos una base de datos No-SQL y usaremos <strong>Mongodb</strong>. Estoy configurando mi mongodb en <strong><a href="https://www.mongodb.com/es/atlas/database">mongodb.com</a></strong>. Nuestra base de datos contendrá una única colección llamada <strong>mensajes</strong> con los campos <strong>nombre</strong> y <strong>mensaje</strong>.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/espanol/news/content/images/2023/01/Screenshot-2023-01-23-at-10.02.55-PM.png" class="kg-image" alt="UWJYcDmpxrFhUoKRCrgkhtaTcBD4z4NivreC" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2023/01/Screenshot-2023-01-23-at-10.02.55-PM.png 600w, https://www.freecodecamp.org/espanol/news/content/images/size/w1000/2023/01/Screenshot-2023-01-23-at-10.02.55-PM.png 1000w, https://www.freecodecamp.org/espanol/news/content/images/size/w1600/2023/01/Screenshot-2023-01-23-at-10.02.55-PM.png 1600w, https://www.freecodecamp.org/espanol/news/content/images/2023/01/Screenshot-2023-01-23-at-10.02.55-PM.png 1676w" sizes="(min-width: 720px) 720px" width="1676" height="1122" loading="lazy"></figure><p>Para conectar esta base de datos a la aplicación, usaremos otro paquete llamado <strong>Mongoose</strong>.</p><h4 id="mongoose"><strong><strong><strong>Mongoose</strong></strong></strong></h4><p>Mongoose es una herramienta de modelado de objetos MongoDB diseñada para trabajar en un entorno asíncrono. Mongoose se puede instalar usando el comando:</p><pre><code class="language-bash">npm install -s mongoose</code></pre><p>Dentro de <strong>server.js</strong> necesitaremos mongoose:</p><pre><code class="language-js">var mongoose = require(‘mongoose’);</code></pre><p>Y le asignaremos una variable, la URL de nuestra base de datos mongodb:</p><pre><code class="language-js">var dbUrl = ‘mongodb://username:pass@ds257981.mlab.com:57981/simple-chat’</code></pre><p>Mongoose se conectará a la base de datos mongodb con el método de conexión:</p><pre><code class="language-js">mongoose.connect(dbUrl , (err) =&gt; { 
   console.log(‘Mongodb conectado’,err);
})</code></pre><p>Y definiremos nuestro modelo de mensaje como:</p><pre><code class="language-js">var Mensaje = mongoose.model(‘Mensaje’,{ nombre : String, mensaje: String})</code></pre><p>Podemos implementar la lógica de chat ahora. Pero antes de eso, hay un paquete más que debe agregarse.</p><h4 id="body-parser"><strong><strong><strong>Body-Parser</strong></strong></strong></h4><p>Body-Parser extrae la parte del cuerpo completo de una secuencia de solicitud entrante y la expone en req.body. El middleware formaba parte de Express.js anteriormente, pero ahora debe instalarlo por separado.</p><p>Instálalo usando el siguiente comando:</p><pre><code class="language-bash">npm install -s body-parser</code></pre><p>Agregue los siguientes códigos a <strong>server.js</strong>:</p><pre><code class="language-js">var bodyParser = require(‘body-parser’)
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}))</code></pre><h3 id="enrutamiento"><strong>Enrutamiento</strong></h3><p>El enrutamiento se refiere a cómo los puntos finales de una aplicación (URIs) responden a las solicitudes de los clientes. Usted define el enrutamiento usando métodos del objeto de aplicación Express que corresponden a métodos HTTP: app.get() para manejar solicitudes GET y app.post() para manejar solicitudes POST.</p><p>Estos métodos de enrutamiento especifican <a href="https://expressjs.com/es/guide/routing.html">una función de callback</a> (a veces denominada "funciones de controlador") que se activa cuando la aplicación recibe una solicitud para la ruta (punto final) y el método HTTP especificados. En otras palabras, la aplicación "escucha" las solicitudes que coinciden con las rutas y los métodos especificados, y cuando detecta una coincidencia, llama a la función de callback especificada.</p><p>Ahora necesitamos crear dos rutas a los mensajes para que nuestro chat funcione.</p><p>Dentro de <strong>server.js</strong>:</p><p><strong>get</strong>: obtendrá todos los mensajes de la base de datos</p><pre><code class="language-js">app.get('/mensajes', (req, res) =&gt; {
  Mensaje.find({},(err, mensajes)=&gt; {
    res.send(mensajes);
  })
})</code></pre><p><strong>post </strong>: publicará nuevos mensajes creados por el usuario en la base de datos</p><pre><code class="language-js">app.post('/mensajes', (req, res) =&gt; {
  var mensaje = new Mensaje(req.body);
  mensaje.save((err) =&gt;{
    if(err)
      sendStatus(500);
    res.sendStatus(200);
  })
})</code></pre><p>Para conectar estas rutas al front-end, debemos agregar el siguiente código en la etiqueta del script del lado del cliente en <strong>index.html</strong>:</p><pre><code class="language-js">$(() =&gt; {
    $("#enviar").click(()=&gt;{
       enviarMensaje({
          nombre: $("#nombre").val(), 
          mensaje:$("#mensaje").val()});
        })
      obtenerMensajes()
    })
    
function agregarMensajes(mensaje){
   $(“#mensajes”).append(`
      &lt;h4&gt; ${mensaje.nombre} &lt;/h4&gt;
      &lt;p&gt;  ${mensaje.mensaje} &lt;/p&gt;`)
   }
   
function obtenerMensajes(){
  $.get(‘http://localhost:3000/mensajes', (data) =&gt; {
   data.forEach(agregarMensajes);
   })
 }
 
function enviarMensaje(mensaje){
   $.post(‘http://localhost:3000/mensajes', mensaje)
 }</code></pre><p>Aquí, <strong>enviarMensaje</strong> se usa para invocar la ruta de publicación de los mensajes y guardar un mensaje enviado por el usuario. El mensaje se crea cuando un usuario hace clic en el botón enviar.</p><p>De manera similar, <strong>obtenerMensajes</strong> se usa para invocar la ruta de obtención de mensajes. Esto hará que todos los mensajes se guarden en la base de datos y se agregarán al div de mensajes.</p><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/m1tJ6aV53XnmvkU8PjY7u16wkI1gKrplYWHo" class="kg-image" alt="m1tJ6aV53XnmvkU8PjY7u16wkI1gKrplYWHo" width="800" height="500" loading="lazy"></figure><p>El único problema ahora es que no hay forma de que el cliente sepa si el servidor está actualizado. Entonces, cada vez que publicamos un mensaje, debemos actualizar la página para ver los nuevos mensajes.</p><p>Para solucionar esto podemos añadir un sistema de notificaciones push que enviará mensajes del servidor al cliente. En Node.js usamos <strong>socket.io</strong>.</p><h4 id="socket-io"><strong><strong><strong>Socket.io</strong></strong></strong></h4><p>Socket.IO es una biblioteca de JavaScript para aplicaciones web en tiempo real. Permite la comunicación bidireccional en tiempo real entre los clientes web y el servidor. Tiene dos partes: una biblioteca del lado del cliente que se ejecuta en el navegador y una biblioteca del lado del servidor para Node.js. Socket.io permite la comunicación bidireccional basada en eventos en tiempo real.</p><p>Para instalar socket.io:</p><pre><code class="language-bash">npm install -s socket.io</code></pre><p>también necesitamos un paquete HTTP para que funcione Socket.io:</p><pre><code class="language-bash">npm install -s http</code></pre><p>Agregue el siguiente código a <strong>server.js</strong>:</p><pre><code class="language-js">var http = require(‘http’).Server(app);
var io = require(‘socket.io’)(http);</code></pre><p>Y podemos crear una conexión:</p><pre><code class="language-js">io.on(‘connection’, () =&gt;{
 console.log(‘Un usuario esta conectado’)
})</code></pre><p>En el <strong>index.html</strong> agregue la siguiente etiqueta:</p><pre><code class="language-html">&lt;script src=”/socket.io/socket.io.js”&gt;&lt;/script&gt;</code></pre><p>Ahora necesitamos crear una acción de emisión cuando se crea un mensaje en <strong>server.js</strong>. Así que la ruta de publicación se convierte en esto:</p><pre><code class="language-js">app.post('/mensajes', (req, res) =&gt; {
  var mensaje = new Mensaje(req.body);
  mensaje.save((err) =&gt;{
    if(err)
      sendStatus(500);
    io.emit('mensaje', req.body);
    res.sendStatus(200);
  })
})</code></pre><p>Y en la etiqueta del script del lado del cliente en <strong>index.html</strong>, agregue el siguiente código:</p><pre><code class="language-html">var socket = io();

socket.on(‘mensaje’, agregarMensajes)</code></pre><p>Entonces, cada vez que se publica un mensaje, el servidor actualizará los mensajes en el div de mensajes.</p><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/6KUYtaL4L3ShtPNaHRKWXvP6v3mMuUAdq6R0" class="kg-image" alt="6KUYtaL4L3ShtPNaHRKWXvP6v3mMuUAdq6R0" width="800" height="499" loading="lazy"></figure><p>¡¡Gran!!</p><p>Esta es una aplicación muy básica que podemos crear en Node.js. Hay muchas posibilidades de mejora. El código terminado se puede encontrar en <a href="https://github.com/amkurian/simple-chat" rel="noopener">https://github.com/amkurian/simple-chat</a></p><p><strong><strong>server.js</strong></strong></p><pre><code class="language-js">var express = require('express');
var bodyParser = require('body-parser')
var app = express();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var mongoose = require('mongoose');

app.use(express.static(__dirname));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}))

var Mensaje = mongoose.model('Mensaje',{
  nombre : String,
  mensaje : String
})

var dbUrl = 'mongodb://username:password@ds257981.mlab.com:57981/simple-chat'

app.get('/mensajes', (req, res) =&gt; {
  Mensaje.find({},(err, mensajes)=&gt; {
    res.send(mensajes);
  })
})

app.get('/mensajes', (req, res) =&gt; {
  Mensaje.find({},(err, mensajes)=&gt; {
    res.send(mensajes);
  })
})

app.post('/mensajes', (req, res) =&gt; {
  var mensaje = new Mensaje(req.body);
  mensaje.save((err) =&gt;{
    if(err)
      sendStatus(500);
    io.emit('mensaje', req.body);
    res.sendStatus(200);
  })
})

io.on('connection', () =&gt;{
  console.log('Un usuario esta conectado')
})

mongoose.connect(dbUrl ,{useMongoClient : true} ,(err) =&gt; {
  console.log('Mongodb conectado',err);
})

var servidor = http.listen(3001, () =&gt; {
 console.log(‘el servidor se está ejecutando en el puerto’, servidor.address().port);
});</code></pre><p>Espero que esto haya sido útil para comprender algunos conceptos básicos.</p><p>Algunos enlaces útiles</p><p><a href="https://socket.io/" rel="noopener"><strong><strong>Socket.IO</strong></strong></a><br><a href="https://socket.io/" rel="noopener"><em><em>SOCKET.IO 2.0 IS HERE FEATURING THE FASTEST AND MOST RELIABLE REAL-TIME ENGINE ~/Projects/tweets/index.js var io =…</em></em>socket.io</a></p><p><strong><strong><a href="https://expressjs.com/es/">Express - Node.js web application framework</a></strong></strong><br><a href="https://expressjs.com/es/"><em><em>Express is a minimal and flexible Node.js web application framework that provides a robust set of features for web and…</em></em>expressjs.com</a></p><p><a href="http://mongoosejs.com/" rel="noopener">http://mongoosejs.com/</a></p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Aprende Node.js y Express - Curso desde cero ]]>
                </title>
                <description>
                    <![CDATA[ ¡Hola! Si quieres aprender Node.js y Express, estás en el lugar correcto. En este artículo encontrarás una breve introducción al desarrollo web back-end, Node.js y Express. Aprenderás por qué son herramientas muy poderosas para desarrollar servidores y por qué deberías aprenderlos si tu meta es adentrarte en el mundo del ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/aprende-node-js-y-express-curso-desde-cero/</link>
                <guid isPermaLink="false">62d1b64fb4def50851972da5</guid>
                
                    <category>
                        <![CDATA[ Node.js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Node ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Express ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Estefania Cassingena Navone ]]>
                </dc:creator>
                <pubDate>Sun, 07 Aug 2022 21:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2022/07/thumbnail.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>¡Hola! Si quieres aprender Node.js y Express, estás en el lugar correcto.</p><p>En este artículo encontrarás una breve introducción al desarrollo web back-end, Node.js y Express. Aprenderás por qué son herramientas muy poderosas para desarrollar servidores y por qué deberías aprenderlos si tu meta es adentrarte en el mundo del desarrollo web back-end. </p><p>Luego, encontrarás un <a href="https://www.youtube.com/watch?v=1hpc70_OoAg">curso de <strong>8.5</strong> <strong>horas </strong>de Node.js y Express</a> en el canal de YouTube de freeCodeCamp en español donde puedes aprender los fundamentos en español y construir un proyecto paso a paso. </p><p>¡Comencemos! ✨</p><h2 id="-qu-es-el-desarrollo-web-back-end">🔸<strong> ¿Qué es el desarrollo web back-end? </strong></h2><p>El desarrollo web ha transformado nuestro mundo. Cada día accedemos a internet para encontrar información, aprender, comprar productos, compartir opiniones y comunicarnos con familiares y amigos. </p><p>Básicamente, nuestras vidas no serían lo mismo sin los sitios web. </p><p>¿Estás de acuerdo? 🙂</p><p>Si estás de acuerdo, entonces aprendiendo desarrollo web puedes desarrollarte en una carrera muy gratificante y puedes impactar las vidas de miles o millones de usuarios desarrollando aplicaciones web. </p><p>Hablemos sobre las distintas áreas del desarrollo web. </p><h3 id="desarrollo-web-front-end-vs-desarrollo-web-back-end">Desarrollo web front-end vs. desarrollo web back-end</h3><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/espanol/news/content/images/2022/07/image-7.png" class="kg-image" alt="image-7" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2022/07/image-7.png 600w, https://www.freecodecamp.org/espanol/news/content/images/size/w1000/2022/07/image-7.png 1000w, https://www.freecodecamp.org/espanol/news/content/images/size/w1600/2022/07/image-7.png 1600w, https://www.freecodecamp.org/espanol/news/content/images/2022/07/image-7.png 1920w" sizes="(min-width: 1200px) 1200px" width="600" height="400" loading="lazy"></figure><p>Los desarrolladores que crean estas aplicaciones web asombrosas son llamados <strong>desarrolladores web</strong>. Pueden especializarse para desarrollar partes específicas de una aplicación web:</p><ul><li>Los <strong>desarrolladores web front-end</strong> implementan la parte de la aplicación web con la cual los usuarios interactúan directamente. Crean la parte visible de las plataformas asombrosas que usamos cada día. En la analogía de la tienda que puedes ver en la imagen anterior, el front-end estaría representado por la parte de la tienda que los clientes pueden ver.</li><li>Los <strong>desarrolladores web back-end</strong> implementan toda la funcionalidad que los usuarios no ven, tales como los servidores, bases de datos y todas sus interacciones con el front-end de la aplicación. </li><li>Los <strong>desarrolladores web full-stack </strong>se encargan de ambas áreas. Tienen conocimiento extenso sobre desarrollo web front-end y back-end. </li></ul><p>Interesante, ¿cierto? ✨</p><p>Veamos más detalles sobre el desarrollo web back-end porque esta es una de las principales aplicaciones de Node.js y Express. </p><h3 id="el-modelo-cliente-servidor">El modelo cliente-servidor</h3><p>El internet está basado en el modelo o la arquitectura cliente-servidor, en la cual dos dispositivos (el cliente y el servidor) se comunican entre sí. </p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2022/07/image-173.png" class="kg-image" alt="image-173" width="600" height="400" loading="lazy"><figcaption>Diagrama del modelo cliente-servidor. Cliente (izquierda). Servidor (derecha).</figcaption></figure><h3 id="el-cliente">El cliente</h3><p>Cuando intentas acceder a una página web en tu navegador, el navegador (<strong>cliente</strong>) envía una solicitud HTTP al servidor. </p><h3 id="el-servidor">El servidor</h3><p>El <strong>servidor </strong>es un programa que escucha solicitudes y genera respuestas apropiadas. Estas respuestas incluyen:</p><ul><li>Enviar información al cliente. </li><li>Ejecutar tareas o procesos.</li><li>Trabajar con la información de una base de datos y/o actualizarla. </li></ul><p>Por ejemplo, podemos agregar un usuario nuevo a una base de datos al enviar una solicitud al servidor y el servidor debe realizar las actualizaciones correspondientes en la base de datos. </p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2022/07/image-175.png" class="kg-image" alt="image-175" width="600" height="400" loading="lazy"><figcaption>Cliente (izquierda) - Servidor (centro) - Base de datos (derecha)</figcaption></figure><p>Desarrollar y mantener servidores es una de las tareas principales de los desarrolladores back-end y esa es precisamente la función principal de <strong>Node.js y Express</strong>. </p><h2 id="-qu-es-node-js"><strong>🔹</strong> ¿Qué es Node.js? </h2><p><strong>Node.js</strong> es un runtime de JavaScript asíncrono y basado en eventos desarrollado en base al motor V8 de JavaScript de Chrome. Nos da todas las herramientas que necesitamos para ejecutar JavaScript en el terminal sin un navegador web (browser). </p><p>💡<strong> Dato:</strong> Antes de Node.js, no podíamos ejecutar programas de JavaScript sin un navegador web. Solo los navegadores habían sido diseñados para esta tarea ya que JavaScript es uno de los principales lenguajes de programación de la web. </p><p>Lo asombroso de Node.js es que nos permite construir aplicaciones escalables con alto rendimiento. </p><p>De acuerdo a su <a href="https://nodejs.org/es/about/">documentación oficial</a>:</p><blockquote>Los usuarios de Node.js están libres de preocuparse por el bloqueo del proceso, ya que no existe. Casi ninguna función en Node.js realiza I/O directamente, por lo que el proceso nunca se bloquea. Por ello, <strong>es muy propicio desarrollar sistemas escalables en Node.js.</strong></blockquote><p>🚩 Es importante resaltar que <strong>Node.js no es</strong> un: </p><ul><li>Lenguaje de programación.</li><li>Framework.</li><li>Librería (biblioteca).</li></ul><p>Es un <strong>runtime de JavaScript</strong> desarrollado para ejecutar código de JavaScript. </p><h3 id="-por-qu-deber-as-aprender-node-js"><strong>¿Por qué deberías aprender Node.js?</strong></h3><p>Ahora que ya sabes más sobre Node.js, veamos por qué deberías aprenderlo. </p><p><strong>Node.js </strong>es una de las tecnologías web más populares entre los desarrolladores, incluyendo principiantes que están aprendiendo a programar y profesionales. </p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2022/07/node-logo.png" class="kg-image" alt="node-logo" width="600" height="400" loading="lazy"><figcaption>Logo de Node.js</figcaption></figure><p>La popularidad de Node.js es asombrosa. De acuerdo a la encuesta <a href="https://survey.stackoverflow.co/2022/#most-popular-technologies-webframe">2022 Stack Overflow Developer Survey</a>, es una de las tecnologías web más populares usadas por los que están aprendiendo a programar y por desarrolladores profesionales.</p><p>Cuando a los encuestados se les preguntó cuáles frameworks web o tecnologías web habían usado constantemente el año pasado y con cuáles querían trabajar el próximo año, <strong>Node.js</strong> obtuvo un <strong>47.12%</strong> de los votos. </p><p>💡<strong> Dato:</strong> ¡casi la mitad de las 58,743 respuestas!</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2022/07/image-8.png" class="kg-image" alt="image-8" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2022/07/image-8.png 600w, https://www.freecodecamp.org/espanol/news/content/images/2022/07/image-8.png 922w" width="600" height="400" loading="lazy"><figcaption>Los resultados de la categoría de Web Frameworks and technologies de la encuesta <a href="https://survey.stackoverflow.co/2022/#most-popular-technologies-webframe">2022 Stack Overflow Developer Survey</a>. <strong>Node.js es el primero con 47.12% de las respuestas.</strong></figcaption></figure><p>Ese porcentaje fue incluso mayor entre los encuestados que estaban aprendiendo a programar: &nbsp;<strong>52.86%</strong>. Asombroso, ¿verdad? 😁</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2022/07/image-9.png" class="kg-image" alt="image-9" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2022/07/image-9.png 600w, https://www.freecodecamp.org/espanol/news/content/images/2022/07/image-9.png 919w" width="600" height="400" loading="lazy"><figcaption>Los resultados de la categoría de Web Frameworks and technologies de la encuesta <a href="https://survey.stackoverflow.co/2022/#most-popular-technologies-webframe">2022 Stack Overflow Developer Survey</a> cuando se selecciona Learning to Code. <strong>Node.js es el primero con 52.86% de las respuestas.</strong></figcaption></figure><p>Esto demuestra el impacto que Node.js está teniendo en el área del desarrollo web. Al aprender Node.js estarás invirtiendo tu tiempo y recursos sabiamente. Adquirirás habilidades valiosas y altamente demandadas en este campo. </p><h2 id="-qu-es-express"><strong>🔸</strong> ¿Qué es Express? </h2><p>Si tu meta es desarrollar servidores con Node.js, el proceso puede ser mucho más fácil si usas <strong>Express</strong>, un framework de aplicaciones web específicamente diseñado para Node.js. </p><p>Según la <a href="https://expressjs.com/">documentación oficial</a> de Express:</p><blockquote>Express es un framework de aplicaciones web de Node.js mínimo y flexible que provee un conjunto robusto de herramientas para aplicaciones web y móviles. </blockquote><p>Original en inglés:</p><blockquote>Express is a minimal and flexible Node.js web application framework that provides a robust set of features for web and mobile applications.</blockquote><p>💡<strong> Dato:</strong> Express incluye muchas herramientas que puedes usar para escribir código más conciso, fácil de leer y fácil de mantener. Confía en mi. Cuando comiences a trabajar con Express, nunca querrás dejarlo. </p><p>Express tiene muchos métodos HTTP útiles y middleware que puedes usar para crear APIs robustas (Application Programming Interfaces), las cuales son fundamentales para el desarrollo web back-end y full-stack. </p><p>En la encuesta <a href="https://survey.stackoverflow.co/2022/#most-popular-technologies-webframe">2022 Stack Overflow Developer Survey</a>, Express fue la cuarta tecnología o framework web más usado con <strong>22.99%</strong> de los votos:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2022/07/image-10.png" class="kg-image" alt="image-10" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2022/07/image-10.png 600w, https://www.freecodecamp.org/espanol/news/content/images/2022/07/image-10.png 938w" width="600" height="400" loading="lazy"><figcaption>Los resultados de la categoría Web Frameworks and technologies de la encuesta <a href="https://survey.stackoverflow.co/2022/#most-popular-technologies-webframe">2022 Stack Overflow Developer</a> Survey</figcaption></figure><p><strong>¡Genial! </strong>Ya sabes por qué deberías aprender Node.js y Express. Te prometo que de verdad merecerá tu tiempo y dedicación. ✨</p><h2 id="-contenido-del-curso">🔹<strong> Contenido del curso</strong></h2><p>Ahora veamos lo que aprenderás durante el curso.</p><p>💡<strong><strong> </strong>Dato<strong>:</strong></strong> para tomar el curso, debes tener conocimiento previo de <strong>JavaScript</strong>. Si necesitas repasar este lenguaje de programación en español, te recomiendo tomar el <a href="https://www.youtube.com/watch?v=ivdTnPl1ND0&amp;t=3s">curso de JavaScript</a> en el canal de YouTube de freeCodeCamp en español.</p><h3 id="introducci-n-a-node-js-y-conceptos-b-sicos">Introducción a Node.js y conceptos básicos</h3><ul><li>Introducción a Node.js</li><li>Conceptos básicos de desarrollo web back-end. </li><li>Aplicaciones de Node.js</li><li>APIs y para qué se usan. </li><li>Ventajas de Node.js.</li><li>Descargar e instalar Node.js.</li><li>Confirmar que Node.js fue instalado exitosamente. </li><li>Verificar tu versión de Node.js.</li><li>El REPL de Node.js.</li></ul><h3 id="tu-primer-proyecto-de-node-js-y-m-dulos">Tu primer proyecto de Node.js y módulos</h3><ul><li>¿Qué es un módulo? Conceptos y ventajas.</li><li>Exportar e importar módulos.</li><li>Exportar varios elementos de un módulo de JavaScript.</li><li>Ejecutar un archivo JavaScript con el comando <code>node</code>.</li><li>Módulos core de Node.js.</li><li>El módulo <code>console</code>.</li><li>El módulo <code>process</code>.</li><li>El módulo <code>os</code>.</li><li>El módulo <code>fs</code>.</li><li>El módulo <code>timers</code>.</li></ul><h3 id="introducci-n-a-npm-y-json">Introducción a npm y JSON</h3><ul><li>¿Qué es npm?</li><li>Conceptos básicos de npm.</li><li>Inicializar un paquete con <code>npm init</code>.</li><li>El archivo <code>package.json</code>.</li><li>Introducción al formato JSON.</li><li>Instalar y desinstalar paquetes con npm.</li><li>El archivo <code>package-lock.json</code>.</li></ul><h3 id="eventos-y-operaciones-as-ncronas">Eventos y operaciones asíncronas</h3><ul><li>¿Qué es un evento?</li><li>Eventos en Node.js.</li><li>Eventos y procesos síncronos y asíncronos. </li><li>Promesas y funciones callback en JavaScript. </li><li>Promesas, <code>.then()</code> y <code>.catch()</code>.</li><li>Funciones asíncronas con <code>async</code> y <code>await</code>.</li></ul><h3 id="servidores-con-node-js-y-el-protocolo-http">Servidores con Node.js y el protocolo HTTP</h3><ul><li>El modelo cliente-servidor.</li><li>Formato de solicitudes y respuestas HTTP.</li><li>Métodos o verbos HTTP: &nbsp;GET, POST, PUT, DELETE.</li><li>Códigos de estado HTTP.</li><li>El módulo <code>http</code> en Node.js.</li><li>Crear un servidor en Node.js.</li><li>Los objetos <code>req</code> y <code>res</code>.</li><li>Estructura de una URL. </li><li>Routing (Enrutamiento) en Node.js. </li></ul><h3 id="nodemon">Nodemon</h3><ul><li>¿Qué es Nodemon?</li><li>Cómo instalarlo globalmente.</li><li>Cómo usarlo para actualizar aplicaciones de Node.js automáticamente.</li><li>Conceptos importantes: CRUD, REST, API.</li></ul><h3 id="express">Express</h3><ul><li>Cómo instalar Express y cómo crear un proyecto.</li><li>Routing en Express.</li><li>Express y Nodemon. </li><li>Cómo manejar varias rutas.</li><li>Parámetros de URL y rutas dinámicas. </li><li>Middleware en Express. </li><li>Manejar solicitudes GET, POST, PUT y DELETE.</li><li>Parámetros query. </li><li>Routers en Express. </li></ul><h2 id="-proyecto-de-node-js-y-express">🔸<strong> Proyecto de Node.js y Express</strong></h2><p>Durante el curso aprenderás con ejemplos prácticos, así que aplicarás todo lo que aprendas paso a paso. </p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2022/08/image-3.png" class="kg-image" alt="image-3" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2022/08/image-3.png 600w, https://www.freecodecamp.org/espanol/news/content/images/size/w1000/2022/08/image-3.png 1000w, https://www.freecodecamp.org/espanol/news/content/images/size/w1600/2022/08/image-3.png 1600w, https://www.freecodecamp.org/espanol/news/content/images/2022/08/image-3.png 1920w" sizes="(min-width: 1200px) 1200px" width="600" height="400" loading="lazy"><figcaption>Proyecto que crearemos con Node.js y Express</figcaption></figure><p>Aprenderás cómo trabajar con promesas con un ejemplo de pizza 🍕, cómo trabajar con JavaScript asíncrono, y desarrollarás una API y un servidor básico con Node.js para enviar información sobre cursos de programación y matemáticas al cliente. </p><p>Luego, adaptarás este servidor para trabajar con Express. Aplicarás conceptos que has aprendido y aprenderás nuevos conceptos paso a paso para crear un servidor que manejará varias rutas, parámetros y distintos tipos de solicitudes HTTP.</p><h2 id="-curso-de-node-js-y-express-en-youtube"><strong>📌</strong> Curso de Node.js y Express en YouTube</h2><p>Genial. Ahora que ya sabes más sobre Node.js y Express y lo que aprenderás durante el curso, te invito a tomar el curso completo en español:</p><figure class="kg-card kg-embed-card" data-test-label="fitted">
        <div class="fluid-width-video-container">
          <div style="padding-top: 56.17977528089888%;" class="fluid-width-video-wrapper">
            <iframe width="356" height="200" src="https://www.youtube.com/embed/1hpc70_OoAg?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen="" title="Aprende Node.js y Express - Curso desde Cero" name="fitvid0"></iframe>
          </div>
        </div>
      </figure><p>✍️ Curso creado por Estefania Cassingena Navone (Twitter: <a href="https://twitter.com/EstefaniaCassN">@EstefaniaCassN</a>, YouTube: <a href="https://www.youtube.com/codingwithestefania">Coding with Estefania</a>).</p><p>Sinceramente espero que te guste el curso y que te ayude a tomar tus primeros pasos en el mundo de Node.js, Express y desarrollo web back-end. </p><p>También te invitamos a tomar nuestros cursos de programación en <strong>español</strong>:</p><figure class="kg-card kg-embed-card" data-test-label="fitted">
        <div class="fluid-width-video-container">
          <div style="padding-top: 56.17977528089888%;" class="fluid-width-video-wrapper">
            <iframe width="356" height="200" src="https://www.youtube.com/embed/XqFR2lqBYPs?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen="" title="Aprende HTML y CSS - Curso Desde Cero" name="fitvid1"></iframe>
          </div>
        </div>
      </figure><figure class="kg-card kg-embed-card" data-test-label="fitted">
        <div class="fluid-width-video-container">
          <div style="padding-top: 56.17977528089888%;" class="fluid-width-video-wrapper">
            <iframe width="356" height="200" src="https://www.youtube.com/embed/ivdTnPl1ND0?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen="" title="Aprende JavaScript - Curso Completo desde Cero" name="fitvid2"></iframe>
          </div>
        </div>
      </figure><figure class="kg-card kg-embed-card" data-test-label="fitted">
        <div class="fluid-width-video-container">
          <div style="padding-top: 56.17977528089888%;" class="fluid-width-video-wrapper">
            <iframe width="356" height="200" src="https://www.youtube.com/embed/DLikpfc64cA?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen="" title="Introducción a Programación en Python" name="fitvid3"></iframe>
          </div>
        </div>
      </figure><figure class="kg-card kg-embed-card" data-test-label="fitted">
        <div class="fluid-width-video-container">
          <div style="padding-top: 56.17977528089888%;" class="fluid-width-video-wrapper">
            <iframe width="356" height="200" src="https://www.youtube.com/embed/6Jfk8ic3KVk?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen="" title="Aprende React Desde Cero - Curso de React Con Proyectos" name="fitvid4"></iframe>
          </div>
        </div>
      </figure> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Cómo instalar Node.js en Ubuntu y actualizar npm a la última versión ]]>
                </title>
                <description>
                    <![CDATA[ Si intentas instalar la última versión de Node usando el gestor de paquetes apt, acabarás con la versión 10.19.0. Esta es la última versión en la tienda de aplicaciones de ubuntu, pero no es la última versión liberada de NodeJS. Esto se debe a que cuando se publican nuevas versiones ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/como-instalar-nodejs-en-ubuntu-y-actualizar-npm-a-la-ultima-version/</link>
                <guid isPermaLink="false">62e5ae98b4def50851975e3d</guid>
                
                    <category>
                        <![CDATA[ Node.js ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Keiler Guardo Herrera ]]>
                </dc:creator>
                <pubDate>Wed, 03 Aug 2022 21:33:18 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2022/07/Slice-3-2-.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artículo original:</strong> <a href="https://www.freecodecamp.org/news/how-to-install-node-js-on-ubuntu-and-update-npm-to-the-latest-version/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">How to Install Node.js on Ubuntu and Update npm to the Latest Version</a>
      </p><p>Si intentas instalar la última versión de Node usando el gestor de paquetes apt, acabarás con la versión <strong>10.19.0</strong>. Esta es la última versión en la tienda de aplicaciones de ubuntu, pero no es la última versión liberada de NodeJS.</p><p>Esto se debe a que cuando se publican nuevas versiones de un software, el equipo de Ubuntu puede tardar meses en probarlo y publicarlo en la tienda oficial de Ubuntu. Como resultado, para obtener las últimas versiones de cualquier software, es posible que tengamos que utilizar paquetes privados publicados por los desarrolladores.</p><p>En este tutorial, lo que queremos hacer es obtener la <strong>v12.18.1</strong> (LTS - con soporte a largo plazo) o la <strong>v14.4</strong> de Node. Para obtener las últimas versiones, podemos utilizar <strong>nodesource</strong> o <strong>nvm</strong> (node version manager). Te mostraré cómo usar ambos.</p><p>Todos los comandos aquí serán ejecutados usando el CLI/terminal de Ubuntu.</p><h2 id="usando-nvm-mi-m-todo-preferido">Usando NVM - mi método preferido</h2><p>Me gusta nvm porque me permite usar diferentes versiones de node para diferentes proyectos. A veces, puedes estar colaborando en un proyecto con alguien que usa una versión diferente de node y necesitas cambiar las versiones de node a lo que el proyecto requiere. Para esto, nvm es la mejor herramienta.</p><h2 id="instalar-nvm">Instalar NVM</h2><p><code>curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.3/install.sh | bash</code></p><p>Para comprobar que nvm está instalado, escriba <code>nvm --version</code>. Si obtienes un número de versión como <code>0.35.3</code>, entonces sabes que nvm fue instalado con éxito.</p><p><strong>Reinicia tu terminal para que los cambios surtan efecto.</strong></p><h2 id="instalar-nodejs">Instalar NodeJS</h2><p>A continuación, vamos a instalar la versión 14.4 de Nodejs.</p><p>Simplemente, ejecuta <code>nvm install 14.4.0</code>.</p><p>Puedes utilizar un comando similar para instalar cualquier versión de node, por ejemplo <code>nvm install 12.18.1</code>.</p><p>Este comando instala automáticamente <strong>nodejs</strong>, así como la última versión de <strong>npm</strong> que está en <code>v6.14.5</code>.</p><p>Si alguna vez necesitas cambiar de la versión de node, puedes simplemente ejecutar <code>nvm use &lt;número de versión&gt;</code>, por ejemplo <code>nvm use v12.18.1</code>.</p><p>Para listar las diferentes versiones de node que tiene instaladas con nvm, ejecute <code>nvm ls</code>.</p><h2 id="instalar-nodesource">Instalar Nodesource</h2><p>Ejecuta el siguiente comando para decirle a Ubuntu que queremos instalar el paquete de Nodejs desde nodesource.</p><p><code>curl -sL https://deb.nodesource.com/setup_14.x | sudo -E bash -</code></p><p>Ten en cuenta que v14.4.0 es la última versión de Node, pero actualmente no tiene LTS - soporte a largo plazo proporcionado para ello. Para instalar la última versión de Node con LTS, cambie <code>14</code> en el comando anterior por <code>12</code>.</p><p>Es posible que se te pida que introduzcas la contraseña de tu usuario root. Introduce y pulsa enter/return.</p><h2 id="instalar-nodejs-1"><strong>I</strong>nstalar NodeJS</h2><p>Una vez que hayamos terminado de configurar Nodesource, podemos instalar Nodejs v14.4. Ejecuta <code>sudo apt-get install -y nodejs</code>.</p><p>Después que hayamos terminado, podemos comprobar que tenemos la última versión de Node instalada. Simplemente, escribe <code>nodejs -v</code> en tu terminal y debería devolver la <code>v14.4.0</code>.</p><p>En este punto deberías tener npm instalado automáticamente. Para comprobar qué versión de npm tienes, ejecuta <code>npm version</code>. Si no obtiene un objeto que incluya la última versión de npm en 6.14.5, <code>{npm: '6.14.5'}</code>, entonces puedes actualizar npm manualmente ejecutando el siguiente comando:</p><p><code>npm install -g npm@latest</code>.</p><p>Si te encuentras con algún problema de que npm no se puede actualizar porque no está instalado, puedes instalar npm primero usando <code>sudo apt-get install -y npm</code>, y luego ejecutar el comando anterior para actualizarlo.</p><p>Para que ciertos paquetes de npm se ejecuten, también necesitamos ejecutar el comando <code>sudo apt install build-essential</code>.</p><p>Y eso es todo.</p><p>Ya tienes las últimas versiones de NodeJS y NPM en tu máquina Ubuntu.</p><p>Ve a construir grandes productos :)</p> ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
