Anuncios

Bienvenidos sean a este post, hoy veremos una particularidad de estos dos estandar.

Anuncios

En posts anteriores hemos visto como implementar modulos tanto como CommonJS asi como con ES6 pero hoy nos centraremos en como poder implementarlos juntos, esto es posible ya que estos son similares pero con algunas diferencias y esto es lo que principalmente ocasionara que debamos implementarlos juntos y entender como proceder, nuestra primera intriga es cuales son las extensiones de cada uno y como reconocerlas, analicemos el caso de cuando debemos implementar un modulo ES6:

  • La extension de manera predeterminada es .mjs
  • Si en un paquete json posee un campo con el nombre type y el valor es module, la extension de los archivos debe ser .js
  • Si el nodo binario es ejecutado con el flag –input-type=module y despues cualquier codigo pasado por el argumento –eval, –print o mediante STDIN se interpretara como un modulo ES6
Anuncios

Ahora veamos en que situacion se debe implementar a CommonJS:

  • La extension de manera predeterminada es .js
  • A diferencia del anterior si no tiene unu campo con el nombre type o si contiene un campo type con el valor commonjs el archivo debe llevar la extension .js
  • Al igual que en el caso anterior si el nodo binario posee el flag –type-type o –type-type=commonjs, despues nuevamente cualquier codigo pasado por el argumento –eval, –print o mediante STDIN se interpretara como un modulo CommonJS.
Anuncios
Nota:
Cuando nos referimos a STDIN, es el metodo estandar de entrada por sus siglas en ingles.
Anuncios

Una recomendacion que nos da el equipo de desarrollo de node.js es que siempre debemos pasar el tipo en los archivos .json aunque este sea de tipo CommonJS, vamos a considerar que tenemos un archivo de tipo json:

{
	'type': 'module'
	... resto del archivo
}
Anuncios

Aqui le especificamos que el modulo es de tipo ES6, por lo tanto si tenemos el siguiente comando:

$ node mi-modulo.js
Anuncios

Al ejecutarlo este lo procesara como si fuera un modulo ES6, esto se podria haber logrado de la misma forma sin el archivo json mediante el siguiente comando:

$ node --input-type=module mi-modulo.js
Anuncios

En cambio si en el archivo .json en el campo type tuviera el valor commonjs o en el comando anterior solo hubieramos pasado –input-type o con el valor common.js el modulo se hubiera ejecutado como CommonJS, a su vez estas mismas reglas se aplican tanto a la instruccion import y las funciones import como require, y si bien mas adelante hablaremos sobre esto pero ahora nos centraremos en analizar como la funcion import resuelve parcialmente la imposibilidad de usar modulos ES6 en modulos CommonJS.

Anuncios

Usando modulos ES6 en CommonJS mediante import

Anuncios

En ES6 tenemos la instruccion import la cual al no ser una funcion implica que solo se puede informar una cadena estatica y no puedes computar el identificador del modulo para importar, otra limitacion es que solo trabaja con modulos ES6 impidiendo que se pueda cargar estos desde un modulo CommonJS pero esto se puede hacer? Actualmente si podemos hacerlo porque gracias a que la funcion import esta disponible en ambos estandar por lo tanto podemos importar modulos desde cualquiera de ellos, para entender este concepto vamos a analizar un ejemplo simple, pero para ello debemos reutilizar un codigo que vimos en este post, en este caso usaremos el archivo ejemplo01.mjs y si no lo tienen pueden crearlo y agregarle el siguiente codigo:

ejemplo01.mjs

let contar = 0;

export function proximo() { return ++contar; }

function cuadrado() { return Math.pow(contar, 2); }

export function saludar() {
        return "Hola, como estas?";
}

export default function() { return contar; }
export const valor = 42;
export let nocontar = -1;
export { cuadrado };
Anuncios

Como pueden ver son simplemente algunas funciones que hemos visto en este post pero nos servira para poder importarlas, para ello en el mismo directorio del archivo anterior crearemos otro nuevo con el nombre de import-dinamico.js y le agregaremos el siguiente codigo:

import-dinamico.js

