Os módulos permitem que blocos de código como funções, classes e constantes em arquivos separados possam ser importados quando necessário, facilitando o processo de manutenção e reusabilidade de um projeto JavaScript.

Antes desse recurso era necessário declarar variáveis globais em arquivos .js que, quando adicionados a mesma página, permitiam que essas variáveis passassem a fazer parte do mesmo contexto. Com os módulos o conteúdo de um arquivo pode ser exportado para outro, assim como fazemos com include/require no PHP, por exemplo.

Sintaxe

No arquivo no qual declaramos o recurso que desejamos compartilhar usamos a instrução export:

export [o-que-queremos-compartilhar]

Agora, no arquivo em que desejamos utilizar o recurso compartilhado usamos a instrução import:

import [o-que-queremos-importar] from [nome-do-modulo]

Como utilizar?

Para entender melhor, considere como exemplo uma calculadora simples, onde criamos dois arquivos. O primeiro, util.mjs armazena e exporta algumas funções que podem ser re-utilizadas em diversos locais do projeto e tem o seguinte conteúdo:

/**
 * resultado aproximado de uma circunferência de diâmetro igual a 20.000
 * 
 * @type {number}
 */
export const PI = Math.PI // 3.141592653589793

/**
 * recebe por parâmetro uma quantidade indefinida de números e efetua a soma dos
 * mesmos.
 *
 * @param {number[]} params
 * @returns {number} valor soma dos parâmetros
 */
export function soma (...params) {
 return params.reduce((a, b) => a + b, 0)
}

Perceba no código acima o uso da palavra export precedendo a constante PI e a função soma. Isso significa que ambos os itens podem ser acessados de fora de seus escopos (arquivo), desde que tenham sido importados.

Para fazer a importação utilizamos o segundo arquivo da nossa calculadora, o index.mjs, que é o ponto de partida da nossa aplicação. Vamos importar do arquivo util.mjs a função soma assim como vemos no código abaixo:

import { soma } from './util.mjs'
console.log(soma(10, 20, 30)) // 60

Na linha 1 utilizamos a palavra reservada import, e em chaves o nome da função que será importada, no caso, soma. Por fim, é utilizada a palavra from onde informamos o nome do pacote (no caso do Node.js) ou do arquivo.

É importante lembrar que todas as funções, classes, constantes, etc. são importados como constantes.

Arquivos mjs são arquivos JavaScript com suporte a módulos, ou seja, facilitam a distinção entre arquivos tradicionais e com suporte a módulos.

Quais as variações da sintaxe do import e export?

Existem algumas variações na sintaxe dos módulos, veremos em pequenos exemplos como são estas variações.

1. exportando e importando o conteúdo default

Podemos definir um item do módulo como default, ou seja, quando utilizarmos o import sem utilizar chaves estaremos recuperando este item, por exemplo:

export default const soma = (...params) => params.reduce((a, b) => a + b, 0)

Perceba que neste exemplo utilizamos o prefixo default após a palavra import, significando que este item é o padrão do pacote. É importante lembrar que apenas um único item pode ser exportado como default.

Abaixo vemos como acessar um item definido como default:

import sum from 'pacote'

Perceba que a palavra sum não está entre chaves. Além disso, é possível definir qualquer nome para o item porque como default ele não é exportado com um nome.

2. importando um único item

No exemplo a seguir importamos um único item do escopo de outro arquivo. Perceba que dentro das chaves é definido apenas o nome da função que será utilizada:

import { soma } from './util.mjs'

3. importando vários itens

Podemos também importar uma quantidade indefinida de itens com o import. Para isso basta utilizar chaves e o nome dos itens separados por virgula, como vemos abaixo:

import { soma, PI } from './util.mjs'

4. importando o default e outros itens

Podemos importar junto com o default os itens nomeados que exportamos. Para isso basta fazer como no exemplo abaixo:

import sum, { soma, PI } from './util.mjs'

5. definindo um aliás para um item

É possível definir um apelido para um item importado, o que podemos ver melhor no exemplo abaixo:

import { soma as somaDeTodosOsValores } from './util.mjs'

É importante lembrar que esta sintaxe só funciona nos itens entre as chaves, como no exemplo, soma e PI.

6. importando apenas o arquivo.

Podemos também importar de um arquivo JavaScript sem trazer nenhum item de seu escopo. Essa prática é comum quando precisamos que um script seja executado sem poluir o escopo atual, funcionando como se estivesse sendo executado em segundo plano:

import './outroScript.js'

7. importando todos os itens de um pacote

É comum a necessidade de importar todos os itens em um pacote. Para isso os módulos contam com a seguinte sintaxe:

import * as utils from './util.mjs'
console.log(utils) // { soma, PI }

É importante lembrar que neste tipo de importação o default não é retornado junto com o resto do pacote.

Como testar os módulos no navegador?

Para utilizar na maioria dos navegadores web, basta criar um arquivo HTML e um outro com formato .mjs. Isso significa que é um arquivo JavaScript e suporta os módulos. Em seguida, no JavaScript crie uma tag script, lembrando de informar o nome do seu arquivo mjs no src e o type como module, como podemos ver abaixo:

<script type="module" src="index.mjs"></script>

A partir deste momento, enquanto estiver em um navegador que dê suporte ao recurso será possível utilizar a sintaxe de módulos.

Compatibilidade

Engine Versão Minima
Node.JS ( V8) 8.5.0
Safari ( WebKit) 11.4
Chrome ( V8) 68
Microsoft Edge ( ChakraCore) 17
Firefox ( Gecko) 61
  • No Node.js os módulos ainda estão em estágio experimental.

Nota: O Opera atualmente é um fork do Google Chrome e, por isso, o mesmo foi desconsiderado da lista. Caso você o utilize, verifique na documentação do mesmo se a versão atual possui suporte ao recurso mencionado aqui. É importante lembrar a versão atual do Chrome não equivale a última versão do Opera.

Saiba mais Veja a Série O JavaScript está dominando o mundo?