Módulos CommonJS vs. ES y Node.js

Nota del editor : Este artículo fue actualizado por última vez por Pascal Akunne el 6 de junio de 2024 para discutir cómo las últimas versiones de Node admiten los módulos ES y ofrecer una breve evolución de los módulos de JavaScript, una línea de tiempo desde IIFE hasta los módulos ES.
En el desarrollo de software moderno, los módulos organizan el código en fragmentos independientes que conforman una aplicación más grande y compleja. En el ecosistema JavaScript de los navegadores, el uso de módulos JavaScript depende de las sentencias import
“` y export
“; estas sentencias cargan y exportan módulos ECMAScript (o módulos ES), respectivamente.
El formato del módulo ES es el formato estándar oficial para empaquetar código JavaScript para su reutilización, y la mayoría de los navegadores web modernos admiten los módulos de forma nativa.
Sin embargo, Node.js admite el formato de módulo CommonJS por defecto. Los módulos CommonJS se cargan con require
, y las variables y funciones se exportan desde un módulo CommonJS con .module.exports
El formato de módulo ES se introdujo en Node.js v8.5.0 con la estandarización del sistema de módulos JavaScript. Al ser un módulo experimental, la bandera era necesaria para ejecutar correctamente un módulo ES en un entorno Node.js. Sin embargo, Node.js ofrece compatibilidad estable con módulos ES desde la versión 13.2.0.--experimental-modules
Este artículo no cubrirá mucho sobre el uso de ambos formatos de módulos, sino más bien cómo se compara CommonJS con los módulos ES y por qué es posible que desees usar uno en lugar del otro.
- La evolución de los módulos de JavaScript
- Sintaxis de los módulos CommonJS vs. ES
- Pros y contras de usar módulos ES y módulos CommonJS en Node.js
- Compatibilidad de Node.js con módulos ES
- CommonJS carga los módulos sincrónicamente, los módulos ES son asincrónicos
- Conclusión: ¿Módulos CommonJS o ES?
- Solo el monitor 200s falló y las solicitudes de red fueron lentas en producción
La evolución de los módulos de JavaScript
Antes de comenzar a comprender las diferencias entre la sintaxis de los módulos CommonJS y ES, exploremos brevemente la historia y la evolución de los módulos JavaScript.
Los módulos de JavaScript han evolucionado enormemente a lo largo de los años, desde el IIFE, que evita la contaminación global del ámbito global y permite la encapsulación de código, hasta el patrón Módulo, que proporciona una separación más clara entre los componentes privados y públicos de un módulo, solucionando así la creciente complejidad de las aplicaciones JavaScript. Sin embargo, tanto los IIFE como los patrones Módulo carecían de una forma estándar de gestionar las dependencias, lo que requería mejores soluciones de desarrollo.
Los principios esenciales de una buena página de inicioCommonJS se diseñó principalmente para el desarrollo del lado del servidor con Node.js. Implementaba la carga síncrona mediante require
y . Por otro lado, la Definición de Módulo Asíncrono (AMD) se centra en entornos de navegador con carga asíncrona mediante y , lo que mejoró el tiempo de carga y la capacidad de respuesta de las páginas. Aun así, siempre se necesitaron mejores soluciones. La necesidad de una solución que funcionara tanto en el servidor como en el navegador impulsó el desarrollo de la Definición Universal de Módulo (UMD).module.exports
define
require
Posteriormente llegaron los módulos ES, que proporcionan un sistema de módulos nativo para JavaScript tanto del lado del cliente como del servidor. Los módulos ES6 ofrecen una sintaxis clara, instrucciones de importación y exportación, y compatibilidad con la carga asíncrona. Este progreso ha hecho que el código sea más fácil de mantener, reutilizable y de alto rendimiento, lo que permite a los desarrolladores crear aplicaciones más escalables.
En los inicios de JavaScript, no existía un sistema de módulos integrado. El código se escribía en un ámbito global, lo que hacía que las funciones y variables fueran accesibles globalmente, lo que generaba conflictos de nombres y bases de código complejas. La falta de encapsulación y modularidad dificultaba a los desarrolladores la reutilización del código en múltiples proyectos.
La evolución de los módulos de JavaScript ha dado como resultado un enfoque más organizado y fácil de mantener para escribir código, lo que permite la encapsulación y gestión efectiva de las dependencias del código.
Cómo elaborar una declaración de posicionamiento convincente con ejemplosSintaxis de los módulos CommonJS vs. ES
De forma predeterminada, Node.js trata el código JavaScript como módulos CommonJS. Por ello, los módulos CommonJS se caracterizan por la require
declaración para la importación y la exportación de módulos.module.exports
Por ejemplo, este es un módulo CommonJS que exporta dos funciones:
módulo .exports .add = función ( a , b ) { return a + b ; } módulo . exportaciones . reiniciar = función ( a , b ) { devolver a - b ; }
También podemos importar las funciones públicas a otro script Node.js usando require
, tal como lo hacemos aquí:
const { sumar , reiniciar } = requerir ( './util' ) consola.log ( suma ( 5 , 5 ) ) // 10 consola.log ( resta ( 10 , 5 ) ) // 5
Si estás buscando un tutorial más detallado sobre los módulos CommonJS, consulta este .
Por qué la investigación de usuarios necesita evolucionarPor otro lado, los autores de bibliotecas también pueden habilitar módulos ES en un paquete Node.js simplemente cambiando las extensiones de archivo de a . Por ejemplo, aquí se muestra un módulo ES simple (con una extensión) que exporta dos funciones para uso público:.js
.mjs.
.mjs
// util.mjsfunción de exportación add ( a , b ) { return a + b ; } función de exportación restablecer ( a , b ) { devolver a - b ; }
Luego podemos importar ambas funciones usando la import
declaración:
// aplicación.mjsimportar { sumar , reiniciar } de './util.mjs' consola.log ( suma ( 5 , 5 ) ) // 10 consola.log ( resta ( 10 , 5 ) ) // 5
Otra forma de habilitar módulos ES en tu proyecto puede ser agregando un "type: module"
campo dentro del archivo más cercano (la misma carpeta que el paquete que estás creando):package.json
{ "nombre" : "mi-biblioteca" , "versión" : "1.0.0" , "tipo" : "módulo" , // ... }
Con esta inclusión, Node.js trata todos los archivos dentro de ese paquete como módulos ES, y no tendrás que cambiar la extensión del archivo. Puedes obtener sobre los módulos ES aquí ..mjs
Como alternativa, puedes instalar y configurar un transpilador como Babel para compilar la sintaxis de tu módulo ES a la sintaxis CommonJS. Proyectos como React y Vue son compatibles con los módulos ES porque usan Babel internamente para compilar el código .
Pros y contras de usar módulos ES y módulos CommonJS en Node.js
El formato de módulo ES se creó para estandarizar el sistema de módulos JavaScript. Se ha convertido en el formato estándar para encapsular código JavaScript y reutilizarlo.
Por otro lado, el sistema de módulos CommonJS está integrado en Node.js. Antes de la introducción del módulo ES en Node.js, CommonJS era el estándar para los módulos de Node.js. Por ello, existen numerosas bibliotecas y módulos de Node.js escritos con CommonJS.
Para la compatibilidad con navegadores, todos los navegadores principales admiten la sintaxis del módulo ES y se puede usar import
/ export
en frameworks como React y Vue.js. Estos frameworks utilizan un transpilador como Babel para compilar la sintaxis import
/ export
a require
, compatible de forma nativa con versiones anteriores de Node.js.
Además de ser el estándar para los módulos JavaScript, la sintaxis del módulo ES es mucho más legible que la de require
. Los desarrolladores web que escriben principalmente JavaScript en el cliente no tendrán problemas para trabajar con módulos Node.js gracias a la misma sintaxis.
Compatibilidad de Node.js con módulos ES
Si bien los módulos ES se han convertido en el formato estándar de módulos en JavaScript, los desarrolladores deben tener en cuenta que las versiones anteriores de Node.js carecen de compatibilidad (en concreto, Node.js v9 y anteriores). En otras palabras, el uso de módulos ES hace que una aplicación sea incompatible con versiones anteriores de Node.js que solo admiten módulos CommonJS (es decir, la require
sintaxis).
Pero con las nuevas exportaciones condicionales, podemos crear bibliotecas de modo dual. Estas bibliotecas se componen de los módulos ES más recientes, pero también son retrocompatibles con el formato de módulo CommonJS compatible con versiones anteriores de Node.js. En otras palabras, podemos crear una biblioteca que admita tanto import
y require
, lo que nos permite resolver problemas de compatibilidad.
Considere el siguiente proyecto Node.js:
mi - nodo - biblioteca ├── lib / │ ├── navegador - lib . js (formato iife) │ ├── módulo -a . js (formato commonjs) │ ├── módulo -a . mjs (formato de módulo es6) │ └── privado / │ ├── módulo - b. js │ └── módulo - b . paquete mjs ├──. json └── …
Dentro , podemos usar el campo para exportar el módulo público ( ) en dos formatos de módulo diferentes mientras restringimos el acceso al módulo privado ( ):package.json
exports
module-a
module-b
// paquete . json { "nombre" : "mi-biblioteca" , "exportaciones" : { "." : { "navegador" : { "predeterminado" : "./lib/browser-module.js" } }, "módulo-a" : { "importación" : "./lib/module-a.mjs" "requerir" : "./lib/module-a.js" } } }
Al proporcionar la siguiente información sobre nuestro paquete, ahora podemos usarlo en cualquier lugar donde sea compatible, de la siguiente manera:my-library
// Para CommonJS const moduleA = require ( 'mi-biblioteca/modulo-a' )// Para el módulo ES6, importa el módulo A desde 'my-library/module-a' // Esto no funcionará const moduleA = require ( 'mi-biblioteca/lib/módulo-a' ) import moduleA from 'mi-increíble-lib/lib/pública-módulo-a' const moduleB = require ( 'mi-biblioteca/privada/módulo-b' ) import moduleB from 'mi-biblioteca/privada/módulo-b'
Gracias a las rutas en exports
, podemos importar (y require
) nuestros módulos públicos sin especificar rutas absolutas. Al incluir las rutas para y , podemos solucionar el problema de incompatibilidad; podemos mapear los módulos de los paquetes para diferentes entornos, como el navegador y Node.js, a la vez que restringimos el acceso a los módulos privados..js
.mjs
Sin embargo, es importante recordar que para que Node.js trate un módulo como un módulo ES, debe ocurrir una de las siguientes cosas: la extensión del archivo del módulo debe convertirse de (para CommonJS) a (para módulos ES) o debemos establecer un campo en el archivo más cercano..js
.mjs
{"type":
"module"}
package.json
En este caso, todo el código de ese paquete será tratado como módulos ES y se deberán utilizar las declaraciones import
/ en lugar de .export
require
En los últimos años, se han lanzado versiones de Node.js que han pasado del sistema de módulos CommonJS tradicional al sistema de módulos ES, lo que permite a los desarrolladores utilizar la importación y la exportación de forma nativa dentro de sus proyectos Node.js.
Este cambio mejora la experiencia de desarrollo para JavaScript, tanto del lado del cliente como del servidor, facilitando el intercambio y la reutilización de código. Además, existe interoperabilidad entre los módulos ES y CommonJS, lo que permite a los desarrolladores importar dinámicamente módulos CommonJS mediante la import
función, garantizando así que las bibliotecas y bases de código existentes sigan funcionando durante la transición a los módulos ES.
Además, las bibliotecas estándar de Node.js (como fs, http y url) ahora admiten la sintaxis del módulo ES, lo que permite a los desarrolladores usar las API nativas de Node.js mediante declaraciones de importación. Por ejemplo, se puede importar el fs
módulo para usar la API basada en promesas para operaciones asincrónicas con archivos.
CommonJS ofrece flexibilidad con las importaciones de módulos
En un módulo ES, la instrucción import solo se puede llamar al principio del archivo. Llamarla en cualquier otro lugar desplaza automáticamente la expresión al principio del archivo o incluso puede generar un error. Por otro lado, la require
función se analiza en tiempo de ejecución. Por lo tanto, require
se puede llamar en cualquier parte del código. Se puede usar para cargar módulos de forma condicional o dinámica desde if
instrucciones, bucles condicionales y funciones.
Por ejemplo, puedes llamar require
dentro de una declaración condicional de la siguiente manera:
if ( usuario . longitud 0 ){ const detallesUsuario = require ( './DetallesUsuario . js ' ) ; // Hacer algo .. }
Aquí cargamos un módulo que se llama userDetails
solo si hay un usuario presente.
CommonJS carga los módulos sincrónicamente, los módulos ES son asincrónicos
One of the limitations of using require
is that it loads modules synchronously, which means that modules are loaded and processed one by one. A task can only begin once the preceding one is completed. This is known as “blocking” because if an operation takes a long time to complete, it prevents the following tasks from starting.
Sync code is simple to write and read, and it follows a threaded execution model, making it easier to predict the code flow and result. However, it can cause serious performance issues because sync loading can cause an entire application or program to freeze or become unresponsive, particularly in scenarios involving I/O operations, long computations, or real-time responsiveness, resulting in poor user experience and scalability.
En tal caso, import
podría tener un rendimiento superior require
gracias a su comportamiento asincrónico. Sin embargo, la naturaleza síncrona de [nombre del sistema] require
podría no ser un gran problema para una aplicación a pequeña escala que utilice un par de módulos.
Por otro lado, las operaciones asincrónicas suelen ejecutarse mediante devoluciones de llamada, promesas o sintaxis async/await. El código asincrónico, a diferencia del síncrono, puede ser más difícil de leer, escribir y depurar, ya que no es lineal. Sin embargo, ofrece una mejor experiencia de usuario, ya que funciona bien en aplicaciones web con mucho tráfico que no tienen que esperar su turno para ejecutarse.
Conclusión: ¿Módulos CommonJS o ES?
Para los desarrolladores que aún usan una versión anterior de Node.js, adoptar el nuevo módulo ES sería poco práctico debido al soporte limitado, que podría hacer que una aplicación sea incompatible con versiones anteriores de Node.js.
Sin embargo, para principiantes, aprender módulos ES resulta beneficioso, ya que se están convirtiendo en el formato estándar para definir módulos en JavaScript, tanto del lado del cliente como del servidor. Para nuevos proyectos Node.js, los módulos ES ofrecen una buena alternativa a CommonJS. El formato de módulos ES facilita la escritura de JavaScript isomórfico, que puede ejecutarse tanto en el navegador como en un servidor.
En definitiva, los módulos ECMAScript son el futuro de JavaScript.
Solo el monitor 200s falló y las solicitudes de red fueron lentas en producción
Implementar una aplicación web o un sitio web basado en Node es la parte fácil. Asegurarse de que la instancia de Node siga proporcionando recursos a la aplicación es la parte más difícil. Si le interesa garantizar que las solicitudes al backend o a servicios de terceros se ejecuten correctamente, pruebe LogRocket.
Si quieres conocer otros artículos parecidos a Módulos CommonJS vs. ES y Node.js puedes visitar la categoría Guias.
Entradas Relacionadas