Ir al contenido principal

Node y Quickjs para aplicaciones CLI

Node y Quickjs para aplicaciones CLI

Node y Quickjs son 2 de los entornos de ejecución más populares para correr nuestro código javascript. En este artículo explico como programar código portable entre ambos entornos y cual te beneficia utilizar para según el tipo de programa que desarrolles sin dejar de perder las posibilidades de correrlo en el otro entorno.

Vision General

Node

Node.js es un proyecto de código abierto que permite ejecutar códigojavascript fuera del navegador. Es ampliamente utilizado para producir y servir páginas webs. Utiliza el motor javascript V8 (motor que utiliza Chrome entre otros) para ejecutar javascript. Al ser un motor utilizado en ambos entornos, se focalizan las mejoras y se reducen los costes al aunar esfuerzos en un mismo proyecto. Estas premisas han convertido a node en el entorno más potente de javascript, con holgura en todo el espectro de desarrollo.

Quickjs

Quickjs es un motor/entorno/librería que permite ejecutar código javascript fuera del navegador. Tiene poca adopción pero su sencillez, pequeño tamaño y fisonomía, hacen de el la utilidad perfecta para scripting, shell scripting, software embible y hardware de bajas prestaciones. Una de sus cualidades más destacadas es la posibilidad de compilar a código C tu programa utilizando la utilizad qjsc, o directamente generar un ejecitable a partir de tu código javascript.

Aplicaciones CLI

Las aplicaciones CLI son diseñadas para ser utilizadas como comandos desde una consola o terminal. Estos programas son ejecutados escribiendo su nombre acompañado de una serie de parámetros predefinidos con el objetivo de realizar una tarea u obtener un resultado. Son la versión en texto de sus homónimos las aplicaciones con interfaz gráfica y/o ventanas.

Instalación

Tanto node como quickjs son programas multiplataforma. Puedes instalarlos en una amplia variedad de sistemas operativos.

Instalación Node

  1. Visita el apartado de descargas de la página oficial de node en este enlace
  2. Selecciona el binario/instalador correspondiente a tu sistema operativo
  3. Sigue los pasos del instalador (windows) o ejecuta el binario desde la terminal (Unix), en caso que uses un sistema Unix, también puedes utilizar el gestor de paquetes de tu sistema.

Instalación Quickjs

  1. Si tienes instalado g++ y make o estás acostumbrado a compilar programas usando el código fuente, es recomendado compilarlo. Aquí la última versión del código.
    En caso contrario puedes optar por descargarte el binario ya compilado, lo único malo es que no incluye qjsc (el compilador de javascript a binario) . De todas formas podrás correr tu código javascript con solo eo binario. Aquí el listado de binarios disposibles. Asegúrate de bajar la versión más reciente compatible con tu sistema.
  2. Mueve el/los binarios extraídos del .tar.gz / .zip a una de las paths de binarios disponibles en tu sistema para poder utilizar qjs como un comando. En caso de Windows, la ruta C:\Windows\System32 o c:\Windows\SysWOW64 están incluidas por defecto en la variable de entorno PATH, asique si mueves a esa carpeta el ejecutable qjs, podrás utilizarlo desde la cmd como si fuese otro comando del sistema. En caso de Unix los directorios equivalente suelen ser /bin y ~/../usr/bin . Si compilaste desde código copia también qjsc a la ruta.

Testeo de la instalación

Crea un archivo de pruebas para comprobar que ambos entornos funcionen con el comando echo 'console.log("La fecha actual es: " + new Date())' > pruebaInstalacion.js . Prueba node con el comando node pruebaInstalacion.js y deberías ver la fecha en la consola como respuesta. Haz lo propio con quickjs utilizando el comando qjs pruebaInstalacion.js

Creando primera utilidad CLI