async function funcion()
{
        const ejemplo = await import('./ejemplo01.mjs');
        console.log(ejemplo.saludar());
        console.log(ejemplo.proximo());
        console.log(ejemplo.proximo());
        console.log(`contar = ${ejemplo.default()}`);
        console.log(`valor: ${ejemplo.valor}`);
}

funcion().catch(err => { console.error(err); });
Anuncios
Anuncios

Primero definimos una funcion asincronica, en este primero definiremos una constante donde usaremos a import para importar el archivo anterior, si bien cuando hablamos de las instrucciones import y export en posts anteriores nos referimos a que ellas debian estar en el scope global pero como esta es la funcion no tenemos esta posibilidad y debemos utilizar dentro de la funcion asincronica, despues internamente iremos mostrando el resultado de las llamadas a las funciones importadas del archivo anterior, ojo con la comilla usada en las ultimas dos lineas porque si usan las simples no funcionara, por ultimo usamos a catch con la funcion asincronica por si ocurre algun error y lo mostraremos en pantalla, probemos de ejecutarlo para ver como funciona:

tinchicus@dbn001vrt:~/lenguajes/node.js$ node import-dinamico.js
Hola, como estas?
1
2
contar = 2
valor: 42
tinchicus@dbn001vrt:~/lenguajes/node.js$
Anuncios
Anuncios

Aca como pueden ver obtuvimos los resultados de la llamada desde un modulo CommonJS a las contenidas en un modulo ES6, una cosa mas que debemos mencionar es que la instruccion import es asincronica, por lo tanto por extension la funcion import tambien lo es pero la funcion require es sincronica, un detalle que no mencionamos fue el await del import es que lo necesitamos para que se ajuste al async de la funcion que lo contiene, pero si aun pudieramos usarlo en el scope global seria realmente dificil conseguir que una variable global contenga la referencia a ese modulo, tomemos todo el codigo anterior y modifiquemoslo de la siguiente manera:

const ejemplo = import('./ejemplo01.mjs');
console.log(ejemplo);
console.log(ejemplo.saludar());
console.log(ejemplo.proximo());
console.log(ejemplo.proximo());
console.log(`contar = ${ejemplo.default()}`);
console.log(`valor: ${ejemplo.valor}`);
Anuncios

En este caso basicamente lo que hicimos fue tomar el codigo anterior y lo metimos en un scope global, por lo tanto ya no podemos implementar el await y a su vez agregamos una linea mas para mostrar como esta la constante ejemplo, si lo ejecutamos obtendremos la siguiente salida:

tinchicus@dbn001vrt:~/lenguajes/node.js$ node import-dinamico.js
Promise { <pending> }
/home/tinchicus/lenguajes/node.js/import-dinamico.js:3
console.log(ejemplo.saludar());
                    ^

TypeError: ejemplo.saludar is not a function
    at Object.<anonymous> (/home/tinchicus/lenguajes/node.js/import-dinamico.js:3:21)
    at Module._compile (node:internal/modules/cjs/loader:1241:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1295:10)
    at Module.load (node:internal/modules/cjs/loader:1091:32)
    at Module._load (node:internal/modules/cjs/loader:938:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:83:12)
    at node:internal/main/run_main_module:23:47

Node.js v20.6.1
tinchicus@dbn001vrt:~/lenguajes/node.js$
Anuncios
Anuncios

Observen como esta la promesa pendiente para el objeto ejemplo, por lo tanto no tenemos ninguna referencia a este y esto provoca que no podemos acceder a las funciones y variables de este, una opcion para solucionarlo puede ser el uso de then y catch para la funcion import, esto hara que se termine la promesa de forma exitosa o no, pero ahora el modulo cargado estara dentro de la funcion callback, aunque sobre esto hablaremos en otro post por lo tanto guarden este ejemplo que lo revisitaremos.

Anuncios

En resumen, hoy hemos visto un ejemplo de como podemos implementar un modulo de ES6 desde un modulo CommonJS, tambien hemos visto algunas similitudes y declaraciones que debemos tener en cuenta para una correcta ejecucion, espero les haya sido de utilidad sigueme en tumblr, Twitter o Facebook para recibir una notificacion cada vez que subo un nuevo post en este blog, nos vemos en el proximo post.

Anuncios

Donación

Es para mantenimento del sitio, gracias!

$1.50