NEWWorld's first AI visibility audit tool for Web3 is live.Run free audit →
PLAYBOOK Technical Last reviewed

Lazy-load seu wallet SDK para corrigir INP e passar Core Web Vitals

Os SDKs de wallet-connect são o maior assassino de INP em sites Web3. Carregar esses SDKs de forma eager em cada página custa 200-400KB de JS e 200-400ms de TBT. Veja como fazer o lazy-load deles em 30 minutos.

Time
30-45 minutes
Difficulty
Intermediate
Impact
High

Por que isso importa

Estado anterior (como o ruim se parece)

// pages/_app.tsx (Next.js example)
import { WagmiConfig, createConfig } from 'wagmi';
import { ConnectKitProvider, getDefaultConfig } from 'connectkit';

// SDK loads on every page mount, even marketing pages
const config = createConfig(getDefaultConfig({
  appName: 'My dApp',
  walletConnectProjectId: 'xxx',
}));

export default function App({ Component, pageProps }) {
  return (
    <WagmiConfig config={config}>
      <ConnectKitProvider>
        <Component {...pageProps} />
      </ConnectKitProvider>
    </WagmiConfig>
  );
}

Paso a paso

Passo 1: Meça seu INP base

Abra o Chrome DevTools, vá para a aba Performance, faça throttle para "Slow 4G" e 4x CPU slowdown (simula Android de gama média). Recarregue sua homepage e capture um trace de Performance. Anote o Total Blocking Time (TBT) e Interaction to Next Paint (INP). Qualquer coisa acima de 200ms INP falha o CWV.

Passo 2: Identifique o wallet SDK no seu bundle

Rode um bundle analyzer. Para Next.js: ANALYZE=true npm run build. Para Vite: vite-bundle-visualizer. Busque @rainbow-me/rainbowkit, @web3modal/wagmi, wagmi, ethers, viem. Esses tipicamente representam 200-500KB de JS em sites Web3. Esse é seu alvo para lazy-loading.

# Next.js bundle analyzer
npm i -D @next/bundle-analyzer
# Then add to next.config.js and run:
ANALYZE=true npm run build

Passo 3: Marque o botão de connect com um atributo data

Adicione data-connect-wallet a cada botão <Connect Wallet> através do seu site. Esse é o trigger que carrega o SDK. Não use handlers onClick porque precisamos detectar o click antes que o handler rode (o handler ainda não existe nesse ponto).

<button data-connect-wallet className="...">Connect Wallet</button>

Passo 4: Implemente o wrapper de dynamic import

Use o dynamic() do Next.js com ssr:false para fazer lazy-load do wallet provider. O componente wrapper renderiza children diretamente até que um botão connect seja clicado, depois carrega o SDK e envolve os children no provider real. Use o código do "Estado posterior" como seu template.

Passo 5: Mova a inicialização do SDK para o componente interno

Todo o código de config de wagmi/RainbowKit/Web3Modal vai no componente interno (carregado sob demanda). O wrapper externo apenas escuta o trigger. Dessa forma, o código de config do SDK só roda quando é necessário.

Passo 6: Teste o fluxo de connect end-to-end

Clique em "Connect Wallet" na sua homepage. Verifique: (1) o SDK carrega (a aba Network mostra os chunks), (2) o modal abre, (3) a conexão de wallet completa, (4) as ações pós-connect funcionam normalmente. A experiência para o usuário deve ser idêntica a antes.

Passo 7: Meça o INP de novo e confirme a melhoria

Rode de novo o trace de Performance do Chrome DevTools do Passo 1. INP deve cair significativamente (típico: 380ms → 180ms). Rode PageSpeed Insights para a versão de field-data (a data de CrUX leva 28 dias para atualizar completamente, porém a data de lab atualiza imediatamente). Documente o antes/depois para sua equipe.

FREE WEB3 AUDIT

Veja onde esse playbook se aplica no seu site.

Rode uma auditoria Crawlux grátis antes de começar o playbook. Diz quais correções são mais urgentes.

Primeira auditoria grátis · Sem cadastro · 60 segundos · Full PDF report

Estado posterior (como o bom se parece)

// components/WalletProvider.tsx - dynamic import
import dynamic from 'next/dynamic';
import { useState } from 'react';

const WalletProviderInner = dynamic(
  () => import('./WalletProviderInner'),
  { ssr: false, loading: () => null }
);

export function WalletProvider({ children }) {
  const [walletNeeded, setWalletNeeded] = useState(false);

  // Listen for the connect button click
  if (!walletNeeded) {
    return (
      <div onClick={(e) => {
        if (e.target.closest('[data-connect-wallet]')) {
          setWalletNeeded(true);
        }
      }}>
        {children}
      </div>
    );
  }

  return <WalletProviderInner>{children}</WalletProviderInner>;
}