La primera utilidad va a ser algo sencillo con poca utilidad práctica, pero que nos sirva para entender como trabajar con los parámetros, así como otras utilidades en cada entorno (utilizando un método simple sin depencencias ni módulos externos) y a escribir código portable que funcione entre ambos entornos. Vamos a escribir un programa que acepte texto y nos diga cuantas letras, numeros y caracteres tiene. Utilizaremos 3 parámetros distintos para indicarle al programa que resultado queremos que nos muestre y otro parámetro para indicarle el archivo en el que se encuentra el texto.

Haciendo código compatible

Quickjs usa imports especiales con strings internos. En concreto tiene 2 módulos de este tipo, el módulo std, y el módulo os. Estos se deben importar al inicio del archivo antes que nada y su sintaxis es tal que import * as std from "std";. Tratar de correr un script con este tipo de import sin ruta ni extensión causaría una excepción en node. Para circunventar este problema se puede omitir estos imports utilizando el argumento --std. Para evitar tener que escribir este argumento puedes crear un alias. En caso de bash y linux, lo puedes hacer con el siguiente comando echo alias qjs="'"qjs --std "'" >> ~/.bashrc . En caso de windows para creat el alias puedes renombrar el binario de quickjs que añadiste anteriormente en C:\Windows\Sys y crear tu batch llamado qjs en el cual llames al qjs original con el argumento --std. También utilizaremos código para simplificar la detección de si el script corre en node o quickjs. let isQjs = false; try { isQjs = std ? true : false; } catch(e) {}

Leyendo los argumentos

En node para leer los argumentos utilizas process.argv, que retorna un array con todos los argumentos con los que fué llamado el programa. El equivalente en quickjs es scriptArgs. Para unificar ambos añadimos el código const cli = { args: isQjs ? scriptArgs : process.argv.splice(1) }; Como vamos a cargar el texto al programa leyéndolo de un archivo, debemos unificar también la forma de abrir abrir archivos. Node utiliza el nódulo fs, mientras que quickjs utiliza el módulo std. let loadFile; if (isQjs) { loadFile = std.loadFile; } else { const fs = require("fs"); loadFile = filename => { try { filename = fs.readFileSync(filename, { encoding: "utf-8" }) } catch(e) { filename = null; } return filename; }; }

Utilizaremos también el objeto cli para guardar nuestros argumentos con un switch: for (let i in cli.args) { switch(cli.args[i]) { case "-f": case "--file": cli.file = "" + loadFile(cli.args[+i + 1]); break; case "-h": case "--help": cli.help = true; break; case "-l": case "--letter": case "--letters": cli.letter = true; break; case "-n": case "--number": case "--numbers": cli.number = true; break; case "-s": case "--simbol": case "--simbols": cli.simbol = true; break; case "-t": case "--total": cli.total = true; } }

Funcionalidad del programa CLI

Por último añadimos que hacer en caso de que se encontrase cada argumento. (() => { if (cli.help) { console.log(`usage [engine] charcounter.js [arguments] engine: + qjs --std + node arguments: + -f, --file File name (path) of the file you want to load + -h, --help This message + -l, --letters Output how many letters the file has + -n, --numbers Output how many numbers the file has + -s, --simbols Output how many simbols the file has + -t, --total shows how many characters the file has Letters: a to Z Numbers: 0 to 9 Simbols: Anything else. Characters: Total. `); return; } else if (!!!cli.file) { console.log("Error: MISSING ARGUMENT -f\nArgument is mandatory."); return; } else { if (cli.letter) console.log(cli.file.match(/[a-zA-Z]/g).length); if (cli.number) console.log(cli.file.match(/[0-9]/g).length); if (cli.simbol) console.log(cli.file.match(/[^A-Za-z0-9]/g).length); if (cli.total) console.log(cli.file.length); } })();

Conclusiones

