Desenvolvimento

25 set, 2017

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

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