Os módulos do EcmaScript (ESM) já são suportados em vários browsers, porém, no Node.js essa implementação não é tão simples quanto parece, dadas as complexidades em manter a compatibilidade com o CommonJS (para quem quiser entender melhor sugiro este artigo e este ) a comunidade demorou muito para chegar a um acordo sobre como seria feita essa implementação no Node.
Agora, felizmente, já temos uma especificação definida de como será a implementação do ESM e também uma possível data para a release do Node 10 que será em Abril de 2018. Obviamente não precisamos esperar até lá para para utilizar essas novas funcionalidades, até agora utilizamos o Babel para transpilar o código para uma versão suportada permitindo assim usar as features do ESM como por exemplo import/export.
No dia 10 de Agosto a galera da Microsoft anunciou o @std/esm que é introduzido nesse artigo. O @std/esm é um module loader que promete ser o mais fiel possível a especificação original definida pelo Node.js.
Daí vocês me perguntam: mas é necessário mesmo migrar para o padrão do ESM? Bom, dentre as várias características do ESM tem uma em específico que é a grande chave para diferenciar módulos CommonJS e ESM, que é a extensão .mjs. Sim, todos módulos terão essa extensão. Se você estiver se perguntando algo do tipo “WTF? Mas que #@!#!”, leia os artigos que linkei no início do post e entenda que essa decisão veio após anos de discussão.
Sendo assim, o quanto antes podermos adotar o padrão melhor, mesmo que ele só esteja disponível oficialmente em 2018 e a versão do Node 8 LTS vá até 2020 devemos pensar que essa migração pode ter grande impacto no nosso código, e o quanto antes nos adaptarmos mais seguro será. Já era possível fazer isso através do Babel, mas sem contar com todas as funcionalidades da especificação, além disso, o @std/esm funciona de forma diferente do Babel, que pega o código e transpila para CommonJS, já o @std/esm realiza as transformações necessárias sob demanda, processando e fazendo cache de arquivos em tempo de execução.
“Unlike existing ESM solutions which require shipping transpiled CJS, @std/esm performs minimal, inline source transformations on demand, processing and caching files at runtime. Processing files at runtime has a number of advantages.”
Fonte: https://medium.com/web-on-the-edge/es-modules-in-node-today-32cff914e4b
Na prática
A utilização do @std/esm é bastante simples, basta realizar os seguintes passos:
No terminal:
npm i --save @std/esm
Antes de importar os módulos ESM:
require("@std/esm")
Vamos ver na prática como vocês poderiam fazer nas suas próprias aplicações:
Aqui, tenho uma aplicação express com um módulo main.mjs:
Note que o trecho acima já utiliza as funcionalidades do ESM, como o import e o export. Ele também faz a importação de um módulo chamado Math, um módulo de exemplo criado por mim, que possui o seguinte código:
O nome do arquivo onde esse módulo foi salvo é math.mjs, note que para importar não é necessário adicionar a extensão mjs, isso porque o import já busca por essa extensão, não será possível usar import em arquivos .js seguindo a especificação.
Para que o suporte ao ESM funcione basta carregar o main.mjs como no arquivo index.js detalhado a seguir:
No exemplo acima eu dou um require no @std/esm e depois um require no meu main.mjs chamando o default, dessa maneira o @std/esm vai cuidar do resto, e minha aplicação já está suportando ESM sem precisar de um transpiler.
Além do import e export o @std/esm oferece suporte à:
Ele também possui algumas features que ajudam na migração para o ESM que podem ser vistas aqui.
O código de exemplo utilizado está nesse repositório.
Referências:
https://medium.com/web-on-the-edge/es-modules-in-node-today-32cff914e4b
https://medium.com/@nodesource/es-modules-and-node-js-hard-choices-2b6995e4d491
https://medium.com/webpack/the-state-of-javascript-modules-4636d1774358