Era un día normal de parcheo. Parché y actualicé mis dependencias de npm sin realizar cambios en el código y, de repente, algunas de mis pruebas unitarias fallaron.
¡Qué carajo!
Mis pruebas fallaron porque Jest encontró un token inesperado; Fallaron porque Jest no puede manejar paquetes exclusivos de ESM listos para usar. De hecho, Jest está escrito en CommonJS.
Pero ¿qué significa eso? Para hacerlo, debemos comprender por qué existen CommonJS y ESM.
En los primeros días del desarrollo web, JavaScript se usaba principalmente para manipular el modelo de objetos de documento (DOM) con bibliotecas como jQuery. Sin embargo, la introducción de Node.js también llevó a que JavaScript se utilizara para la programación del lado del servidor. Este cambio aumentó la complejidad y el tamaño de las bases de código JavaScript. Como resultado, surgió la necesidad de un método estructurado para organizar y gestionar el código JavaScript. Se introdujeron sistemas de módulos para satisfacer esta necesidad, permitiendo a los desarrolladores dividir su código en unidades manejables y reutilizables1.
CommonJS se estableció en 2009, originalmente llamado ServerJS2. Fue diseñado para JavaScript del lado del servidor y proporciona convenciones para definir módulos. Node.js adoptó CommonJS como su sistema de módulos predeterminado, lo que lo hizo prevalente entre los desarrolladores backend de JavaScript. CommonJS utiliza require para importar y module.exports para exportar módulos. Todas las operaciones en CommonJS son sincrónicas, lo que significa que cada módulo se carga individualmente.
En 2015, ECMAScript introdujo un nuevo sistema de módulos llamado ECMAScript Modules (ESM), dirigido principalmente al desarrollo del lado del cliente. ESM utiliza declaraciones de importación y exportación, y sus operaciones son asincrónicas, lo que permite que los módulos se carguen en paralelo3. Inicialmente, ESM estaba destinado a navegadores, mientras que CommonJS estaba diseñado para servidores. Se convirtió cada vez más en un estándar para el ecosistema JS. Hoy en día, los tiempos de ejecución de JavaScript modernos admiten ambos sistemas de módulos. Los navegadores comenzaron a admitir ESM de forma nativa en 2017. Incluso Typecript adaptó la sintaxis de ESM y, cada vez que la aprendes, también aprendes ESM de manera inconsciente.
La verdad es que hay muchos más paquetes exclusivos de CommonJS (CJS) que paquetes exclusivos de ESM4.
Sin embargo, hay una tendencia clara. El número de paquetes de módulo dual o solo ESM está aumentando, mientras que se crean menos paquetes solo CJS. Esta tendencia subraya la creciente preferencia por ESM y plantea la pregunta de cuántos de los paquetes exclusivos de CJS se mantienen activamente.
Una comparación interesante entre CommonJS y ESM involucra puntos de referencia de rendimiento. Debido a su naturaleza sincrónica, CommonJS es más rápido cuando utiliza directamente declaraciones require e import. Consideremos el siguiente ejemplo:
// CommonJS -> s3-get-files.cjs const s3 = require('@aws-sdk/client-s3'); new s3.S3Client({ region: 'eu-central-1' }); // ESM -> s3-get-files.mjs import { S3Client } from '@aws-sdk/client-s3'; new S3Client({ region: 'eu-central-1' });
Utilicé el cliente S3 de aws-sdk porque admite módulos duales. Aquí creamos una instancia del cliente y luego lo ejecutamos con el nodo:
hyperfine --warmup 10 --style color 'node s3-get-files.cjs' 'node s3-get-files.mjs' Benchmark 1: node s3-get-files.cjs Time (mean ± σ): 82.6 ms ± 3.7 ms [User: 78.5 ms, System: 16.7 ms] Range (min … max): 78.0 ms … 93.6 ms 37 runs Benchmark 2: node s3-get-files.mjs Time (mean ± σ): 93.9 ms ± 4.0 ms [User: 98.3 ms, System: 18.1 ms] Range (min … max): 88.1 ms … 104.8 ms 32 runs Summary node s3-get-files.cjs ran 1.14 ± 0.07 times faster than node s3-get-files.mjs
Como puede ver, s3-get-files.cjs y, por lo tanto, CommonJS se ejecutan más rápido.
Me inspiré en Buns Blogpost.
Sin embargo, cuando desees producir tu biblioteca JS, debes empaquetarla. De lo contrario, enviará todos los node_modules. Se utiliza esbuild porque puede integrarse en CJS y ESM. Ahora, ejecutemos el mismo punto de referencia con la versión incluida.
hyperfine --warmup 10 --style color 'node s3-bundle.cjs' 'node s3-bundle.mjs' Benchmark 1: node s3-bundle.cjs Time (mean ± σ): 62.1 ms ± 2.5 ms [User: 53.8 ms, System: 6.7 ms] Range (min … max): 59.5 ms … 74.5 ms 45 runs Warning: Statistical outliers were detected. Consider re-running this benchmark on a quiet system without any interferences from other programs. It might help to use the '--warmup' or '--prepare' options. Benchmark 2: node s3-bundle.mjs Time (mean ± σ): 45.3 ms ± 2.2 ms [User: 38.1 ms, System: 5.6 ms] Range (min … max): 43.0 ms … 59.2 ms 62 runs Warning: Statistical outliers were detected. Consider re-running this benchmark on a quiet system without any interferences from other programs. It might help to use the '--warmup' or '--prepare' options. Summary node s3-bundle.mjs ran 1.37 ± 0.09 times faster than node s3-bundle.cjs
Como puede ver, s3-bundle.mjs ahora es más rápido que s3-bundle.cjs. El archivo ESM ahora es incluso más rápido que el archivo CommonJS desagregado porque genera tamaños de archivo más pequeños y tiempos de carga más rápidos debido a la eficiente agitación de árboles, un proceso que elimina el código no utilizado.
El futuro de los módulos JavaScript sin duda se inclina hacia ESM. Esto comienza al crear un nuevo proyecto NodeJS o incluso un proyecto React. Cada tutorial y artículo utiliza la declaración import, que por lo tanto es ESM. A pesar de que existen muchos paquetes CommonJS, la tendencia está cambiando a medida que más desarrolladores y mantenedores adoptan ESM por sus beneficios de rendimiento y su sintaxis moderna. Otra pregunta es también cuántos de estos proyectos exclusivos de CJS todavía se mantienen.
ESM es un estándar que funciona en cualquier tiempo de ejecución, como NodeJS, Bun o Deno, y en el navegador sin ejecutarse en un servidor. No es necesario realizar la conversión a través de Babel a CommonJS porque el navegador comprende ESM. Aún puedes usar Babel para convertir a una versión diferente de ECMAScript, pero no debes convertir a CJS.
Deberías desarrollar solo en ESM porque ahora todos los tiempos de ejecución y los navegadores posteriores a 2017 entienden ESM.
Si tu código falla, es posible que tengas problemas heredados. Considere utilizar diferentes herramientas o paquetes. Por ejemplo, puedes migrar de Jest a vitest o de ExpressJS a h3. La sintaxis sigue siendo la misma; la única diferencia es la declaración de importación.
Conclusiones clave:
Para comenzar, puedes seguir esta esencia u obtener un aprendizaje inspirador aquí.
¡Para un mejor futuro de JavaScript, adopte ESM!
La presentación
https://www.freecodecamp.org/news/javascript-es-modules-and-module-bundlers/#why-use-modules ↩
https://deno.com/blog/commonjs-is-hurting-javascript ↩
https://tc39.es/ecma262/#sec-overview ↩
https://twitter.com/wooorm/status/1759918205928194443 ↩
Descargo de responsabilidad: Todos los recursos proporcionados provienen en parte de Internet. Si existe alguna infracción de sus derechos de autor u otros derechos e intereses, explique los motivos detallados y proporcione pruebas de los derechos de autor o derechos e intereses y luego envíelos al correo electrónico: [email protected]. Lo manejaremos por usted lo antes posible.
Copyright© 2022 湘ICP备2022001581号-3