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

Lazy-load tu wallet SDK para arreglar INP y pasar Core Web Vitals

Los SDKs de wallet-connect son el mayor asesino de INP en sitios Web3. Cargarlos eager en cada página cuesta 200-400KB de JS y 200-400ms de TBT. Aquí está cómo lazy-loadearlos en 30 minutos.

Time
30-45 minutes
Difficulty
Intermediate
Impact
High

Por qué importa esto

Estado anterior (cómo se ve lo malo)

// 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

Paso 1: Mide tu INP base

Abre Chrome DevTools, ve a la pestaña Performance, throttlea a "Slow 4G" y 4x CPU slowdown (simula Android de gama media). Recarga tu homepage y captura un trace de Performance. Anota el Total Blocking Time (TBT) e Interaction to Next Paint (INP). Cualquier cosa arriba de 200ms INP falla CWV.

Paso 2: Identifica el wallet SDK en tu bundle

Corre un bundle analyzer. Para Next.js: ANALYZE=true npm run build. Para Vite: vite-bundle-visualizer. Busca @rainbow-me/rainbowkit, @web3modal/wagmi, wagmi, ethers, viem. Estos típicamente representan 200-500KB de JS en sitios Web3. Ese es tu objetivo 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

Paso 3: Marca el botón de connect con un atributo data

Añade data-connect-wallet a cada botón <Connect Wallet> a través de tu sitio. Este es el trigger que carga el SDK. No uses handlers onClick porque necesitamos detectar el click antes de que el handler corra (el handler no existe todavía en ese punto).

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

Paso 4: Implementa el wrapper de dynamic import

Usa el dynamic() de Next.js con ssr:false para lazy-loadear el wallet provider. El componente wrapper renderiza children directamente hasta que un botón connect es clickeado, luego carga el SDK y envuelve los children en el provider real. Usa el código del "Estado posterior" como tu plantilla.

Paso 5: Mueve la inicialización del SDK al componente interno

Todo el código de config de wagmi/RainbowKit/Web3Modal va en el componente interno (cargado bajo demanda). El wrapper externo solo escucha el trigger. De esta manera, el código de config del SDK solo corre cuando se necesita.

Paso 6: Prueba el flujo de connect end-to-end

Haz click en "Connect Wallet" en tu homepage. Verifica: (1) el SDK carga (la pestaña Network muestra los chunks), (2) el modal abre, (3) la conexión de wallet completa, (4) las acciones post-connect funcionan normalmente. La experiencia hacia el usuario debería ser idéntica a antes.

Paso 7: Re-mide el INP y confirma la mejora

Vuelve a correr el trace de Performance de Chrome DevTools del Paso 1. INP debería caer significativamente (típico: 380ms → 180ms). Corre PageSpeed Insights para la versión de field-data (la data de CrUX toma 28 días para actualizar completamente pero la data de lab actualiza inmediatamente). Documenta el antes/después para tu equipo.

FREE WEB3 AUDIT

Mira dónde aplica este playbook en tu sitio.

Corre una auditoría Crawlux gratis antes de empezar el playbook. Te dice qué correcciones son más urgentes.

Primera auditoría gratis · Sin registro · 60 segundos · Full PDF report

Estado posterior (cómo se ve lo bueno)

// 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>
  );
}

Cómo validar la corrección

Errores comunes

Pitfall

Olvidar la dependencia de contexto de wagmi

Algunos componentes aguas abajo pueden usar useAccount() de wagmi esperando que el provider exista. Envuelve esos con renderizado condicional o usa un valor por defecto cuando el SDK no esté cargado todavía.

Pitfall

Errores SSR de dynamic import

Siempre usa { ssr: false } en las opciones de dynamic(). Los SDKs de wallet asumen globales del navegador (window, localStorage) y se caen durante SSR.

Pitfall

Auto-connect en reload de página no funciona

Si los usuarios tenían auto-connect habilitado, esperan ser auto-conectados al recargar. Solución: verifica la cookie/localStorage de conexión persistida en el mount inicial y dispara setWalletNeeded(true) si se encuentra. De lo contrario auto-connect se rompe.

Pitfall

Botón connect en una ruta diferente disparando carga demasiado temprano

Si tu sitio tiene el botón connect en un header global y un usuario aterriza en /blog/some-post/, el SDK carga al click pero el usuario ya está profundo en el contenido. Eso está bien en realidad; el objetivo es evitar cargar en el mount inicial de página, no nunca cargar.

Pitfall

Problemas de tree-shaking con providers de wagmi

wagmi 2.x ha sido más agresivo con tree-shaking. Algunos imports disparan carga completa del SDK. Usa el bundle analyzer para verificar que tu chunk dinámico no incluya accidentalmente el SDK entero en el main bundle.

Si algo se rompe: rollback

Revierte WalletProvider.tsx a la versión eager-load. La wallet funciona exactamente como antes en minutos. INP regresa a la línea base. Considera este rollback solo si el patrón dynamic-load rompe flujos de usuario; la mejora de performance vale esfuerzo significativo para corregir hacia adelante.

Corre una auditoría Crawlux gratis sobre esta corrección

Crawlux valida las correcciones de schema, técnicas y AEO de este playbook automáticamente. Plan gratis en un dominio.

Ejecutar auditoría gratuita →

Preguntas frecuentes

¿Funciona esto con Vite o Vue u otros frameworks?

Sí. El patrón es universal: dynamic import detrás de un trigger de acción de usuario. Vite tiene React.lazy() con Suspense. Vue tiene defineAsyncComponent. Misma idea: solo carga el wallet SDK bajo demanda, no en el mount inicial.

¿Qué si necesito conexión de wallet al inicio de la app (ej., dashboard SaaS)?

Entonces el lazy-loading no es el patrón correcto; eager-load es correcto para rutas de app. Aplica este patrón solo a páginas de marketing y páginas de contenido donde la conexión de wallet es opcional. Usa carga basada en ruta: las rutas de marketing lazy-load, las rutas de app eager-load.

¿Esto romperá los deep links de WalletConnect?

No. Las URIs de WalletConnect se generan cuando el modal abre. Mientras el SDK cargue cuando el modal necesita renderizar, los deep links funcionan normalmente.

¿Cómo manejo el provider inyectado de metamask?

El window.ethereum inyectado de MetaMask está disponible sin el SDK. Si quieres detectar la presencia de MetaMask en la carga inicial (sin cargar el SDK completo), verifica window.ethereum?.isMetaMask. Lazy-load el SDK solo cuando el usuario hace click en connect.

¿Esto afecta el SEO?

Positivamente. Las páginas más rápidas rankean mejor. INP es una señal de ranking confirmada en el algoritmo de Google de 2026. El SDK no es contenido SEO-relevante (es código funcional), así que removerlo de la carga inicial no daña nada que Google indexe.

Playbooks relacionados

Guías pilares

Módulos de auditoría

RUN YOUR FIRST AUDIT

Corre el playbook contra una auditoría real.

Recibe un reporte de auditoría Crawlux gratis y úsalo como línea base para el trabajo en este playbook.

Primera auditoría gratis · Sin registro · 60 segundos · Full PDF report

Audit this fix → Free audit