A mensagem de erro “Cannot use import statement outside a module” ocorre quando a palavra-chave import é encontrada em um módulo JavaScript ou TypeScript configurado incorretamente.

Em um ambiente de tempo de execução no lado do servidor JavaScript, esse erro geralmente resulta do uso da sintaxe import para módulos escritos em ECMAScript (ES) quando o Node.js espera a palavra-chave require usada pelo sistema de módulos CommonJS.

O TypeScript oferece suporte a diferentes formatos de módulo, mas os erros de codificação que confundem as abordagens ES e CommonJS para importar módulos também resultam nesse erro.

No lado do navegador, o erro geralmente ocorre quando você não usa um empacotador para seus arquivos de código JavaScript.

Este artigo explora essas três fontes de erro e detalha uma solução para cada ambiente.

Como resolver o erro no JavaScript do lado do servidor

Esta seção demonstra como resolver o erro em ambientes JavaScript do lado do servidor.

Background

O Node.js usa a palavra-chave require do sistema CommonJS por padrão. Portanto, você receberá o erro conhecido, a menos que configure o Node.js para dar suporte à sintaxe do módulo ES. Da mesma forma, o Node.js requer a extensão .mjs para reconhecer e trabalhar com módulos ES.

Solução

Como alternativa ao uso do .mjs, você pode tornar as versões mais antigas do Node.js compatíveis com o módulo ES atual usando bundlers ou executando o Node.js com o sinalizador --experimental-modules. Caso contrário, você pode definir o campo type no arquivo package.json para module da seguinte forma:

{
  "name": "test-package",
  "version": "1.0.0",
  "type": "module",
  "main": "app.js",
  "dependencies": { }
}

(Observação: você deve incluir a propriedade type no arquivo package.json em todos os pacotes. Essa prática facilita a identificação do sistema de módulos em uso e garante a consistência entre suas bibliotecas)

Outra maneira de evitar o erro é garantir que as sintaxes import e export estejam corretas e sejam carregadas adequadamente. É fundamental que você sempre use caminhos de arquivos relativos, exportações nomeadas, extensões de arquivos para exportações e evite exportações padrão.

Aqui está um exemplo:

//module import 
import { sampleFunction } from './sampleModule.js';

// function export
export function sampleFunction() {
     // code goes here
}

Finalmente, você deve garantir a compatibilidade de todas as bibliotecas de terceiros com módulos ES. Para obter essas informações, consulte a documentação da biblioteca no arquivo package.json. Alternativamente, use um bundler para transpilar o código, de forma que um ambiente JavaScript possa entendê-lo.

Como resolver o erro em ambientes TypeScript

Esta seção demonstra como resolver a mensagem de erro em ambientes TypeScript.

Contexto

Com os módulos, você pode reutilizar, organizar e compartilhar código entre vários arquivos em um projeto. O ES oferece suporte a módulos externos para o compartilhamento de código entre vários arquivos usando as palavras-chave import e export.

Esse erro geralmente ocorre em ambientes TypeScript quando você usa a sintaxe do módulo ES sem configurar o TypeScript para usá-la. Como o TypeScript é um superconjunto do JavaScript, o padrão é usar a sintaxe CommonJS para importações, que usa require em vez de import. Nesse caso, a instrução import causa o erro. No entanto, a configuração correta do TypeScript é necessária para que ele ofereça suporte aos módulos ES.

Você também pode encontrar esse erro se usar a extensão de arquivo incorreta. Por exemplo, ao usar o TypeScript em um ambiente Node.js com sintaxe de módulo ES, o módulo que você deseja importar deve ter a extensão de arquivo .mjs em vez da extensão .js normal.

Outra fonte comum do erro é a configuração incorreta do campo module nos arquivos tsconfig.json ou package.json quando você usa empacotadores como o Webpack. No entanto, você pode usar bundlers para módulos ES em TypeScript configurando os campos module e target no arquivo tsconfig.json como ECMAScript. Assim, o Webpack entenderá o ambiente de destino e usará as extensões de arquivo corretas ao transpilar o código.

Solução

Para carregar módulos ES usando um carregador de módulo como o RequireJS ou um empacotador como o Webpack, faça as seguintes adições ao arquivo tsconfig.json:

{
  "compilerOptions": {
    "module": "es20215",
    "target": "es20215",
    "sourceMap": true
  }
}

Na parte compilerOptions do código acima, os campos module e target são definidos para que você use um módulo es20215. Com essas adições, você pode usar as declarações import e export em um ambiente TypeScript sem causar o erro.

Como o TypeScript usa o CommonJS por padrão, se você não modificar o arquivo tsconfig.json adequadamente, a mensagem de erro será exibida.

