Cómo desarrollar una aplicación de línea de comandos interactiva utilizando Node.js

 

 

 

  • Taller de diseño conductual, con Susan y Guthrie Weinschenk
  • Implemente rápidamente. Implementar inteligentemente

  • Índice
    1. "Hola Mundo"
    2. Manejo de argumentos de línea de comando
    3. Entradas de usuario en tiempo de ejecución
    4. Comunicación de red asíncrona
    5. Decorando la salida
    6. Convirtiéndolo en un comando de Shell
    7. Más allá de JavaScript
      1. Otras lecturas

    Node.js ha ayudado a aportar uniformidad al desarrollo de software. Escribir herramientas de línea de comandos también se ha vuelto más fácil que nunca gracias a Node.js. Herramientas como Yeoman solicitan entradas de tiempo de ejecución que eventualmente también le ayudarán a personalizar la configuración de un proyecto. Algunos generadores en Yeoman le ayudan a implementar un proyecto en su entorno de producción. Eso es exactamente lo que vas a aprender hoy. En este tutorial, Nihar Sawant desarrollará una aplicación de línea de comandos que acepta un archivo CSV de información del cliente y, utilizando la API SendGrid, les enviará correos electrónicos.

     

    Durante los últimos cinco años, Node.js ha ayudado a aportar uniformidad al desarrollo de software. Puede hacer cualquier cosa en Node.js, ya sea desarrollo front-end, scripting del lado del servidor, aplicaciones de escritorio multiplataforma, aplicaciones móviles multiplataforma, Internet de las cosas, lo que sea. Escribir herramientas de línea de comandos también se ha vuelto más fácil que nunca gracias a Node.js: no cualquier herramienta de línea de comandos, sino herramientas que son interactivas, útiles y que requieren menos tiempo de desarrollo.

     

    Si es un desarrollador front-end, debe haber oído hablar o haber trabajado en Gulp , Angular CLI , Cordova , Yeoman y otros. ¿Alguna vez te has preguntado cómo funcionan? Por ejemplo, en el caso de Angular CLI, al ejecutar un comando como ng new project-name, terminas creando un proyecto Angular con una configuración básica. Herramientas como Yeoman solicitan entradas de tiempo de ejecución que eventualmente también le ayudarán a personalizar la configuración de un proyecto. Algunos generadores en Yeoman le ayudan a implementar un proyecto en su entorno de producción. Eso es exactamente lo que vamos a aprender hoy.

    En este tutorial, desarrollaremos una aplicación de línea de comandos que acepta un archivo CSV de información del cliente y, utilizando la API SendGrid , les enviaremos correos electrónicos. Aquí está el contenido de este tutorial:

    1. "Hola Mundo"
    2. Manejo de argumentos de línea de comando
    3. Entradas del usuario en tiempo de ejecución
    4. Comunicación de red asíncrona
    5. Decorar la salida CLI
    6. Convirtiéndolo en un comando de shell
    7. Más allá de JavaScript

    "Hola Mundo"

    Este tutorial asume que ha instalado Node.js en su sistema. En caso de que no lo hayas hecho, instálalo . Node.js también viene con un administrador de paquetes llamado npm . Con npm, puede instalar muchos paquetes de código abierto. Puede obtener la lista completa en el sitio web oficial de npm . Para este proyecto, usaremos muchos módulos de código abierto (más sobre esto más adelante). Ahora, creemos un proyecto Node.js usando npm.

    $ npm initname: broadcastversion: 0.0.1description: CLI utility to broadcast emailsentry point: broadcast.js

    He creado un directorio llamado broadcast, dentro del cual ejecuté el npm initcomando. Como puede ver, he proporcionado información básica sobre el proyecto, como nombre, descripción, versión y punto de entrada. El punto de entrada es el archivo JavaScript principal desde donde comenzará la ejecución del script. De forma predeterminada, Node.js asigna index.jscomo punto de entrada; sin embargo, en este caso, lo cambiaremos a broadcast.js. Cuando ejecute el npm initcomando, obtendrá algunas opciones más, como el repositorio, la licencia y el autor de Git. Puede proporcionar valores o dejarlos en blanco.

    Tras la ejecución exitosa de npm init, encontrará que package.jsonse ha creado un archivo en el mismo directorio. Este es nuestro archivo de configuración. Por el momento, contiene la información que proporcionamos al crear el proyecto. Puede explorar más package.json en la documentación de npm .

     

    Ahora que nuestro proyecto está configurado, creemos un programa "Hola mundo". Para comenzar, crea un broadcast.jsarchivo en tu proyecto, que será tu archivo principal, con el siguiente fragmento:

    console.log('hello world');

    Ahora, ejecutemos este código.

    $ node broadcasthello world

    Como puede ver, "hola palabra" se imprime en la consola. Puede ejecutar el script con node broadcast.jso node broadcast; Node.js es lo suficientemente inteligente como para comprender la diferencia.

    Según package.jsonla documentación de , existe una opción denominada dependenciesen la que puede mencionar todos los módulos de terceros que planea usar en el proyecto, junto con sus números de versión. Como se mencionó, utilizaremos muchos módulos de código abierto de terceros para desarrollar esta herramienta. En nuestro caso, package.jsonse ve así:

    { "name": "broadcast", "version": "0.0.1", "description": "CLI utility to broadcast emails", "main": "broadcast.js", "license": "MIT", "dependencies": { "async": "^2.1.4", "chalk": "^1.1.3", "commander": "^2.9.0", "csv": "^1.1.0", "inquirer": "^2.0.0", "sendgrid": "^4.7.1" }}

    Como habrás notado, usaremos Async , Chalk , Commander , CSV , Inquirer.js y SendGrid . A medida que avancemos con el tutorial, se explicará en detalle el uso de estos módulos.

    Manejo de argumentos de línea de comando

    Leer los argumentos de la línea de comando no es difícil. Simplemente puedes usarlos process.argvpara leerlos. Sin embargo, analizar sus valores y opciones es una tarea engorrosa. Entonces, en lugar de reinventar la rueda, usaremos el módulo Commander . Commander es un módulo Node.js de código abierto que le ayuda a escribir herramientas de línea de comandos interactivas. Viene con funciones muy interesantes para analizar opciones de línea de comandos y tiene subcomandos similares a Git, pero lo que más me gusta de Commander es la generación automática de pantallas de ayuda. No es necesario escribir líneas de código adicionales; simplemente analice la opción –helpo -h. A medida que comience a definir varias opciones de línea de comando, la –helppantalla se completará automáticamente. Profundicemos:

    $ npm install commander --save

    Esto instalará el módulo Commander en su proyecto Node.js. Al ejecutar la npm install with –saveopción, Commander se incluirá automáticamente en las dependencias del proyecto, definidas en package.json. En nuestro caso, ya se han mencionado todas las dependencias; por lo tanto, no es necesario ejecutar este comando.

    var program = require('commander');program .version('0.0.1') .option('-l, --list [list]', 'list of customers in CSV file') .parse(process.argv)console.log(program.list);

    Como puede ver, manejar los argumentos de la línea de comando es sencillo. Hemos definido una –listopción. Ahora, cualquier valor que proporcionemos seguido de la –listopción se almacenará en una variable entre corchetes (en este caso, ) list. Puedes acceder a él desde la programvariable, que es una instancia de Commander. Por el momento, este programa sólo acepta una ruta de archivo para la –listopción y la imprime en la consola.

     

    $ node broadcast --list input/employees.csvinput/employees.csv

    Debes haber notado también un método encadenado que hemos invocado, llamado version. Siempre que ejecutemos el comando que proporciona –versiono -Vcomo opción, se imprimirá cualquier valor que se pase en este método.

    $ node broadcast --version0.0.1

    De manera similar, cuando ejecuta el comando con la –helpopción, imprimirá todas las opciones y subcomandos definidos por usted. En este caso, se verá así:

    $ node broadcast --help Usage: broadcast [options] Options: -h, --help output usage information -V, --version output the version number -l, --list list list of customers in CSV file

    Ahora que aceptamos rutas de archivos desde argumentos de línea de comando, podemos comenzar a leer el archivo CSV usando el módulo CSV . El módulo CSV es una solución todo en uno para manejar archivos CSV. Desde crear un archivo CSV hasta analizarlo, puedes lograr cualquier cosa con este módulo.

    Debido a que planeamos enviar correos electrónicos utilizando la API SendGrid, utilizamos el siguiente documento como un archivo CSV de muestra. Usando el módulo CSV, leeremos los datos y mostraremos el nombre y la dirección de correo electrónico proporcionados en las filas respectivas.

    Nombre de pila Apellido Correo electrónico
    Dwight Schrute [email protected]
    Jim Halpert [email protected]
    pam abejas [email protected]
    ryan Howard [email protected]
    stanley hudson [email protected]

    Ahora, escribamos un programa para leer este archivo CSV e imprimir los datos en la consola.

    const program = require('commander');const csv = require('csv');const fs = require('fs');program .version('0.0.1') .option('-l, --list [list]', 'List of customers in CSV') .parse(process.argv)let parse = csv.parse;let stream = fs.createReadStream(program.list) .pipe(parse({ delimiter : ',' }));stream .on('data', function (data) { let firstname = data[0]; let lastname = data[1]; let email = data[2]; console.log(firstname, lastname, email); });

    Usando el módulo nativo del sistema de archivos , leemos el archivo proporcionado mediante argumentos de la línea de comando. El módulo Sistema de archivos viene con eventos predefinidos, uno de los cuales es data, que se activa cuando se lee una porción de datos. El parsemétodo del módulo CSV divide el archivo CSV en filas individuales y activa múltiples eventos de datos. Cada evento de datos envía una matriz de datos de columnas. Así, en este caso, imprime los datos en el siguiente formato: Filtros de Agua

    $ node broadcast --list input/employees.csvDwight Schrute [email protected] Halpert [email protected] Beesly [email protected] Howard [email protected] Hudson [email protected]

    Entradas de usuario en tiempo de ejecución

    Ahora sabemos cómo aceptar argumentos de línea de comando y cómo analizarlos. Pero ¿qué pasa si queremos aceptar entradas durante el tiempo de ejecución? Un módulo llamado Inquirer.js nos permite aceptar varios tipos de entrada, desde texto sin formato hasta contraseñas y una lista de verificación de selección múltiple.

     

    Para esta demostración, aceptaremos la dirección de correo electrónico y el nombre del remitente mediante entradas en tiempo de ejecución.

    …let questions = [ { type : "input", name : "sender.email", message : "Sender's email address - " }, { type : "input", name : "sender.name", message : "Sender's name - " }, { type : "input", name : "subject", message : "Subject - " }];let contactList = [];let parse = csv.parse;let stream = fs.createReadStream(program.list) .pipe(parse({ delimiter : "," }));stream .on("error", function (err) { return console.error(err.message); }) .on("data", function (data) { let name = data[0] + " " + data[1]; let email = data[2]; contactList.push({ name : name, email : email }); }) .on("end", function () { inquirer.prompt(questions).then(function (answers) { console.log(answers); }); });

    Primero, notarás en el ejemplo anterior que hemos creado una matriz llamada contactList, que estamos usando para almacenar los datos del archivo CSV.

    Inquirer.js viene con un método llamado prompt, que acepta una serie de preguntas que queremos hacer durante el tiempo de ejecución. En este caso, queremos saber el nombre y la dirección de correo electrónico del remitente y el asunto de su correo electrónico. Hemos creado una matriz denominada questionsen la que almacenamos todas estas preguntas. Esta matriz acepta objetos con propiedades como type, que pueden ser cualquier cosa, desde una entrada hasta una contraseña o una lista sin formato. Puedes ver la lista de todos los tipos disponibles en la documentación oficial . Aquí, namecontiene el nombre de la clave en la que se almacenará la entrada del usuario. El promptmétodo devuelve un objeto de promesa que eventualmente invoca una cadena de devoluciones de llamada de éxito y fracaso, que se ejecutan cuando el usuario ha respondido todas las preguntas. Se puede acceder a la respuesta del usuario a través de la answersvariable, que se envía como parámetro a la thendevolución de llamada. Esto es lo que sucede cuando ejecuta el código:

    $ node broadcast -l input/employees.csv? Sender's email address - [email protected]? Sender's name - Micheal Scott? Subject - Greetings from Dunder Mifflin{ sender: { email: '[email protected]', name: 'Michael Scott' }, subject: 'Greetings from Dunder Mifflin' }

    Comunicación de red asíncrona

    Ahora que podemos leer los datos del destinatario del archivo CSV y aceptar los datos del remitente a través de la línea de comando, es hora de enviar los correos electrónicos. Usaremos la API de SendGrid para enviar correos electrónicos.

     

    …let __sendEmail = function (to, from, subject, callback) { let template = "Wishing you a Merry Christmas and a " + "prosperous year ahead. P.S. Toby, I hate you."; let helper = require('sendgrid').mail; let fromEmail = new helper.Email(from.email, from.name); let toEmail = new helper.Email(to.email, to.name); let body = new helper.Content("text/plain", template); let mail = new helper.Mail(fromEmail, subject, toEmail, body); let sg = require('sendgrid')(process.env.SENDGRID_API_KEY); let request = sg.emptyRequest({ method: 'POST', path: '/v3/mail/send', body: mail.toJSON(), }); sg.API(request, function(error, response) { if (error) { return callback(error); } callback(); });};stream .on("error", function (err) { return console.error(err.response); }) .on("data", function (data) { let name = data[0] + " " + data[1]; let email = data[2]; contactList.push({ name : name, email : email }); }) .on("end", function () { inquirer.prompt(questions).then(function (ans) { async.each(contactList, function (recipient, fn) { __sendEmail(recipient, ans.sender, ans.subject, fn); }); }); });

    Para comenzar a utilizar el módulo SendGrid , necesitamos obtener una clave API. Puede generar esta clave API desde el panel de SendGrid (deberá crear una cuenta). Una vez que se genera la clave API, almacenaremos esta clave en variables de entorno junto con una clave denominada SENDGRID_API_KEY. Puede acceder a las variables de entorno en Node.js usando process.env.

    En el código anterior, enviamos correos electrónicos asincrónicos utilizando la API de SendGrid y el módulo Async . El módulo Async es uno de los módulos de Node.js más potentes. Manejar devoluciones de llamadas asincrónicas a menudo conduce al infierno de las devoluciones de llamadas . Llega un punto en el que hay tantas llamadas asincrónicas que terminas escribiendo devoluciones de llamada dentro de una devolución de llamada y, a menudo, esto no tiene fin. Manejar errores se vuelve aún más complicado para un ninja de JavaScript. El módulo Async le ayuda a superar el infierno de las devoluciones de llamadas, proporcionando métodos útiles como each, seriesy mapmuchos más. Estos métodos nos ayudan a escribir código que sea más manejable y que, a su vez, parezca un comportamiento sincrónico.

    En este ejemplo, en lugar de enviar una solicitud sincrónica a SendGrid, enviamos una solicitud asincrónica para enviar un correo electrónico. Según la respuesta, enviaremos solicitudes posteriores. Usando cada método en el módulo Async, iteramos sobre la contactListmatriz y llamamos a una función llamada sendEmail. Esta función acepta los detalles del destinatario, los detalles del remitente, la línea de asunto y la devolución de llamada para la llamada asincrónica.sendEmail envía correos electrónicos utilizando la API de SendGrid; Puede explorar más sobre el módulo SendGrid en la documentación oficial . Una vez que un correo electrónico se envía correctamente, se invoca una devolución de llamada asincrónica, que pasa al siguiente objeto de la contactListmatriz.

    ¡Eso es todo! Usando Node.js, hemos creado una aplicación de línea de comandos que acepta entradas CSV y envía correos electrónicos.

     

    Decorando la salida

    Ahora que nuestra aplicación está lista para enviar correos electrónicos, veamos cómo podemos decorar el resultado, como mensajes de error y de éxito. Para hacerlo, usaremos el módulo Chalk , que se usa para diseñar entradas de línea de comando.

    …stream .on("error", function (err) { return console.error(err.response); }) .on("data", function (data) { let name = data[0] + " " + data[1]; let email = data[2]; contactList.push({ name : name, email : email }); }) .on("end", function () { inquirer.prompt(questions).then(function (ans) { async.each(contactList, function (recipient, fn) { __sendEmail(recipient, ans.sender, ans.subject, fn); }, function (err) { if (err) { return console.error(chalk.red(err.message)); } console.log(chalk.green('Success')); }); }); });

    En el fragmento anterior, agregamos una función de devolución de llamada al enviar correos electrónicos, y esa función se llama cuando el eachbucle asíncrono se completa o se interrumpe debido a un error de tiempo de ejecución. Cada vez que un bucle no se completa, envía un errorobjeto, que imprimimos en la consola en rojo. En caso contrario, imprimimos un mensaje de éxito en verde.

    Si consulta la documentación de Chalk, encontrará muchas opciones para diseñar esta entrada, incluida una gama de colores de consola (magenta, amarillo, azul, etc.) texto subrayado y en negrita.

    Convirtiéndolo en un comando de Shell

    Ahora que nuestra herramienta está completa, es hora de hacerla ejecutable como un comando de shell normal. Primero, agreguemos un shebang en la parte superior de broadcast.js, que le indicará al shell cómo ejecutar este script.

    #!/usr/bin/env nodeconst program = require("commander");const inquirer = require("inquirer");…

    Ahora, configuremos el package.jsonpara que sea ejecutable.

    … "description": "CLI utility to broadcast emails", "main": "broadcast.js", "bin" : { "broadcast" : "./broadcast.js" }…

    Hemos agregado una nueva propiedad llamada bin, en la que hemos proporcionado el nombre del comando desde el cual broadcast.jsse ejecutará.

    Ahora para el paso final. Instalemos este script a nivel global para que podamos comenzar a ejecutarlo como un comando de shell normal.

    $ npm install -g

    Antes de ejecutar este comando, asegúrese de estar en el mismo directorio del proyecto. Una vez que se completa la instalación, puede probar el comando.

    $ broadcast --help

    Esto debería imprimir todas las opciones disponibles que obtenemos después de ejecutar node broadcast –help. Ahora está listo para presentar su utilidad al mundo.

    Una cosa a tener en cuenta: durante el desarrollo, cualquier cambio que realice en el proyecto no será visible si simplemente ejecuta el broadcastcomando con las opciones dadas. Si ejecuta which broadcast, se dará cuenta de que la ruta de broadcastno es la misma que la ruta del proyecto en el que está trabajando. Para evitar esto, simplemente ejecútelo npm linken la carpeta de su proyecto. Esto establecerá automáticamente un enlace simbólico entre el comando ejecutable y el directorio del proyecto. De ahora en adelante, cualquier cambio que realice en el directorio del proyecto también se reflejará en el comando de transmisión.

    Más allá de JavaScript

    El alcance de la implementación de este tipo de herramientas CLI va mucho más allá de los proyectos de JavaScript. Si tiene algo de experiencia en desarrollo de software y TI, las herramientas Bash habrán sido parte de su proceso de desarrollo. Desde scripts de implementación hasta trabajos cron y copias de seguridad, puede automatizar cualquier cosa utilizando scripts Bash. De hecho, antes de que Docker , Chef y Puppet se convirtieran en los estándares de facto para la gestión de infraestructura, Bash era el salvador. Sin embargo, los scripts Bash siempre tuvieron algunos problemas. No encajan fácilmente en un flujo de trabajo de desarrollo. Por lo general, usamos cualquier cosa, desde Python hasta Java y JavaScript; Bash rara vez ha sido parte del desarrollo central. Incluso escribir una declaración condicional simple en Bash requiere pasar por documentación y depuración interminables.

    Sin embargo, con JavaScript, todo este proceso se vuelve más sencillo y eficiente. Todas las herramientas se vuelven automáticamente multiplataforma. Si desea ejecutar un comando de shell nativo como git, mongodbo heroku, puede hacerlo fácilmente con el módulo Proceso secundario en Node.js. Esto le permite escribir herramientas de software con la simplicidad de JavaScript.

    Espero que este tutorial te haya sido útil. Si tiene alguna pregunta, déjela en la sección de comentarios a continuación o envíeme un tweet .

    Otras lecturas

    • Una introducción detallada a Webpack
    • Una introducción a Node.js y MongoDB
    • Representación del lado del servidor con React, Node y Express
    • Herramientas, tutoriales y recursos útiles de Node.js

    (rb, al, il, mrn)Explora más en

    • Angular
    • javascript
    • Nodo.js
    • Flujo de trabajo





    Tal vez te puede interesar:

    1. ¿Deberían abrirse los enlaces en ventanas nuevas?
    2. 24 excelentes tutoriales de AJAX
    3. 70 técnicas nuevas y útiles de AJAX y JavaScript
    4. Más de 45 excelentes recursos y repositorios de fragmentos de código

    Cómo desarrollar una aplicación de línea de comandos interactiva utilizando Node.js

    Cómo desarrollar una aplicación de línea de comandos interactiva utilizando Node.js

    'Hola Mundo'Manejo de argumentos de línea de comandoEntradas de usuario en tiempo de ejecuciónComunicación de red asíncronaDecorando la salidaConvirtiéndo

    programar

    es

    https://aprendeprogramando.es/static/images/programar-como-desarrollar-una-aplicacion-de-linea-de-comandos-interactiva-utilizando-node-911-0.jpg

    2024-12-03

     

    Cómo desarrollar una aplicación de línea de comandos interactiva utilizando Node.js
    Cómo desarrollar una aplicación de línea de comandos interactiva utilizando Node.js

    Si crees que alguno de los contenidos (texto, imagenes o multimedia) en esta página infringe tus derechos relativos a propiedad intelectual, marcas registradas o cualquier otro de tus derechos, por favor ponte en contacto con nosotros en el mail [email protected] y retiraremos este contenido inmediatamente

     

     

    Update cookies preferences