// components/WalletProviderInner.tsx - actual SDK
import { WagmiConfig, createConfig } from 'wagmi';
import { ConnectKitProvider, getDefaultConfig } from 'connectkit';

const config = createConfig(getDefaultConfig({
  appName: 'My dApp',
  walletConnectProjectId: 'xxx',
}));

export default function WalletProviderInner({ children }) {
  return (
    <WagmiConfig config={config}>
      <ConnectKitProvider>{children}</ConnectKitProvider>
    </WagmiConfig>
  );
}

Como validar a correção

Erros comuns

Pitfall

Esquecer a dependência de contexto do wagmi

Alguns componentes rio abaixo podem usar useAccount() do wagmi esperando que o provider exista. Envolva esses com renderização condicional ou use um valor padrão quando o SDK ainda não estiver carregado.

Pitfall

Erros SSR de dynamic import

Sempre use { ssr: false } nas opções de dynamic(). Os SDKs de wallet assumem globais do navegador (window, localStorage) e caem durante SSR.

Pitfall

Auto-connect en reload de página no funciona

Se os usuários tinham auto-connect habilitado, esperam ser auto-conectados ao recarregar. Solução: verifique a cookie/localStorage de conexão persistida no mount inicial e dispare setWalletNeeded(true) se for encontrado. Caso contrário auto-connect quebra.

Pitfall

Botão connect em uma rota diferente disparando carga cedo demais

Se seu site tem o botão connect em um header global e um usuário chega em /blog/some-post/, o SDK carrega ao click, porém o usuário já está profundo no conteúdo. Isso está bem na verdade; o objetivo é evitar carregar no mount inicial de página, não nunca carregar.

Pitfall

Problemas de tree-shaking com providers do wagmi

wagmi 2.x tem sido mais agressivo com tree-shaking. Alguns imports disparam carga completa do SDK. Use o bundle analyzer para verificar que seu chunk dinâmico não inclua acidentalmente o SDK inteiro no main bundle.

Si algo se rompe: rollback

Reverta WalletProvider.tsx para a versão eager-load. A wallet funciona exatamente como antes em minutos. INP volta à linha base. Considere esse rollback apenas se o padrão dynamic-load quebra fluxos de usuário; a melhoria de performance vale esforço significativo para corrigir para frente.

Rode uma auditoria Crawlux grátis sobre essa correção

Crawlux valida as correções de schema, técnicas e AEO desse playbook automaticamente. Plano grátis em um domínio.

Executar auditoria gratuita →

FAQ

Isso funciona com Vite ou Vue ou outros frameworks?

Sim. O padrão é universal: dynamic import atrás de um trigger de ação de usuário. Vite tem React.lazy() com Suspense. Vue tem defineAsyncComponent. Mesma ideia: só carrega o wallet SDK sob demanda, não no mount inicial.

E se eu preciso de conexão de wallet no início do app (ex., dashboard SaaS)?

Então o lazy-loading não é o padrão correto; eager-load é correto para rotas de app. Aplique esse padrão apenas a páginas de marketing e páginas de conteúdo onde a conexão de wallet é opcional. Use carga baseada em rota: as rotas de marketing lazy-load, as rotas de app eager-load.

Isso vai quebrar os deep links do WalletConnect?

Não. As URIs do WalletConnect são geradas quando o modal abre. Enquanto o SDK carregar quando o modal precisa renderizar, os deep links funcionam normalmente.

Como eu manejo o provider injetado do metamask?

O window.ethereum injetado do MetaMask está disponível sem o SDK. Se você quer detectar a presença do MetaMask na carga inicial (sem carregar o SDK completo), verifique window.ethereum?.isMetaMask. Faça lazy-load do SDK apenas quando o usuário clica em connect.

Isso afeta o SEO?

Positivamente. As páginas mais rápidas rankeiam melhor. INP é um sinal de ranking confirmado no algoritmo do Google de 2026. O SDK não é conteúdo SEO-relevante (é código funcional), então removê-lo da carga inicial não danifica nada que o Google indexe.

Playbooks relacionados

Guias pilares

Módulos de auditoria

RUN YOUR FIRST AUDIT

Rode o playbook contra uma auditoria real.

Receba um relatório de auditoria Crawlux grátis e use-o como linha base para o trabalho nesse playbook.

Primeira auditoria grátis · Sem cadastro · 60 segundos · Full PDF report

Audit this fix → Free audit