W3docs

JavaScript export e import

Aprenda export e import no JavaScript: exportações nomeadas, padrão, renomeação com as, importações de namespace, dinâmicas e reexportações.

No JavaScript moderno, as palavras-chave export e import são a forma de dividir um programa em vários arquivos e depois uni-los novamente. Um arquivo que as utiliza é um módulo ES: em vez de colocar tudo em um único script gigante, você mantém cada parte da funcionalidade em seu próprio arquivo, declara o que compartilha com o mundo externo (export) e importa apenas o que precisa em outros lugares (import).

Este guia cobre todas as formas que você encontrará na prática — exportações nomeadas, exportações padrão, renomeação com as, importações de namespace, reexportação e import() dinâmico — além dos erros comuns que pegam as pessoas de surpresa. Cada exemplo é pequeno e executável.

Por que usar módulos?

Antes dos módulos ES, compartilhar código significava adicionar coisas ao objeto global e torcer para que os nomes não colidissem. Os módulos resolvem isso:

  • Encapsulamento — qualquer coisa que você não exportar permanece privada ao arquivo.
  • Dependências explícitas — as linhas de import no topo de um arquivo são uma lista precisa do que ele depende.
  • Avaliação única — o código de nível superior de um módulo é executado apenas uma vez, independentemente de quantos arquivos o importem; o resultado é armazenado em cache e compartilhado.

Para executar módulos no navegador, carregue seu arquivo de entrada com type="module":

<script src="app.js" type="module"></script>

No Node.js, nomeie os arquivos com .mjs ou defina "type": "module" no package.json.

Exportações nomeadas

Uma exportação nomeada disponibiliza um vínculo com seu próprio nome. Um módulo pode ter quantas exportações nomeadas quiser.

// math.js
export const PI = 3.14159;

export function add(a, b) {
  return a + b;
}

// You can also list exports at the bottom:
const subtract = (a, b) => a - b;
export { subtract };

Você importa exportações nomeadas entre chaves, usando exatamente os mesmos nomes:

// app.js
import { add, PI } from './math.js';

console.log(add(2, 3)); // 5
console.log(PI);        // 3.14159
Informação

Os nomes devem corresponder à exportação. import { Add } quando a exportação é add lança um SyntaxError — não existe tal exportação nomeada.

Renomeando com as

Quando dois módulos exportam o mesmo nome, ou um nome é inconveniente, renomeie na importação (ou exportação) com as:

// Rename on import
import { add as sum } from './math.js';
console.log(sum(1, 1)); // 2
// Rename on export
const internalAdd = (a, b) => a + b;
export { internalAdd as add };

Exportações padrão

Uma exportação padrão é a única coisa "principal" que um módulo fornece. Um módulo pode ter no máximo uma exportação padrão.

// multiply.js
export default function multiply(a, b) {
  return a * b;
}

Ao importar um padrão, você não usa chaves e escolhe o nome local você mesmo:

// app.js
import multiply from './multiply.js'; // any name works
console.log(multiply(4, 5)); // 20

Como quem importa nomeia, as exportações padrão são frequentemente usadas quando um arquivo representa uma única coisa — uma única classe, um único componente React, um único objeto de configuração.

Misturando exportações padrão e nomeadas

Um módulo pode ter ambas. O padrão fica fora das chaves, as nomeadas ficam dentro:

// user.js
export default class User { /* ... */ }
export const ADMIN_ROLE = 'admin';
// app.js
import User, { ADMIN_ROLE } from './user.js';
Informação

Prefira exportações nomeadas por padrão. Elas tornam as importações autodocumentadas e permitem que as ferramentas (autocomplete, "encontrar referências", tree-shaking) funcionem de forma confiável. Recorra a uma exportação padrão apenas quando um arquivo realmente exporta uma única coisa.

Técnicas de importação

Importação de namespace (import * as)

Para capturar tudo o que um módulo exporta como um único object, use uma importação de namespace:

// app.js
import * as math from './math.js';

console.log(math.add(5, 3)); // 8
console.log(math.PI);        // 3.14159

Cada exportação nomeada torna-se uma propriedade de math. Uma exportação padrão, se houver, aparece como math.default. Use isso quando um módulo agrupa muitos auxiliares relacionados.

Importação dinâmica (import())

