Desenvolvimento

Desenvolvimento

Suportando módulos Ecmascript (ESM) no Node.js sem Babel

25 set, 2017
Publicidade

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 esse artigo e esse), 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 à especificação original definida pelo Node.js.

Daí vocês me perguntam: é 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 os módulos terão essa extensão. Se você estiver se perguntando algo do tipo “mas o que é isso?”, leia os artigos que linkei no início do artigo e entenda que essa decisão veio após anos de discussão. Sendo assim, o quanto antes pudermos 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:

import Math from './math';
import express from 'express';
const app = express();

app.get('/sum', function (req, res) {
    res.send(`The sum is ${Math.sum(1,1)}`)
});

app.listen(3000, function () {
    console.log('Example app listening on port 3000!')
});

export default app;

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:

const math = {
  sum(n1,n2) {
    return n1+n2;
  }
};

export default math;

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:

require("@std/esm")
module.exports = require("./main.mjs").default

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