Migrar para package:web
Como migrar código de interop web de dart:html para package:web.
O package:web do Dart expõe acesso às APIs do navegador,
possibilitando a interop entre aplicações Dart e a web.
Use package:web para interagir com o navegador e
manipular objetos e elementos no DOM.
import 'package:web/web.dart';
void main() {
final div = document.querySelector('div')!;
div.textContent = 'Text set at ${DateTime.now()}';
}
package:web vs dart:html
#
O objetivo do package:web é reformular a forma como o Dart expõe as APIs web,
resolvendo várias questões das bibliotecas web atuais do Dart:
-
Compatibilidade com Wasm
Pacotes só podem ser compatíveis com Wasm se usarem
dart:js_interopedart:js_interop_unsafe. Opackage:webé baseado emdart:js_interop, então, por padrão, ele tem suporte nodart2wasm.Bibliotecas web centrais do Dart, como
dart:htmledart:svg, estão depreciadas e não são suportadas ao compilar para Wasm. -
Manter-se moderno
O
package:webusa a Web IDL para gerar automaticamente membros de interop e tipos de interop para cada declaração na IDL. Gerar referências diretamente, em vez de usar os membros e abstrações adicionais dodart:html, permite que opackage:webseja mais conciso, mais fácil de entender, mais consistente e mais capaz de acompanhar a evolução do desenvolvimento web. -
Versionamento
Por ser um pacote, o
package:webpode ser versionado com mais facilidade do que uma biblioteca como odart:html, evitando quebrar o código dos usuários conforme evolui. Isso também torna o código menos exclusivo e mais aberto a contribuições. Desenvolvedores podem criar declarações de interop alternativas próprias e usá-las junto com opackage:websem conflito.
Essas melhorias resultam naturalmente em algumas
diferenças de implementação entre package:web e dart:html.
As mudanças que mais afetam pacotes existentes,
como renomeações da IDL e
testes de tipo,
são tratadas nas seções de migração a seguir. Embora nos refiramos apenas ao
dart:html por brevidade, os mesmos padrões de migração se aplicam a qualquer outra
biblioteca web central do Dart, como dart:svg.
Migrando de dart:html
#
Remova o import de dart:html e substitua-o por package:web/web.dart:
import 'dart:html' as html; // Remove
import 'package:web/web.dart' as web; // Add
Adicione web às dependencies do seu pubspec:
dart pub add web
As seções a seguir cobrem alguns dos problemas comuns de migração
de dart:html para package:web.
Para outros problemas de migração, consulte o repositório dart-lang/web e abra uma issue.
Renomeações
#
Muitos dos símbolos em dart:html foram renomeados em relação
à sua declaração original na IDL, para se alinhar mais ao estilo do Dart.
Por exemplo, appendChild virou append,
HTMLElement virou HtmlElement, etc.
Em contraste, para reduzir a confusão,
o package:web usa os nomes originais das definições da IDL.
Um dart fix está disponível para converter tipos que foram renomeados
entre dart:html e package:web.
Depois de trocar o import, os objetos renomeados vão gerar novos erros de "undefined". Você pode resolvê-los de duas formas:
- Pela CLI, executando
dart fix --dry-run. -
Na sua IDE, selecionando o
dart fix: Rename to 'package:web name'.
O dart fix cobre muitas das renomeações de tipos comuns.
Se você encontrar um tipo de dart:html sem um dart fix
para renomeá-lo,
primeiro nos avise abrindo uma issue.
Depois, você pode tentar descobrir manualmente o nome do tipo em package:web de um
membro existente de dart:html olhando sua definição.
O valor da anotação @Native na definição de um membro de dart:html
indica ao compilador para tratar qualquer objeto JS desse tipo como a classe Dart
que ela anota. Por exemplo, a anotação @Native nos diz que o nome nativo JS do membro
HtmlElement do dart:html é HTMLElement, então o nome em
package:web também será HTMLElement:
@Native("HTMLElement")
class HtmlElement extends Element implements NoncedElement { }
Para encontrar a definição em dart:html de um membro indefinido no package:web,
tente um dos métodos a seguir:
- Pressione Ctrl ou Command e clique no nome indefinido na IDE e escolha Go to Definition.
-
Pesquise o nome na documentação da API de
dart:htmle verifique a página dele na seção Annotations.
De forma semelhante, você pode encontrar uma API indefinida no package:web cujo membro
correspondente em dart:html usa a palavra-chave native
na definição.
Verifique se a definição usa a anotação @JSName para uma renomeação;
o valor da anotação indicará o nome que o membro usa no
package:web:
@JSName('appendChild')
Node append(Node node) native;
native é uma palavra-chave interna que significa o mesmo que external neste
contexto.
Element e HTMLElement
#
Element agora é HTMLElement, mas o extension type Element também existe como
um tipo base para HTMLElement, SVGElement, etc.
Veja a documentação de Element no MDN.
querySelector retorna um Element, pois ele pode retornar outros subtipos de
Element
além de HTMLElement, como SVGElement. É preciso fazer um downcast para
HTMLElement
se você precisar acessar os métodos dele.
element.querySelector('#selectme')!.className = 'test'; // valid in both
element.querySelector('#selectme')!.style.color = 'red'; // Remove
(element.querySelector('#selectme') as HTMLElement).style.color = 'red'; // Add
Operações com listas
#
Diferente do dart:html, métodos do package:web como Element.querySelectorAll
e
Element.children retornam valores que não implementam List. Se for necessário
uma List, você precisará envolvê-la com uma classe.
Para operações imutáveis, você pode usar JSImmutableListWrapper:
final anchors = document.querySelectorAll('a');
for (final anchor in anchors) {} // Remove
for (final anchor in JSImmutableListWrapper(anchors)) {} //Add
for (final child in parent.children) {} // Remove
for (final child in JSImmutableListWrapper(parent.children)) {} // Add
Você precisa implementar operações mutáveis simples, como removeWhere:
parent.children.removeWhere(test); // Remove
for (var i = parent.children.length - 1; i >= 0; --i) {
if (test(parent.children.item(i)!)) {
parent.children.item(i)!.remove();
}
} // Add
Exemplos comuns de manipulação do DOM
#
Aqui estão alguns exemplos comuns de mudanças triviais que precisam ser feitas
ao migrar de dart:html para package:web:
element.querySelector('#selector')?.innerHtml = 'something'; // Remove
element.querySelector('#selector')?.innerHTML = 'something'.toJS; // Add
element.parent.classes.add('class'); // Remove
element.parentElement.classList.add('class'); // Add
element.appendHtml(html); // Remove
element.insertAdjacentHTML('beforeend', html.toJS); // Add
var checkbox = CheckboxInputElement(); // Remove
var checkbox = HTMLInputElement()..type='checkbox'; // Add
element.text = 'Hello'; // Remove
element.textContent = 'Hello'; // Add
element.querySelectorAll('a').classes.add('link'); // Remove
for (final a in JSImmutableListWrapper(element.querySelectorAll('a'))) {
a.classList.add('a');
} // Add
Testes de tipo
#
É comum que código que usa dart:html utilize verificações em tempo de execução, como is.
Quando usados com um objeto de dart:html, is e as
verificam se o objeto é
o tipo JS dentro da anotação @Native.
Em contraste, todos os tipos de package:web são reificados para JSObject. Isso significa que um
teste de tipo em tempo de execução terá comportamento diferente entre tipos de dart:html
e
de package:web.
Para conseguir fazer testes de tipo, migre qualquer código de dart:html que usa testes de tipo com
is
para usar métodos de interop, como
instanceOfString,
ou o helper isA
mais conveniente e tipado.
A seção Compatibilidade, verificações de tipo e casts
da página de tipos JS cobre as alternativas em detalhes.
obj is Window; // Remove
obj.instanceOfString('Window'); // Add
element is InputElement; // Remove
element.isA<HTMLInputElement>(); // Add
Para detectar verificações de tipo e casts inválidos com tipos de interop JS,
habilite a regra de lint invalid_runtime_check_with_js_interop_types.
A partir do package:lints
7.0.0,
package:lints/core.yaml inclui essa regra.
Assinaturas de tipo
#
Muitas APIs em dart:html aceitam vários tipos do Dart em suas assinaturas de tipo.
Como o dart:js_interop restringe
os tipos que podem ser escritos, alguns
dos membros do package:web agora exigirão que você converta
o valor antes
de chamar o membro.
Aprenda a usar os métodos de conversão de interop na seção Conversões
da página de tipos JS.
Por exemplo, ao passar callbacks para addEventListener,
converta a função Dart em uma JSFunction usando .toJS:
window.addEventListener('click', callback); // Remove
window.addEventListener('click', callback.toJS); // Add
// where callback's first parameter accepts Event.
Se você preferir assinar eventos do DOM usando Streams do Dart
em vez de addEventListener, pode usar as extensions helper de stream
do package:web:
// Using the stream helper extension (same API shape as dart:html):
button.onClick.listen((event) {
// event is already typed as MouseEvent without needing a cast:
print('Clicked at (${event.clientX}, ${event.clientY})');
});
// Or using EventStreamProviders directly:
EventStreamProviders.clickEvent.forTarget(button).listen((event) {
print('Clicked at (${event.clientX}, ${event.clientY})');
});
De modo geral, você consegue identificar quais métodos precisam de conversão porque eles serão sinalizados com alguma variação da exceção:
A value of type '...' can't be assigned to a variable of type 'JSFunction?'
Imports condicionais
#
É comum que o código use um import condicional baseado em o dart:html
ser suportado para diferenciar entre nativo e web:
export 'src/hw_none.dart'
if (dart.library.io) 'src/hw_io.dart'
if (dart.library.html) 'src/hw_html.dart';
No entanto, como dart:html está depreciado e não é suportado ao
compilar para Wasm, a alternativa correta agora é
usar dart.library.js_interop para diferenciar entre nativo e web:
export 'src/hw_none.dart' // Stub implementation
if (dart.library.io) 'src/hw_io.dart' // dart:io implementation
if (dart.library.js_interop) 'src/hw_web.dart'; // package:web implementation
Dispatch virtual e mocking
#
As classes de dart:html suportavam dispatch virtual, mas, como a interop JS usa
extension types, o dispatch virtual não é possível. De modo semelhante, chamadas
dynamic
com tipos de package:web não funcionarão como esperado (ou podem continuar funcionando
por acaso, mas vão parar quando dart:html for removido), pois os membros deles
estão disponíveis apenas estaticamente. Migre todo o código que depende de dispatch virtual para
evitar esse problema.
Um caso de uso do dispatch virtual é o mocking. Se você tem uma classe de mock que
faz implements de uma classe de dart:html, ela não pode ser usada para implementar um tipo
de package:web. Em vez disso, prefira fazer o mock do próprio objeto JS. Veja o
tutorial de mocking
para mais informações.
APIs não-native
#
As classes de dart:html também podem conter APIs com uma implementação não trivial.
Esses membros podem ou não existir nos helpers do package:web. Se o seu código
depende dos detalhes dessa implementação, talvez você consiga copiar o código necessário.
No entanto, se achar que isso não é viável ou se esse código for útil também para
outros usuários, considere abrir uma issue ou enviar um pull request para
o package:web para dar suporte a esse membro.
Zones
#
Em dart:html, os callbacks são automaticamente associados à zone.
Isso não acontece no package:web. Não há vinculação automática de
callbacks à zone atual.
Se isso for importante para sua aplicação, você ainda pode usar zones, mas terá que escrevê-las você mesmo vinculando o callback. Veja #54507 para mais detalhes.
Por exemplo, ao passar um callback para um listener de evento do DOM,
vincule-o manualmente à zone atual antes de convertê-lo com .toJS:
// Before: Callback lost zone context
element.addEventListener(
'click',
(web.Event event) {
// ... relies on zone-local values
}.toJS,
);
element.addEventListener(
'click',
Zone.current.bindUnaryCallback((web.Event event) {
// ... zone-local values are preserved
}).toJS,
);
Ainda não há uma API de conversão nem um helper disponível para fazer isso automaticamente.
Helpers
#
O núcleo do package:web contém membros de interop external,
mas não fornece outras funcionalidades que o dart:html oferecia por padrão.
Para amenizar essas diferenças, o package:web contém helpers
com suporte adicional para vários casos de uso
que não estão disponíveis diretamente pela interop central.
A biblioteca de helpers contém vários membros que expõem algumas funcionalidades legadas
das bibliotecas web do Dart.
Por exemplo, o package:web central só tem suporte para adicionar e remover
event listeners. Em vez disso, você pode usar helpers de stream, que facilitam
assinar eventos com Streams do Dart sem escrever esse código você mesmo.
// Original dart:html version:
final htmlInput = InputElement();
await htmlInput.onBlur.first;
// Migrated package:web version:
final webInput = HTMLInputElement();
await webInput.onBlur.first;
Você pode encontrar todos os helpers e a documentação deles no repositório, em
package:web/helpers. Eles serão atualizados continuamente para ajudar
os usuários na migração e facilitar o uso das APIs web.
Exemplos
#
Aqui estão alguns exemplos de pacotes que foram migrados de dart:html
para package:web:
Salvo indicação em contrário, a documentação neste site reflete Dart 3.13.7. Página atualizada pela última vez em 2026-11-12. Ver código-fonte ou relatar um problema.
Encontrou essa página sem tradução ou que precisa de correção? Abra uma issue e nos ajude a manter esse site em PT-BR para ajudar pessoas como você.