Foi um dia normal de patch. Corrigi e atualizei minhas dependências npm sem fazer alterações no código e, de repente, alguns de meus testes de unidade falharam.
Que merda!
Meus testes falharam porque Jest encontrou um token inesperado; eles falharam porque Jest não consegue lidar com pacotes somente ESM prontos para uso. Na verdade, Jest está escrito em CommonJS.
Mas o que isso significa? Para fazer isso, precisamos entender por que existem CommonJS e ESM.
Nos primeiros dias do desenvolvimento web, JavaScript era usado principalmente para manipular o Document Object Model (DOM) com bibliotecas como jQuery. No entanto, a introdução do Node.js também fez com que o JavaScript fosse usado para programação no lado do servidor. Essa mudança aumentou a complexidade e o tamanho das bases de código JavaScript. Como resultado, surgiu a necessidade de um método estruturado para organizar e gerenciar o código JavaScript. Sistemas de módulos foram introduzidos para atender a essa necessidade, permitindo que os desenvolvedores dividissem seu código em unidades gerenciáveis e reutilizáveis1.
CommonJS foi criado em 2009, originalmente denominado ServerJS2. Ele foi projetado para JavaScript do lado do servidor, fornecendo convenções para definição de módulos. O Node.js adotou o CommonJS como seu sistema de módulos padrão, tornando-o predominante entre os desenvolvedores back-end de JavaScript. CommonJS usa require para importar e module.exports para exportar módulos. Todas as operações em CommonJS são síncronas, o que significa que cada módulo é carregado individualmente.
Em 2015, ECMAScript introduziu um novo sistema de módulos chamado ECMAScript Modules (ESM), visando principalmente o desenvolvimento do lado do cliente. O ESM usa instruções de importação e exportação e suas operações são assíncronas, permitindo que os módulos sejam carregados em paralelo3. Inicialmente, o ESM foi projetado para navegadores, enquanto o CommonJS foi projetado para servidores. Tornou-se cada vez mais um padrão para o ecossistema JS. Hoje em dia, os tempos de execução modernos de JavaScript suportam ambos os sistemas de módulos. Os navegadores começaram a oferecer suporte nativo ao ESM em 2017. Até o Typescript adaptou a sintaxe do ESM e, sempre que você a aprende, também aprende o ESM inconscientemente.
A verdade é que existem muito mais pacotes somente CommonJS (CJS) do que pacotes somente ESM4.
No entanto, há uma tendência clara. O número de pacotes somente ESM ou de módulo duplo está aumentando, enquanto menos pacotes somente CJS estão sendo criados. Esta tendência sublinha a preferência crescente pelo ESM e levanta a questão de quantos pacotes exclusivos do CJS são ativamente mantidos.
Uma comparação interessante entre CommonJS e ESM envolve benchmarks de desempenho. Devido à sua natureza síncrona, o CommonJS é mais rápido ao usar diretamente instruções require e import. Vamos considerar o seguinte exemplo:
// 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' });
Eu usei o aws-sdk S3-Client porque ele tem suporte para módulo duplo. Aqui instanciamos o cliente e depois o executamos com node:
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 você pode ver, o s3-get-files.cjs e, portanto, o CommonJS rodam mais rápido.
Me inspirei no Buns Blogpost.
No entanto, quando você deseja produzir sua biblioteca JS, você precisa agrupá-la. Caso contrário, você enviará todos os node_modules. É usado esbuild porque é capaz de agrupar CJS e ESM. Agora, vamos executar o mesmo benchmark com a versão incluída.
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 você pode ver, o s3-bundle.mjs agora é mais rápido que o s3-bundle.cjs. O arquivo ESM agora é ainda mais rápido do que o arquivo CommonJS desagregado porque resulta em tamanhos de arquivo menores e tempos de carregamento mais rápidos devido à agitação eficiente da árvore – um processo que remove o código não utilizado.
O futuro dos módulos JavaScript está, sem dúvida, inclinado para o ESM. Isso começa ao criar um novo projeto NodeJS ou mesmo um projeto React. Cada tutorial e artigo usa a instrução import—, que é, portanto, ESM. Apesar de muitos pacotes CommonJS existentes, a tendência está mudando à medida que mais desenvolvedores e mantenedores adotam o ESM por seus benefícios de desempenho e sintaxe moderna. Outra questão é também quantos desses projetos exclusivos do CJS ainda são mantidos.
ESM é um padrão que funciona em qualquer tempo de execução, como NodeJS, Bun ou Deno, e no navegador sem rodar em um servidor. Não é necessário converter via Babel para CommonJS porque o navegador entende ESM. Você ainda pode usar o Babel para converter para uma versão diferente do ECMAScript, mas não deve converter para CJS.
Você deve desenvolver apenas em ESM porque todos os tempos de execução atuais e navegadores mais recentes que 2017 entendem ESM.
Se o seu código quebrar, você pode ter problemas legados. Considere usar ferramentas ou pacotes diferentes. Por exemplo, você pode migrar de Jest para vitest ou de ExpressJS para h3. A sintaxe permanece a mesma; a única diferença é a instrução de importação.
Principais conclusões:
Para começar, você pode seguir este Gist ou obter um aprendizado inspirador aqui.
Para um futuro JavaScript melhor, adote o ESM!
A apresentação
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 ↩
Isenção de responsabilidade: Todos os recursos fornecidos são parcialmente provenientes da Internet. Se houver qualquer violação de seus direitos autorais ou outros direitos e interesses, explique os motivos detalhados e forneça prova de direitos autorais ou direitos e interesses e envie-a para o e-mail: [email protected]. Nós cuidaremos disso para você o mais rápido possível.
Copyright© 2022 湘ICP备2022001581号-3