Felizmente, depois de definir os campos module e target para usar um módulo ECMAScript, você pode usar a instrução export para exportar uma função ou variável de um módulo e a instrução import para carregar outro módulo no escopo do atual. Esse processo ocorre no código abaixo:

// sum.ts
export function sum(a: number, b: number, c: number): number {
  return a + b + c;
}

// main.ts
import { sum } from './sum';
console.log(add(4, 4, 9));

Se você estiver usando uma versão mais antiga do Node.js, poderá ativar o suporte ao módulo ES executando seu código com o sinalizador --experimental-modules. Você também deve usar um empacotador como Webpack, Browserify ou Rollup para empacotar todo o código ES e enviá-lo para um único arquivo. Certifique-se de que ele esteja em uma versão que os navegadores e as versões antigas do Node.js possam entender e configure um arquivo Webpack.config.js na raiz do seu projeto que especifique o tipo de módulo.

Aqui está um exemplo extraído da documentação do Webpack:

module.exports = {
  entry: './src/index.ts',
  output: {
    filename: 'bundle.js',
   path: path.resolve(__dirname, 'dist')
  },
  resolve: {
    extensions: ['.ts', '.js', '.mjs']
  },
  module: {
    rules: [
      {
        test: /.ts$/,
        use: 'ts-loader',
        exclude: /node_modules/
      }
    ]
  },
  experiments: {
    outputModule: true
  }
};

O código compilado é enviado para um arquivo bundle.js no diretório dist do diretório raiz do projeto.

Você também pode usar polyfills como es-module-shims para direcionar os navegadores mais antigos que não suportam as instruções import e export dos módulos ES.

Como resolver o erro no JavaScript do lado do navegador

Esta seção mostra a você como resolver o erro em ambientes JavaScript do lado do navegador.

Background

A maioria dos navegadores modernos, incluindo Chrome, Firefox, Edge e Safari, oferece suporte a módulos ES, portanto, você não precisará usar polyfills, bundlers ou transpilers de navegador.

Você também não precisará deles se usar as bibliotecas de frontend baseadas em JavaScript React ou Vue, pois elas são compatíveis com os campos ES imports e exports por padrão. No entanto, os navegadores mais antigos não oferecem suporte à sintaxe ES e, portanto, exigem essas ferramentas para compatibilidade entre plataformas.

O motivo mais comum para o erro em um navegador mais antigo é quando os arquivos HTML de uma página não contêm o atributo type="module". Nesse cenário, o erro ocorre porque o JavaScript executado na web não inclui suporte padrão para a sintaxe do módulo ES. Para o código JavaScript enviado por meio da conexão, você pode encontrar um erro de compartilhamento de recursos entre origens ao tentar carregar um módulo ES de um domínio diferente.

Solução

Para evitar o erro de módulo em um navegador mais antigo, verifique se você está usando o atributo correto da tag scripttype="module" – no arquivo HTML raiz. Como alternativa, você pode usar o Webpack para transpilar o código para que os navegadores mais antigos possam entendê-lo.

Para usar o atributo type="module", inclua a seguinte linha em seu arquivo HTML raiz:

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

É fundamental garantir que os caminhos do arquivo import sejam válidos e que você esteja usando a sintaxe import correta.

Além disso, você pode visitar sites como o Can I Use para confirmar a compatibilidade do navegador com os módulos ES.

Por fim, como o uso da extensão de arquivo .js é uma prática comum, você pode definir o atributo type na tag script do arquivo HTML do módulo como uma solução alternativa. Ao definir esse atributo como module, você informa ao navegador para desconsiderar a extensão .js e tratar o arquivo como um módulo.

Resumo

O erro “Cannot use import statement outside a module” pode aparecer por vários motivos, dependendo de você estar em um ambiente JavaScript do lado do navegador ou do lado do servidor. Sintaxe incorreta, configurações inadequadas e extensões de arquivo sem suporte são algumas das fontes mais comuns desse erro.

Embora a maioria dos navegadores modernos ofereça suporte a módulos ES, você deve garantir que os navegadores mais antigos sejam compatíveis. Pacotes como o Webpack permitem que você compile todo o código-fonte com suas dependências em uma única saída que os navegadores mais antigos possam entender.

Lembre-se de adicionar o atributo type="module" no arquivo HTML para informar ao navegador que o módulo é um módulo ES. Por fim, embora o uso da extensão .js para CommonJS seja a prática padrão, você pode usar a extensão .mjs para permitir a importação de módulos ES.

Você tem um aplicativo JavaScript que precisa ficar on-line, mas não quer gerenciar os servidores por conta própria? As plataformas de hospedagem de aplicativos e hospedagem de banco de dados da Kinsta podem ser a resposta para você. Você pode até mesmo combinar esses serviços com a Hospedagem de Site Estático da Kinsta para que o frontend do seu aplicativo seja servido gratuitamente.