Sobre este problema HTML
O padrão HTML living standard define que scripts com type="module" são sempre obtidos em paralelo e avaliados depois do documento ter sido analisado, que é o mesmo comportamento que o atributo defer fornece para scripts clássicos. Porque esta execução diferida é uma característica inerente dos scripts de módulo, a especificação proíbe explicitamente combinar os dois. Incluir ambos não altera como o navegador lida com o script, mas sinaliza uma má compreensão de como os módulos funcionam e produz HTML inválido.
Este erro de validação surge comummente quando os programadores migram scripts clássicos para módulos ES. Um script clássico como <script defer src="app.js"></script> depende do atributo defer para evitar bloquear o analisador. Ao converter para um módulo adicionando type="module", é natural deixar defer no lugar — mas já não é necessário ou permitido.
Vale a pena notar que o atributo async é válido em scripts de módulo e altera o seu comportamento. Enquanto defer é redundante porque os módulos já são diferidos, async substitui esse padrão e faz com que o módulo execute assim que ele e as suas dependências terminaram de carregar, em vez de esperar que a análise HTML seja concluída.
Como corrigir
Remova o atributo defer de qualquer elemento <script> que tenha type="module". Não são necessárias outras alterações — o comportamento de carregamento e execução permanecerá idêntico.
Se pretende intencionalmente que o script execute o mais cedo possível (antes da análise ser concluída), use async em vez de defer. Mas se quiser o comportamento diferido padrão, simplesmente omita ambos os atributos e deixe que o padrão do módulo faça efeito.
Exemplos
❌ Incorreto: defer combinado com type="module"
<script type="module" defer src="app.js"></script>
O atributo defer é redundante aqui e causa um erro de validação.
✅ Correto: script de módulo sem defer
<script type="module" src="app.js"></script>
Os scripts de módulo são diferidos automaticamente, pelo que isto comporta-se exatamente da mesma forma que o exemplo incorreto acima mas é HTML válido.
✅ Correto: usar async com um módulo (quando necessário)
<script type="module" async src="analytics.js"></script>
Ao contrário de defer, o atributo async é permitido em scripts de módulo. Faz com que o módulo execute assim que estiver pronto, sem esperar que a análise HTML termine.
✅ Correto: script clássico com defer
<script defer src="app.js"></script>
Para scripts clássicos (não-módulo), o atributo defer é válido e necessário se quiser execução diferida.
Encontre problemas como este automaticamente
O Rocket Validator analisa milhares de páginas em segundos, detetando problemas HTML em todo o seu site.