Escolha uma Página

Se você quer uma tabela rápida de comparações ela está abaixo:

Resumo das Diferenças

AspectoCommonJSESModules
Sintaxe de Importaçãorequire('modulo')import modulo from 'modulo.js'
Sintaxe de Exportaçãomodule.exports = objetoexport / export default
CarregamentoSincrônicoAssíncrono
SuporteTodos os Node.js Navegadores modernos e Node.js a partir da versão 12.
Análise estáticaNão suportadoSuportado
Tree ShakingNão suportadoSuportado
Suporte DinâmicoSuporta importação dinâmica via require()Suporta via import()
Extensão.js.mjs ou .js (com "type": "module")
Tabela comparativa entre as principais diferenças de CommonJS (CJS) e ESModules (ESM)

Quem veio primeiro?

O CommonJS (CJS) veio antes do EcmaScript Modules (ESM), e se trata de um padrão de módulos utilizado pelo Node.js desde a sua primeira versão em 2009. O EcmaScript Modules (ESM) foi lançado apenas em 2015 como parte do ECMAScript 6, e é a especificação padrão e oficial de módulos para o JavaScript desde então.

Podemos então dizer que o CJS supriu a demanda por um forma de exportar e importar módulos no Node.Js, até que a própria linguagem JavaScript implementasse um modo para isso.

As diferenças entre CJS e ESM estão relacionadas ao modo como os módulos são definidos e utilizados. Vamos ver em breve em detalhes as diferenças entre eles.

Trabalhando com arquivos em diferentes diretórios

Antes de irmos para as sintaxes dos códigos, vamos ver algo básico que pode te pegar, que é a forma de lhe dar com a disposição entre arquivos. Isso é importante em um projeto onde vamos exportar e importar arquivos de diferentes lugares.

Em um típico ambiente Linux, onde geralmente se rodas aplicações web, ao navegar entre arquivos um único ponto (.) representa o diretório atual, enquanto dois pontos (..) representam o diretório acima.

Agora imaginemos o seguinte cenário:

my-app/
├─ moduleHello.js
├─ index.js

Então de dentro do arquivo index.js para chamar o módulo moduleHello.js devemos escrever ./moduleHello.js. Pois usando o ponto único (.) você disse que a partir do diretório atual, quer indicar o caminho para moduleHello.js.

Digamos agora que nosso arquivo de módulo para uma melhor organização foi colocado dentro de um diretório chamado “modules“, destinado a guardar módulos, fora do diretório “my-app”. Veja isso a seguir:

my-app/
├─ index.js
modules/
├─ moduleHello.js

Para chamar um arquivo em um diretório ao lado ou acima do nosso, vamos usar os dois pontos (..) para subir um diretório, saindo do atual, e então indicar o caminho para o arquivo que queremos. Neste caso do arquivo index.js a chamada para o módulo fica ../modules/module.js.

Por fim, se percebeu pelo programador que seria melhor deixar o novo diretório de módulos dentro do diretório do projeto my-app.

A árvore de diretórios agora está assim:

my-app/
├─ modules/
│ ├─ moduleHello.js
├─ index.js

Para indicar um arquivo que está em um diretório mais abaixo, dentro do mesmo diretório onde o arquivo de chamada está, vamos também usar o ponto único (.), afinal vamos partir do mesmo diretório da chamada. Neste caso use então em index.js a chamada ./modules/moduleHello.js.

Entendido como chamar um arquivo em diferentes disposições, vamos prosseguir para as diferenças entre CommonJS (CJS) e ESModules (ESM).

Sintaxe de Exportação e Importação

  • CommonJS usa module.exports ou exports para exportar módulos e require() para importá-los.
  • ESModules usa export para exportar módulos e import para importá-los.

Exportação e Importação de um módulo com CJS

//Exportando um módulo com CJS
function hello() { 
  console.log("hello world")
}
module.exports = { hello };
//Importando um módulo com CJS
const myHelloModule = require('./modules/moduleHello.js');
myHelloModule.hello();

Exportação e Importação de um módulo com ESM

// Exportando um módulo com ESM
export const myFunction = () => { /* code here */ };
export const myVar = 42;

// Importando um módulo com ESM
import myModule from './myModule.js';

Ambiente de Execução

  • CommonJS foram desenvolvidos para o Node.js, então são quase que exclusivamente encontrados em código de backend, salva exceções quando algum programador os adapta para rodar em navegador web.
  • ESModules são uma especificação nativa do JavaScript (ECMAScript 6), por tanto foram projetados para funcionar em navegadores. No entanto, o Node.js a partir de sua versão 12 suporta os suporta. bastando a extensão de um arquivo com ESModules terminar com .mjs ou especificando "type": "module" no package.json).

Comportamento do Carregamento de Módulos

  • CommonJS são carregados de forma sincrônica. Isso significa que até o módulo ser carregado e executado todos os recursos amarrados a esta chamada ficarão aguardando o final da requisição. Além ao importar vários módulos eles serão importados e carregador um após o outro.
  • ESModules são carregados de forma assíncrona, o que signifca que o fluxo da sua aplicação não ficará interrompido até um módulo terminar de ser carregado. Além disso vários ESModules podem ser importados ao mesmo tempo.