Al archivo con el código lo llamo charcounter.js, y funciona tanto en node como en qjs. Si miramos el tiempo que tarda el script con cada motor, podremos apreciar una diferencia muy significante: $ time qjs charcounter.js -f charcounter.js -l -n -s -t 1064 9 1004 2077 real 0m0.028s user 0m0.012s sys 0m0.012s $ time node charcounter.js -f charcounter.js -l -n -s -t 1064 9 1004 2077 real 0m0.250s user 0m0.216s sys 0m0.029s Quickjs ha resultado 10 veces más veloz que node. Solo por eso ya es una opción que merece la pena considerar, sobre todo para scripts pequeños y utilidades. Cómo es esto posible? Todo se basa en la significante diferencia del tiempo de carga. Node es mucho más grande y completo en muchos sentidos y por tanto necesita más tiempo para arrancar. Pero una vez arrancado es mucho más veloz que quickjs debido sobre todo a su implementación JIT.
Siempre tendrías la opción de correr el comando de node como un servicio, así siempre lo tendrías disponible(evitando tener que arrancarlo cada vez que corrar el programa). Esa opción puede ser un malgasto de recursos importante o no, depende de tu situación. Por ejemplo si substituyeses bash por tu propio REPL tendría sentido correrlo como un servicio 24/7. En cambio con utilidades simples como este contador de caracteres Quickjs es la solución perfecta.
Si compilaste el código de quickjs puedes usar qjsc para compilar el programa y añadirlo a la PATH de binarios para correrlo sin necesidad deprecederlo de qjs ni de qjs --std.

Comentarios

Entradas populares de este blog

Programar APKs en Termux

Programar APKs en Termux Siempre he querido programar apks (el .exe de android) directamente en Android. Tras varias búsquedas a lo largo del tiempo encontré una forma de crear apks usando comandos. Tanto Java como Kotlin son lenguajes que no me entusiasman precisamente asique he desarrollado un script en javascript y un par de repos para poder construir la apk a partir de una url o una carpeta con archivos html, css, js y demás de tal forma que no tengas que tocar ni una sola linea de código de java, kotlin, xml, etc. No es nada complejo, solo tienes que correr 2 comandos. Instalación Mi script utiliza unos cuantos paquetes de Termux: Quickjs Git Aapt Apksigner Dx Ecj Curl buildAPKs Hice un commando para que simplemente lo copies y pegues, te deja todo listo. Si acabas de descargarte termux, corre termux-setup-storage antes de nada. Si ya tenías acceso a la carpeta storage no hace falta. Aquí el comando: yes | pkg install quickjs git aapt apksigner dx e...

Javascript tutorial

Javascript tutorial Indice: 0. Un vistazo superficial. 1. Primeros Pasos. 2. Introducción al DOM. Capítulo 0. Un vistazo superficial. Qué es? Es un lenguaje de programación de propósito general. Esto significa que puede usarse en programas para móvil, programas de windows, drones, sistemas aeroespaciales, parquímetros, sistemas de contabilidad... Pero donde cobra mayor trascendencia es en la web. Originalmente en páginas web, pero también en el lado del servidor. Para qué sirve? Para hacer cualquier tipo de programa. Sobre todo haciendo funcionar las páginas web, donde html se usa para definir el contenido, css modifica y estiliza la apariencia y javascript se ocupa de "lo que hace" la web. Desde mostrar algo al pulsar un botón, hasta descargarse una web entera, obtener algo que nos interesa de ella, almacenarlo, mostrarlo, enviarlo... Qué conocimientos necesito? Ninguno. Se usará html mínimo para crear un documento e indicar donde está el código con javasc...

Node & Quickjs for CLI Development

Node & Quickjs for CLI development Este artículo también está disponible en español . Node and Quickjs are 2 of most popular runtime environments to run our javascript code. In this article I explain how to program portable code between both environments and which one benefits you to use according to the type of program you develop while still keeping the possibilities of running it in the other environment. Overview Node Node.js is an open source project that allows you to run javascript outside the browser. It is widely used to produce and serve web pages. It uses the V8 javascript engine (an engine that Chrome uses, among other browsers) to execute javascript. As it is an engine used in both environments, improvements are focused and costs are reduced by joining community...