Estos dÃas he estado usando deno con mÃĄs frecuencia y debo decirles que aÚn hay un par de cosas que me molestan. Sà logrÃĐ resolver algunos de esos problemas "agregando" algunos sub-comandos. No, no es magia negra, sÃģlo un pequeÃąo truco que aprendà hace tiempo y hoy voy a decirles cÃģmo funciona.
ÂŋQuÃĐ necesitamos?
En teorÃa cualquier intÃĐrprete que nos permita crear funciones deberÃa ser suficiente. En este artÃculo les estarÃĐ mostrando los ejemplos usando una sintaxis compatibles con intÃĐrpretes que obedecen el estÃĄndar POSIX (piensen en "shells" como zsh, bash, ash, etc...).
ÂŋQuÃĐ queremos lograr?
Personalmente a mà me encantarÃa que deno tuviera algÚn equivalente nativo a los npm scripts, pero parece que no tendremos nada de eso aÚn. Quisiera poder hacer algo asÃ.
deno start hello world
TambiÃĐn me gustarÃa poder inicializar esos scripts, porque deben existir en algÚn lado.
deno init
Como ya deben saber los sub-comandos start e init no existen y vamos a arreglar eso (casi).
Empecemos
El primer paso serÃa ubicar el archivo que su intÃĐrprete favorito ejecuta cada vez que lo invocan. En zsh por ejemplo, pueden usar ~/.zshrc. En bash pueden usar ~/.bashrc. Esos dos son los Únicos que conozco, si usan otro intÃĐrprete busquen en su documentaciÃģn algÚn equivalente.
La DefiniciÃģn
ÂŋEstÃĄn listos? Ahora deben crear una funciÃģn en ese archivo.
deno()
{
echo "Hola"
}
Ahora si reinician el intÃĐrprete (o "recargan" su configuraciÃģn) e invocan el comando deno deberÃan obtener Hola como resultado. Genial, hemos creado un problema, no podemos usar el comando deno. No teman, vamos por buen camino.
Vuelve a mi, deno
Si quisieramos invocar el comando deno lo Único que tenemos que hacer es usar el comando command asÃ:
command deno --version
Eso deberÃa mostrarle la informaciÃģn de deno.
deno x.x.x (release, x86_64-unknown-linux-gnu)
v8 x
typescript x.x
Con este nuevo conocimiento podemos resolver nuestro problema. Vamos a hacer una prueba.
deno()
{
echo "EstÃĄs usando"
command deno --version
}
Y esto es lo que deberÃa ocurrir al invocarlo.
$ deno
EstÃĄs usando
deno x.x.x (release, x86_64-unknown-linux-gnu)
v8 x
typescript x.x
Volviendo a la normalidad
Ahora que sabemos cÃģmo llamar a deno lo que deberÃamos hacer ahora es imitar el comportamiento de deno en nuestra funciÃģn. Debemos hacer esto de una manera que nos deje espacio para agregar nuestros propios comandos, para esto vamos a usar la declaraciÃģn case.
deno()
{
local cmd=$1; shift;
case "$cmd" in
*)
command deno $cmd $@
;;
esac
}
La primera lÃnea lo que hace es asignar el primer parÃĄmetro ($1) a la variable cmd y luego lo elimina de la lista de argumentos ($@). DespuÃĐs lo que hacemos es comparar cmd con un patrÃģn. Por ahora el Único patrÃģn que tenemos es *, que actÚa como un comodÃn que coincide con todo, bÃĄsicamente es nuestro default. Probemos.
deno --version
Bien, pero ahora si intentamos usar deno sin argumentos nos darÃĄ un error. Para arreglar eso vamos verificar si el primer parÃĄmetro estÃĄ vacÃo, si ese es el caso sÃģlo llamamos deno.
deno()
{
if [ -z "$1" ];then
command deno
return
fi
local cmd=$1; shift;
case "$cmd" in
*)
command deno $cmd $@
;;
esac
}
Invocando sub-comandos
Ya estamos en el lugar que queremos, finalmente podremos agregar nuestros propios sub-comandos. Veamos cÃģmo funcionarÃa.
deno()
{
if [ -z "$1" ];then
command deno
return
fi
local cmd=$1; shift;
case "$cmd" in
+ hola)
+ command deno eval "console.log('deno dice hola')"
+ ;;
*)
command deno $cmd $@
;;
esac
}
Si invocamos el comando hola:
$ deno hola
deno dice hola
Ahora estamos seguros que funciona.
deno scripts
Ya podemos comenzar con lo mÃĄs importante, nuestro reemplazo para los npm scripts. Lo que quiero hacer primero es crear el comando start, el cual es el mÃĄs comÚn que usarÃa.
deno()
{
if [ -z "$1" ];then
command deno
return
fi
local cmd=$1; shift;
case "$cmd" in
+ start)
+ command deno run --allow-run ./Taskfile.js start $@
+ ;;
*)
command deno $cmd $@
;;
esac
}
Esto lo que harÃĄ serÃĄ ejecutar un archivo llamado Taskfile.js usando deno. --allow-run nos permitirÃĄ usar Deno.run en nuestro cÃģdigo para poder llamar comandos externos dentro de Taskfile.js. Ahora vamos a usarlo.
Creamos Taskfile.js.
const cmd = ['echo', 'Taskfile: ', ...Deno.args];
Deno.run({ cmd });
Y llamamos start de esta manera.
$ deno start hola
Taskfile start hola
Genial. El siguiente paso serÃa crear un Taskfile.js "mÃĄs inteligente," que sea capaz de ejecutar varias tareas. Ya he hecho algo asà en el pasado (pueden encontrar los detalles aquÃ), asà que les mostrarÃĐ el cÃģdigo que yo usarÃa.
const entrypoint = "./src/main.js";
run(Deno.args, {
start(...args) {
exec(["deno", "run", entrypoint, ...args]);
},
list() {
console.log('Available tasks: ');
Object.keys(this).forEach((k) => console.log(`* ${k}`));
},
});
function run([name, ...args], tasks) {
if(tasks[name]) {
tasks[name](...args);
} else {
console.log(`Task "${name}" not found\n`);
tasks.list();
}
}
async function exec(args) {
const proc = await Deno.run({ cmd: args }).status();
if (proc.success == false) {
Deno.exit(proc.code);
}
return proc;
}
Con esto podrÃamos ejecutar el archivo ./src/main.js al invocar deno start. Ahora tenemos otro problema, no queremos escribir todo eso cada vez que queremos iniciar un proyecto. Lo que haremos serÃĄ crear un comando init que copie esta plantilla en la carpeta de nuestro proyecto.
deno()
{
if [ -z "$1" ];then
command deno
return
fi
local cmd=$1; shift;
case "$cmd" in
start)
command deno run --allow-run ./Taskfile.js start $@
;;
+ init)
+ cp /path/to/template/Taskfile.js ./
+ echo "Taskfile.js created"
+ ;;
*)
command deno $cmd $@
;;
esac
}
Ya tiene buena forma. La Última cosa que nos quedarÃa por hacer es manejar otras tareas ademÃĄs de start. Con npm podemos invocar npm run para elegir quÃĐ script queremos ejecutar, nuestro equivalente se llamarÃĄ x.
deno()
{
if [ -z "$1" ];then
command deno
return
fi
local cmd=$1; shift;
case "$cmd" in
+ x)
+ command deno run --allow-run ./Taskfile.js $@
+ ;;
start)
command deno run --allow-run ./Taskfile.js start $@
;;
init)
cp /path/to/template/Taskfile.js ./
echo "Taskfile.js created"
;;
*)
command deno $cmd $@
;;
esac
}
Ahora podrÃamos tener una "tarea" llamada test:api y llamarla de esta manera.
deno x test:api
Un poco mÃĄs de conveniencia
Lo Último que quiero hacer es crear una forma de ejecutar un script el cual pueda llamar las librerÃas que uso con mÃĄs frecuencia sin usar su URL. Podemos hacer esto con el apoyo de un import-map, un archivo .json en el cual podemos vincular un "alias" a una URL.
Yo uso uno como este.
{
"imports": {
"@std/": "https://deno.land/std@0.93.0/",
"@npm/": "https://jspm.dev/",
"ansi-colors": "https://jspm.dev/ansi-colors@4.1.1",
"arg": "https://jspm.dev/arg@5.0.0",
"cheerio": "https://jspm.dev/cheerio@1.0.0-rc.5",
"exec": "https://deno.land/x/exec@0.0.5/mod.ts",
"ramda": "https://jspm.dev/ramda@0.27.1",
"@utils/": "/path/to/deno/utils/"
}
}
deno puede leerlo si le pasamos el argumento --import-map. Ahora vamos a crear un comando para usarlo.
deno()
{
if [ -z "$1" ];then
command deno
return
fi
local cmd=$1; shift;
case "$cmd" in
x)
command deno run --allow-run ./Taskfile.js $@
;;
start)
command deno run --allow-run ./Taskfile.js start $@
;;
init)
cp /path/to/template/Taskfile.js ./
echo "Taskfile.js created"
;;
+ s|script)
+ command deno run --import-map="/path/to/deno/import-map.json" $@
+ ;;
*)
command deno $cmd $@
;;
esac
}
Como ya es costumbre, tenemos que probar esto. Vamos a crear un script de prueba con este contenido.
import dayjs from '@npm/dayjs';
import c from 'ansi-colors';
c.enabled = !Deno.noColor;
const date = dayjs().format('{YYYY} MM-DDTHH:mm:ss SSS [Z] A');
console.log(c.green(date));
Tal vez quieran especificar la versiÃģn de la librerÃa que estÃĄn usando con
@npm, en ese caso harÃan esto@npm/dayjs@1.10.4
Lo ejecutamos.
$ deno script ./test.js
Download https://jspm.dev/dayjs@1.10.4
Download https://jspm.dev/npm:dayjs@1.10.4!cjs
{2021} 04-18T11:28:05 929 Z AM
ÂĄJaja! Ahora tengo todo lo que quiero.
El resultado final
DespuÃĐs de todo este proceso la funciÃģn deno deberÃa quedar asÃ.
deno()
{
if [ -z "$1" ];then
command deno
return
fi
local cmd=$1; shift
case "$cmd" in
x)
command deno run --allow-run ./Taskfile.js $@
;;
start)
command deno run --allow-run ./Taskfile.js start $@
;;
init)
cp /path/to/template/Taskfile.js ./
echo "Taskfile.js created"
;;
s|script)
command deno run --import-map="/path/to/deno/import-map.json" $@
;;
*)
command deno $cmd $@
;;
esac
}
ConclusiÃģn
Entonces, ÂŋquÃĐ hicimos hoy? "Escondimos" el comando deno detrÃĄs de una funciÃģn para poder agregar "sub-comandos" creados por nosotros. Logramos crear una especie de equivalente de npm run para deno y finalmente usamos import maps para simplificar la declaraciÃģn de dependencias en un script. No estÃĄ mal para un dÃa de trabajo.
Gracias por su tiempo. Si este artÃculo les pareciÃģ Útil y quieren apoyar mis esfuerzos para crear mÃĄs contenido pueden dejar una propina en ko-fi.com/vonheikemen.

Top comments (0)