Executando Bibliotecas React no Preact com preact/compat
Use preact/compat para executar bibliotecas React no Preact, com aliases para Vite, webpack, Rollup, Jest, TypeScript e falhas comuns.
preact/compat é uma camada de compatibilidade, distribuída dentro do pacote principal preact desde o Preact X, que mapeia a API pública do React para o Preact, de modo que a maioria das bibliotecas React funciona sem modificações enquanto sua aplicação entrega cerca de 9,5KB de framework em vez do runtime bem maior do React.
Trocar o alias é um trabalho de cinco minutos. Descobrir três dias depois que um date picker está lançando erros vindos de algum ponto profundo dentro de node_modules é a parte sobre a qual ninguém te avisa. Você habilita a camada criando um alias de react e react-dom para preact/compat no seu bundler: sem mudanças de código nos seus componentes, sem pacote separado para instalar. Este guia traz a configuração exata de alias para cada toolchain relevante, um passo a passo de migração com o ganho em tamanho de bundle e um relato honesto sobre quais bibliotecas quebram.
Principais Conclusões
preact/compatvem dentro do pacotepreact. O compat agora vive no core, então o pacote standalonepreact-compatestá obsoleto enpm install preacté tudo o que você precisa.- Todo o mecanismo consiste em criar alias para quatro caminhos de importação:
react,react-dom,react-dom/test-utilsereact/jsx-runtime, todos apontando para o Preact. - Com
@preact/preset-vite, o aliasing é automático, então você não escreveresolve.aliasà mão. - No webpack, o alias de
react-domprecisa estar listado abaixo dereact-dom/test-utils, ou a regra mais abrangente sobrescreve o mapeamento de test-utils. - O compat cobre a API pública do React, não seus internals. Bibliotecas que acessam caminhos internos profundos de
react-dom, ou que dependem das APIs mais recentes do React 19, ainda podem quebrar.
O que é preact/compat e por que ele existe?
preact/compat traduz a superfície de API pública do React (React.Component, hooks, createPortal, forwardRef, memo, o JSX runtime) para os equivalentes do Preact, de forma que componentes de terceiros escritos para React resolvam para Preact em tempo de build. A própria listagem no npm do Preact vende a biblioteca com base no amplo suporte a React por trás de um único alias, e é essa compatibilidade que permite reutilizar o ecossistema React sem uma reescrita.
Não existe mais um pacote preact-compat para instalar. O guia oficial de upgrade explica que a camada já foi distribuída separadamente e foi incorporada ao repositório principal para simplificar a coordenação, então quem estiver atualizando precisa trocar imports e aliases antigos de preact-compat por preact/compat. O pacote sem escopo é um beco sem saída: seu repositório no GitHub está arquivado e em modo somente leitura desde dezembro de 2021, e sua página no npm orienta a desinstalá-lo, já que o Preact X traz o compat por padrão. O Preact 10.x é a linha estável atual, com a 11.0.0 em estágio de release candidate e não em disponibilidade geral; a página de releases do Preact lista os números exatos de versão.
O Aliasing É Todo o Truque
Discover how at OpenReplay.com.
Todo o mecanismo é aliasing: você aponta react, react-dom, react-dom/test-utils e react/jsx-runtime para o Preact, de modo que toda importação existente, incluindo bibliotecas de terceiros no fundo de node_modules, resolva para preact/compat em vez de React. Nada no código dos seus componentes muda. Uma instrução import { useState } from 'react' permanece exatamente como está escrita; o bundler reescreve para onde react resolve.
As quatro entradas canônicas, segundo o guia do Preact sobre aliasing React to Preact:
| Caminho de importação | Alvo do alias | Motivo |
|---|---|---|
react | preact/compat | API central do React |
react-dom/test-utils | preact/test-utils | Utilitários de teste |
react-dom | preact/compat | Renderizador DOM (precisa ficar abaixo de test-utils) |
react/jsx-runtime | preact/jsx-runtime | Transform automática de JSX |
Criar alias apenas para react e react-dom, um atalho comum em tutoriais mais antigos, deixa bibliotecas que importam o JSX runtime ou react-dom/test-utils resolvendo para React, o que reintroduz justamente os bytes que você estava tentando eliminar.
Configuração de Alias por Toolchain
Vite (padrão recomendado)
Com @preact/preset-vite, o aliasing é automático e você não deve escrever resolve.alias à mão. O preset ativa os aliases de React por você: a opção reactAliasesEnabled os controla e vem definida como true a menos que você a desative. Ele também configura a transform de JSX para você.
// vite.config.ts
import { defineConfig } from 'vite';
import preact from '@preact/preset-vite';
export default defineConfig({
plugins: [preact()], // JSX + react→preact/compat aliasing handled automatically
});
Se você usa o Vite sem o preset, adicione o fallback manual:
export default defineConfig({
resolve: {
alias: {
react: 'preact/compat',
'react-dom/test-utils': 'preact/test-utils',
'react-dom': 'preact/compat',
'react/jsx-runtime': 'preact/jsx-runtime',
},
},
});
Webpack
No webpack, o alias de react-dom precisa estar listado abaixo de react-dom/test-utils; caso contrário, a regra mais abrangente de react-dom sobrescreve o mapeamento de test-utils e os utilitários de teste resolvem silenciosamente para o módulo errado.
const config = {
resolve: {
alias: {
react: 'preact/compat',
'react-dom/test-utils': 'preact/test-utils',
'react-dom': 'preact/compat', // Must be below test-utils
'react/jsx-runtime': 'preact/jsx-runtime',
},
},
};
Rollup
Instale @rollup/plugin-alias e registre-o antes de @rollup/plugin-node-resolve, para que as reescritas aconteçam antes de o Rollup resolver os módulos.
import alias from '@rollup/plugin-alias';
export default {
plugins: [
alias({
entries: [
{ find: 'react', replacement: 'preact/compat' },
{ find: 'react-dom/test-utils', replacement: 'preact/test-utils' },
{ find: 'react-dom', replacement: 'preact/compat' },
{ find: 'react/jsx-runtime', replacement: 'preact/jsx-runtime' },
],
}),
],
};
Node / Next.js (sem alias de bundler)
Runtimes Node ignoram aliases de bundler, incluindo o Next.js, então o alias vai no package.json, usando o pacote publicado @preact/compat. Esse pacote com escopo existe apenas para que o aliasing nativo do npm tenha algo para apontar; sua função inteira é reexportar preact/compat sem alterações. Note que o @preact/compat com escopo não é o preact-compat sem escopo, que está descontinuado.
{
"dependencies": {
"react": "npm:@preact/compat",
"react-dom": "npm:@preact/compat"
}
}
Jest
O Jest reescreve caminhos de módulos com entradas regex sob moduleNameMapper:
{
"moduleNameMapper": {
"^react$": "preact/compat",
"^react-dom/test-utils$": "preact/test-utils",
"^react-dom$": "preact/compat",
"^react/jsx-runtime$": "preact/jsx-runtime"
}
}
TypeScript
O TypeScript resolve tipos de forma independente do seu bundler, então mapeie os caminhos no tsconfig.json e habilite skipLibCheck. Ative skipLibCheck porque um punhado de bibliotecas React se apoia em tipos que o compat não fornece, e uma verificação completa de cada .d.ts em node_modules vai falhar nessas declarações.
{
"compilerOptions": {
"skipLibCheck": true,
"baseUrl": "./",
"paths": {
"react": ["./node_modules/preact/compat/"],
"react/jsx-runtime": ["./node_modules/preact/jsx-runtime"],
"react-dom": ["./node_modules/preact/compat/"],
"react-dom/*": ["./node_modules/preact/compat/*"]
}
}
}
Um Passo a Passo Mínimo de Migração
Migrar uma aplicação React existente para o Preact com tooling moderno é uma operação de quatro passos:
- Troque as dependências. Remova
react,react-dome seus@types, já que o Preact traz seus próprios tipos TypeScript, depois rodenpm install preactenpm install -D @preact/preset-vite. - Adicione o preset. Coloque
preact()nos plugins do Vite. Ele cuida tanto da transform de JSX quanto do aliasreact → preact/compat, então você pode deletar qualquer configuração manual deesbuild.jsxInject/jsxFactoryvinda de setups da era do Vite 2. - Mude o entry point de renderização. Troque a chamada de montagem do React DOM pelo
renderdo Preact:
// Before
import ReactDOM from 'react-dom';
ReactDOM.render(<App />, document.getElementById('root'));
// After
import { render } from 'preact';
render(<App />, document.getElementById('root'));
- Faça o build e verifique o tamanho. O ganho é o ponto central: o core do Preact mais
preact/compatfica em torno de 9,5KB min+gzip, contra algo mais próximo de 60KB para React 19 mais React DOM, quase tudo isso no entryreact-dom/client. Para uma aplicação cujos componentes já resolvem através do compat, essa diferença sai praticamente de graça.
Quando o preact/compat quebra?
O compat cobre a API pública do React, não seus internals. Bibliotecas que acessam caminhos internos privados de react-dom, ou que se apoiam em algumas das APIs mais novas do React 19, podem quebrar mesmo com o alias correto, então verifique cada dependência antes de subir para produção. Incompatibilidades de tipos vindas de bibliotecas tipadas para React são esperadas e resolvidas com skipLibCheck; as falhas em runtime é que merecem atenção, e session replays dessas integrações frequentemente as revelam como erros de console lançados de dentro de uma dependência, e não do seu próprio código.
Uma checagem rápida antes de adotar uma biblioteca:
- Faça um grep no pacote procurando imports internos profundos de
react-dom/, o sinal de quebra mais comum. - Verifique APIs exclusivas do React 19 das quais a biblioteca depende; confirme a cobertura na release atual do Preact em vez de presumir.
- Rode a suíte de testes da própria biblioteca sob o
moduleNameMapperdo Jest mostrado acima para pegar falhas cedo. - Faça um smoke test em dev, observando o console em busca de erros originados dentro da dependência.
Usuários de SSR e de frameworks enfrentam uma classe distinta de problema: como aliases de bundler não se aplicam no Node, Next.js e runtimes similares precisam do alias no package.json, e o caminho de ssrLoadModule do Vite pode contornar parte da configuração de alias, então confirme que tanto o cliente quanto o servidor resolvem para preact/compat.
Crie os aliases das quatro entradas para o seu toolchain, rode os testes das suas dependências através do mesmo mapeamento, e você poderá reutilizar a maior parte do ecossistema React por uma fração dos bytes. As exceções honestas são bibliotecas acopladas aos internals do React em vez de sua API pública. Comece adicionando @preact/preset-vite em uma branch e medindo seu bundle de produção antes e depois.
Perguntas Frequentes
Qual é a diferença entre @preact/compat e o antigo pacote preact-compat?
O @preact/compat com escopo é um pacote npm ativo que reexporta preact/compat, usado apenas para criar alias de react via package.json em runtimes Node como o Next.js, onde aliases de bundler não se aplicam. O preact-compat sem escopo é um pacote diferente e arquivado, cujo repositório está em modo somente leitura desde dezembro de 2021; ele mirava o Preact 8.x, e o Preact X agora traz o compat dentro do core. Nunca instale o sem escopo.
Ainda preciso escrever resolve.alias manualmente se eu uso @preact/preset-vite?
Não. Com @preact/preset-vite, o aliasing de react e react-dom para preact/compat acontece automaticamente, controlado pela opção reactAliasesEnabled, que fica ativa a menos que você a desligue. Adicionar preact() aos seus plugins do Vite cuida tanto da transform de JSX quanto do aliasing, então escrever resolve.alias à mão é redundante e pode gerar conflito. Você só escreve o bloco manual com as quatro entradas quando roda o Vite sem o preset.
Por que meus utilitários de teste resolvem para o módulo errado depois do aliasing no webpack?
Porque o alias de react-dom está listado acima de react-dom/test-utils na sua configuração do webpack. O webpack casa primeiro com a regra mais abrangente de react-dom, então ela sobrescreve o mapeamento mais específico de test-utils e os utilitários de teste resolvem silenciosamente para preact/compat em vez de preact/test-utils. Corrija colocando a entrada react-dom abaixo de react-dom/test-utils. O Rollup tem uma regra de ordenação relacionada: coloque @rollup/plugin-alias antes de @rollup/plugin-node-resolve.
Por que uma biblioteca React quebra mesmo com meu alias de preact/compat correto?
Porque o compat mapeia a API pública do React, não seus internals. Bibliotecas que importam caminhos internos profundos de react-dom, ou que dependem das APIs mais recentes do React 19, podem falhar em runtime mesmo com um alias correto. Isso aparece como erros de console lançados de dentro da dependência, não do seu próprio código. Antes de adotar uma biblioteca, faça um grep procurando imports profundos de react-dom/ e rode a suíte de testes dela sob o moduleNameMapper do Jest.
Gain Debugging Superpowers
Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers.
Star on GitHub12k