A instrução import acima é estática — ela é executada antes de qualquer outra coisa e seu caminho deve ser um literal de string. Às vezes você quer carregar um módulo sob demanda: apenas quando o usuário abre um recurso, ou com base em uma condição de runtime. Para isso, use import() como função. Ela retorna uma Promise que resolve para o object de namespace do módulo:

// Load a heavy module only when needed
async function openEditor() {
  const editor = await import('./editor.js');
  editor.init();
}

A importação dinâmica funciona dentro de funções e condicionais — lugares onde um import estático não é permitido — o que a torna a base para code-splitting e lazy loading.

Reexportação

Um arquivo "barrel" pode coletar exportações de vários módulos e encaminhá-las, para que os consumidores importem de um único lugar:

// shapes/index.js
export { Circle } from './circle.js';
export { Square } from './square.js';
export { default as Triangle } from './triangle.js'; // re-export a default as a name
// app.js
import { Circle, Square, Triangle } from './shapes/index.js';

Erros comuns

  • Extensões importam no navegador e no Node.js ESM. import { x } from './math' falha; escreva './math.js'.
  • import/export só funcionam no nível superior de um módulo — não dentro de um bloco if ou de uma função. Use import() dinâmico para carregamento condicional.
  • Importações são vínculos ao vivo somente leitura. Você pode ler um valor importado, mas não reatribuí-lo; add = 5 em uma importação lança um erro.
  • Uma exportação padrão não recebe automaticamente um nome. export default add exporta o valor, não o nome add; quem importa escolhe o nome local.
  • Os módulos são adiados e executados automaticamente no modo estrito — sem necessidade de 'use strict'.

Um exemplo prático: um mini sistema de biblioteca

Aqui, vários módulos exportam um array de objects de livros, e um arquivo principal os importa e combina.

index.html:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <title>Interactive Library App</title>
</head>
<body>
  <h1>Interactive Library App</h1>
  <button id="loadFiction">Load Fiction</button>
  <button id="loadSciFi">Load Sci-Fi</button>
  <div id="bookList"></div>
  <script src="app.js" type="module"></script>
</body>
</html>

fiction.js:

export const fictionBooks = [
  { title: 'Pride and Prejudice', author: 'Jane Austen' },
  { title: 'To Kill a Mockingbird', author: 'Harper Lee' }
];

sciFi.js:

export const sciFiBooks = [
  { title: 'Dune', author: 'Frank Herbert' },
  { title: 'Neuromancer', author: 'William Gibson' }
];

app.js:

import { fictionBooks } from './fiction.js';
import { sciFiBooks } from './sciFi.js';

function displayBooks(books) {
  const list = document.getElementById('bookList');
  list.innerHTML = '';
  books.forEach(book => {
    const item = document.createElement('div');
    item.textContent = `${book.title} by ${book.author}`;
    list.appendChild(item);
  });
}

document
  .getElementById('loadFiction')
  .addEventListener('click', () => displayBooks(fictionBooks));
document
  .getElementById('loadSciFi')
  .addEventListener('click', () => displayBooks(sciFiBooks));

Cada categoria vive em seu próprio módulo e exporta uma função ou dados, e app.js os une. Dividir dados e comportamento dessa forma mantém cada arquivo pequeno e torna trivial adicionar novas categorias.

Boas práticas

  1. Prefira exportações nomeadas para que as importações se autodocumentem e o tree-shaking funcione.
  2. Uma responsabilidade por módulo — um arquivo deve ser fácil de descrever em uma frase.
  3. Use arquivos barrel com moderação — eles organizam as importações, mas podem prejudicar o tree-shaking se usados em excesso.
  4. Carregue sob demanda código pesado ou raramente usado com import() dinâmico.
  5. Sempre inclua extensões de arquivo em caminhos relativos.

Conclusão

As exportações nomeadas fornecem muitos vínculos por arquivo, as exportações padrão fornecem uma exportação "principal", e import (com as, * as e import() dinâmico) oferece controle preciso sobre o que entra e quando. Juntos, eles transformam um conjunto de scripts em um grafo de módulos sustentável e sujeito a tree-shaking. A seguir, veja como os módulos são carregados no navegador em Módulos, introdução.

Prática

Prática
Quais afirmações sobre export e import em JavaScript estão corretas?
Quais afirmações sobre export e import em JavaScript estão corretas?
Was this page helpful?