Cómo Crear Programas CLI en Typescript y Deno

Usando Deno 🦕

Gabriel Trabanco
DotTech
5 min readMay 8, 2021

--

ATENCIÓN: Este artículo contiene altas dosis de emojis 😆.

Logo de Deno, que es un runtime parecido a Node pero para Javascript

Tras el éxito de cómo crear programas de línea de comandos con NodeJS, solo se me ocurre otra cosa más guay, crear los comandos directamente con Typescript 😎 usando Deno 🦕 (y sí, cada vez que escriba Deno 🦕 añadiré también el emoji 🤪).

Requisitos previos

  • Saber un poco de Typescript.
  • Haremos algo “sencillo”, pero que sea mínimamente útil. Crearemos un comando que, recibiendo {usuario|organización}/{repositorio} como parámetros, nos diga cuántos “Pull Request” hay pendientes usando Fetch.

Introducción

Deno 🦕 trae una herramienta que nos permite instalar programas hechos con Typescript como si de archivos binarios se tratasen, dejando dichos programas disponibles en nuestra terminal listos para usarse. Para ver como hacer esto, basta con ejecutar (tras instalar deno, obviamente):

deno install --help

Como podemos ver, el propio Deno 🦕 nos propone varios ejemplos, los cuales son realmente útiles. De hecho, son los que yo he seguido para desarrollar este comando.

Ejecutar un script de Deno 🦕

Deno 🦕, está pensado para ser “seguro” (lo pongo entre comillas, no por que lo sea o no, sino porque soy escéptico respecto de la seguridad informática). Por tanto, existen una serie de argumentos que debemos pasar a un script para permitir que pueda usar fetch (recursos de red) y variables de entorno, en nuestro caso (puedes ver el resto en la documentación de Deno 🦕). Estos argumentos los podemos escribir directamente en el shebang de nuestro script.

#!/usr/bin/env -S deno run --allow-net --allow-env

Agregando estos argumentos y dándole permisos de ejecución al script podréis ejecutarlo directamente usando:

./mi_script_deno

Instalación de un script

Los scripts de Deno 🦕, se pueden instalar en nuestro equipo. Por defecto, se instalarán en $HOME/.deno/bin pero podemos modificar el PATH por defecto a otro, de dos formas:

1. Definiendo una ruta en la variable DENO_ROOT_PATH .

2. Al utilizar el comando deno install pasarle el argumento --root .

Por esto mismo es importante asegurarnos en nuestro .bashrc o bien .zshrcde que agregamos dicha ruta a la variable de entorno PATH, también sirve que lo escribáis en la terminal pero tendréis que hacerlo cada vez que la iniciéis si no lo agregáis en vuestros dotfiles:

 export PATH="$PATH:$HOME/.deno/bin"

A la hora de instalar los scripts lo podemos hacer desde una ruta local, como por ejemplo, suponiendo que nuestro script esté en $HOME/Mis-Codigos/deno-script/mi-script.ts:

deno install $HOME/Mis-Codigos/deno-script/mi-script.ts

Con esto si vamos al directorio $HOME/.deno/bin veremos un archivo con permisos de ejecución llamado mi-script.

Vuelve al paso anterior y trata de instalar de nuevo el mismo script. Deno 🦕 dirá que al archivo ya existe. Por lo que si queremos añadir el script de nuevo, por el motivo que sea, hay que añadir -f para forzar que sobreescriba el script actual.

Nuestro script

Sobre el script que instalaremos

El script para ver las PRs que hay en un repositorio de GitHub se llama deno-github-prs, pero supongamos que o bien tenemos un script con el mismo nombre que hace algo distinto o que lo queremos usar con otro nombre, como por ejemplo github-open-prs. Además, nuestro script necesita dos argumentos de permisos --allow-net para hacer fetch a la API de GitHub y --allow-env, ya que si tienes definida la variable de entorno GITHUB_TOKEN hace la llamada a la API usando tu token de GitHub para no sobrepasar el limite de llamadas a la API.

Instalación del script

Para instalarlo con las condiciones que hemos establecido:

deno install --allow-net --allow-env https://gist.githubusercontent.com/gtrabanco/7bea0d777e318d2f310f06576b23eab5/raw/78cb0dc1816329cba12ba7915c687ca6423e3729/deno-github-open-prs.ts --name github-open-prs

Usando nuestro script

github-open-prs --user denoland --repository deno_std

Nos devolverá un string parecido a lo siguiente (obviamente variará):

El repositorio de GitHub denoland/deno_std, tiene 22 PRs abiertas

Veamos qué tiene github-open-prs

#!/bin/sh
# generated by deno install
exec deno run --allow-net --allow-env "https://gist.githubusercontent.com/gtrabanco/7bea0d777e318d2f310f06576b23eab5/raw/78cb0dc1816329cba12ba7915c687ca6423e3729/deno-github-open-prs.ts" --name github-open-prs "$@"

Tanto si hacemos una instalación local, como remota, veremos que dentro del archivo que nos crea Deno🦕 lo que hay es un enlace al archivo original.

Tengo una buena noticia y una noticia mala para ti. ¡Existe una solución! Pero no te va a gustar para producción (aún).

Deno 🦕 compile al rescate

Existe Deno 🦕 compiler (subcomando compile), que hace eso mismo: crear un binario de nuestro Typescript.

Básicamente en cuanto a cómo debemos usarlo, es igual que deno install pero no es una versión estable (por ahora) y, además, los binarios son muy pesados. En nuestro caso 58 MB usando el argumento --lite. Sin dicho argumento son 64 MB, por lo que tampoco hay mucha diferencia entre que meta el runtime ligero (lite) y el normal.

Lo que hace es meter el runtime en el ejecutable de Deno, además soporta “cross-compilation” (compilación cruzada), es decir, podemos crear un binario para arm desde una arquitectura x86_64 (por ejemplo).

Usando Deno compile

Pues simplemente para instalar el mismo comando y que no tenga que descargar nada ni ejecutar nada de forma remota, usaremos el siguiente comando:

deno compile --unstable --allow-net --allow-env https://gist.githubusercontent.com/gtrabanco/7bea0d777e318d2f310f06576b23eab5/raw/78cb0dc1816329cba12ba7915c687ca6423e3729/deno-github-open-prs.ts --name github-open-prs

Y si lo que queremos es usar la versión “lite” del runtime:

deno compile --unstable --lite --allow-net --allow-env https://gist.githubusercontent.com/gtrabanco/7bea0d777e318d2f310f06576b23eab5/raw/78cb0dc1816329cba12ba7915c687ca6423e3729/deno-github-open-prs.ts --name github-open-prs

Conclusión

Deno 🦕 es una herramienta potente y además es más rápido que node para hacer scripts que se ejecuten como binarios en la terminal. A esto le añadimos que el nivel de dificultad para crear un script ejecutable en Deno 🦕 es similar a Node por lo que es una muy buena alternativa en el presente para utilizarlo de esta forma.

Si bien, como handicap, utiliza el archivo de Typescript de manera “remota”, lo que puede acarrearnos problemas si movemos nuestros scripts o si no tenemos conexión a Internet.

La instalación “compilada” de Deno 🦕, aún no me parece una solución real ya que los binarios que produce son excesivamente pesados. Aún así puede ser una buena alternativa a BASH o PowerShell en ciertos momentos en los que un script de BASH o PowerShell se convierte en algo sumamente complejo que con Typescript, quizás se nos resuma en un código más estructurado o con menor complejidad.

En cualquier caso, te sugiero que lo pruebes porque Deno 🦕 cada vez, tiene mucha mejor pinta.

--

--