Importar um arquivo JSON direto em um módulo ES sempre foi um problema mal resolvido: o navegador não tem como saber, só pelo caminho, que ./config.json deve ser interpretado como dados e não como JavaScript. Os import attributes resolvem isso com uma sintaxe pequena e explícita — with { type: 'json' } — que declara o tipo do módulo importado no próprio import, sem depender de extensão de arquivo, cabeçalho HTTP ou configuração de bundler.
O problema que eles resolvem
Antes dessa sintaxe, trazer um JSON para dentro de um módulo exigia fetch e um await response.json(), mesmo quando o arquivo era estático e conhecido em tempo de build:
const resposta = await fetch('./config.json');
const config = await resposta.json();
console.log(config.apiUrl);
Funciona, mas é assíncrono só por causa da mecânica de carregamento, exige tratamento de erro de rede para um arquivo que está no mesmo projeto, e não passa pelo cache de módulos do próprio import. Tentar simplesmente fazer import config from './config.json' sem indicar o tipo gera erro, porque o especificador aponta para um arquivo que não é JavaScript.
Como funciona o with { type: 'json' }
A cláusula with depois do especificador do módulo declara um atributo obrigatório para a resolução do import. Para JSON, o runtime faz o parse do arquivo e entrega o resultado como export default:
import config from './config.json' with { type: 'json' };
console.log(config.apiUrl);
Sem o with { type: 'json' }, o navegador ou o runtime tentaria interpretar o conteúdo como JavaScript e falharia. Com o atributo, o tipo é explícito e verificado: se o arquivo não for JSON válido, ou se o servidor responder com um Content-Type incompatível, o import falha em vez de executar algo inesperado.
Import dinâmico com atributos
O import() dinâmico aceita o mesmo atributo como segundo argumento, útil quando o caminho do JSON só é conhecido em tempo de execução:
async function carregarTraducao(idioma) {
const modulo = await import(`./i18n/${idioma}.json`, {
with: { type: 'json' }
});
return modulo.default;
}
const textos = await carregarTraducao('pt-br');
console.log(textos.boasVindas);
Diferente do fetch, o resultado passa pelo cache de módulos: importar o mesmo JSON duas vezes não dispara duas requisições nem dois parses.
Reexportando um JSON de outro módulo
Como qualquer import, um JSON importado com atributo pode ser reexportado, o que é útil para centralizar configuração:
// configs.js
export { default as producao } from './config.producao.json' with { type: 'json' };
export { default as desenvolvimento } from './config.dev.json' with { type: 'json' };
CSS como módulo
A mesma sintaxe também define type: 'css', que importa uma folha de estilos como um objeto CSSStyleSheet pronto para ser usado com adoptedStyleSheets — sem precisar injetar uma tag <link> ou <style>:
import folha from './componente.css' with { type: 'css' };
document.adoptedStyleSheets = [...document.adoptedStyleSheets, folha];
O suporte a type: 'css' é mais recente e menos uniforme entre navegadores do que o de JSON, então vale conferir a compatibilidade antes de depender dele em produção.
Quando usar
- Carregar arquivos de configuração ou dados estáticos sem passar por
fetch. - Módulos de tradução (i18n) carregados sob demanda com
import()dinâmico. - Garantir, de forma explícita, que um recurso seja tratado como dado e não como código executável.
- Compartilhar folhas de estilo entre Shadow DOMs via
adoptedStyleSheets, usandotype: 'css'.
Cuidados
A sintaxe atual usa a palavra-chave with; uma versão anterior, chamada import assertions, usava assert { type: 'json' } e já está obsoleta — motores modernos priorizam with, e código novo não deve mais usar assert. O atributo type é obrigatório para JSON e CSS: omiti-lo não faz o runtime "adivinhar" o tipo pela extensão do arquivo.
Compatibilidade
O suporte a with { type: 'json' } é amplo nos navegadores modernos (Chrome, Edge e Firefox recentes, Safari a partir da versão 17.2) e no Node.js a partir da versão 22, alcançando cobertura ampla desde 2025. Já type: 'css' tem suporte mais recente e vale checar caso a caso.
Conclusão
Import attributes tornam explícito algo que antes dependia de convenção ou de um passo extra com fetch: o tipo do recurso importado. Para JSON, o ganho imediato é carregar dados estáticos direto pelo sistema de módulos, com cache e sem assincronismo desnecessário — e para CSS, abrem caminho para compartilhar folhas de estilo sem tocar no DOM manualmente.
0 Comentário
Deixe seu Comentário!
Dúvida, sugestão ou só um "valeu!" — tudo é bem-vindo por aqui.