Transição para o namespace do navegador

A partir do Chrome 148, todas as APIs de extensão do Chrome estão disponíveis no namespace browser, além do namespace chrome. Por exemplo, browser.tabs.create({}) e chrome.tabs.create({}) são equivalentes.

O namespace está disponível em qualquer lugar em que você possa chamar APIs de extensão, incluindo scripts de conteúdo, service workers e documentos offscreen. Ele aponta para os mesmos objetos de API que chrome, então chrome.tabs === browser.tabs.

O namespace browser é resultado do trabalho do WebExtensions Community Group (WECG), um grupo da comunidade W3C em que fornecedores de navegadores colaboram em padrões de extensão compartilhados. O namespace chrome não vai desaparecer. Os dois namespaces vão continuar funcionando.

Decidir se você quer adotar o namespace do navegador

Se você estiver usando webextension-polyfill, pule para Observação para usuários de polyfill antes de mudar qualquer outra coisa porque a resposta é diferente para você.

Se você estiver criando uma nova extensão, defina minimum_chrome_version como "148" e use browser incondicionalmente. Você pode parar de ler aqui. O restante desta seção é para extensões atuais que estão decidindo como adotar.

Verificar quais versões do Chrome seus usuários estão usando

Se você já tiver uma extensão, verifique quais versões do Chrome seus usuários estão usando antes de mudar. O Chrome é atualizado automaticamente, mas alguns usuários desativam as atualizações, e outros usam dispositivos mais antigos que não conseguem executar a versão mais recente. Confirme com seus próprios dados de análise. Se você ainda não configurou o Google Analytics, consulte Monitore a performance da sua extensão com o Google Analytics 4 para começar.

Em seguida, escolha um caminho:

Adotar incondicionalmente

Defina minimum_chrome_version no manifesto e use browser incondicionalmente. Não é necessário usar proteção de tempo de execução:

{
  "minimum_chrome_version": "148"
}

Use um lançamento gradual ao aumentar minimum_chrome_version. Se algo der errado, você poderá reverter a extensão na Chrome Web Store.

Usar a proteção de ambiente de execução

Adicione o snippet a seguir no início do código de inicialização da extensão antes de referenciar browser em qualquer outro lugar:

if (!globalThis.browser) {
  globalThis.browser = chrome;
  // Consider firing an analytics event here to measure how often
  // your users hit this fallback path.
}

Isso faz com que browser seja um alias de chrome em versões anteriores. Assim, o restante do código pode usar browser incondicionalmente.

Observação para usuários de polyfill

Se a extensão usar webextension-polyfill, ela se tornará uma operação nula no Chrome 148 e versões mais recentes. O polyfill pulou o encapsulamento quando browser já estava definido, presumindo que o navegador host já havia fornecido a API.

Uma tentativa anterior de enviar o namespace no Chrome 136 foi revertida por este motivo: com browser recém-definido, o polyfill parou de encapsular, mas o browser.runtime.onMessage do Chrome ainda não era compatível com listeners que retornavam promessas, que o polyfill estava fornecendo. As extensões que dependiam desse padrão pararam de funcionar. O Chrome 148 envia o namespace e os listeners nativos de retorno de promessa onMessage juntos para evitar essa lacuna.

Você pode remover a dependência de polyfill quando sua base de usuários migrar para o Chrome 148.

Outros recursos

Respostas assíncronas em runtime.sendMessage

No Chrome 148, os listeners de runtime.onMessage podem retornar um Promise diretamente para enviar uma resposta assíncrona. Isso funciona se você chamar usando chrome.* ou browser.*.

Antes, a única maneira de responder de forma assíncrona era retornar um literal true do listener e chamar sendResponse mais tarde:

// Old pattern - requires returning true to keep the channel open
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
  fetch('https://example.com')
    .then(response => sendResponse({ statusCode: response.status }));

  return true; // keeps the message channel open for the async response
});

Agora é possível retornar um Promise (ou usar uma função async) diretamente:

// New pattern - return a promise or use async/await
browser.runtime.onMessage.addListener(async (message, sender) => {
  const response = await fetch('https://example.com');
  return { statusCode: response.status };
});

O padrão return true continua funcionando, então o código atual não precisa ser alterado.