Advanced (Actualizado: 2/6/2026)

Analisis de bundles con Claude Code para Vite, Astro y Next.js

Analiza bundles JS, dependencias duplicadas, dynamic import y presupuestos CI con Claude Code.

Analisis de bundles con Claude Code para Vite, Astro y Next.js

Un bundle de JavaScript no se vuelve pesado de golpe. Normalmente crece con cambios razonables: una grafica para el panel, un editor enriquecido, una libreria de fechas, un mapa, un reproductor de video, un SDK de autenticacion o codigo para A/B testing. El problema no es que esas funciones sobren, sino que muchas veces se entregan en la primera carga a usuarios que todavia no las necesitan.

El analisis de bundle consiste en abrir el resultado de produccion y preguntar: “que estamos enviando al navegador?”. Para alguien que empieza, es como pesar una maleta y luego revisar que objetos la hicieron pesada. Claude Code puede ayudar, pero necesita una tarea con medicion, diagnostico, cambio pequeno, verificacion y presupuesto en CI. Pedir solo “optimiza performance” suele producir cambios grandes y dificiles de revisar.

Esta guia cubre proyectos tipo Vite, Astro y Next.js. Veras rollup-plugin-visualizer, source-map-explorer, deteccion de paquetes duplicados, dynamic import, bundle budget en CI y un flujo de revision con Claude Code. Para el contexto completo, enlaza esta lectura con code splitting, tree shaking y optimizacion de performance.

Flujo de trabajo

Los numeros habituales son raw, gzip y brotli. Raw sirve para leer diagramas; gzip y brotli se parecen mas a lo que viaja por la red. Aun asi, una dependencia que comprime bien puede seguir costando parseo y ejecucion, asi que no conviene mirar un unico numero.

flowchart LR
  A["production build"] --> B["visual report"]
  B --> C["duplicate packages"]
  C --> D["replace or dedupe"]
  B --> E["route-level split"]
  D --> F["bundle budget in CI"]
  E --> F
  F --> G["Claude Code review"]

Usa documentacion oficial como base: Building for Production de Vite, la receta de Astro para analyze bundle size, Package Bundling de Next.js, Performance budgets 101 de web.dev y la guia oficial de Claude Code.

Visualizar Vite y Astro

En Vite, el primer paso practico es rollup-plugin-visualizer. Genera un HTML con treemap para ver que librerias ocupan espacio.

npm install -D rollup-plugin-visualizer
// vite.config.ts
import { defineConfig } from "vite";
import { visualizer } from "rollup-plugin-visualizer";

export default defineConfig({
  plugins: [
    visualizer({
      filename: "dist/bundle-stats.html",
      template: "treemap",
      gzipSize: true,
      brotliSize: true,
      open: false
    })
  ],
  build: {
    sourcemap: true,
    rollupOptions: {
      output: {
        manualChunks: {
          react: ["react", "react-dom"],
          charts: ["recharts"],
          editor: ["@tiptap/react", "@tiptap/starter-kit"]
        }
      }
    }
  }
});

En Astro se coloca dentro de la configuracion de Vite:

// astro.config.mjs
import { defineConfig } from "astro/config";
import { visualizer } from "rollup-plugin-visualizer";

export default defineConfig({
  vite: {
    plugins: [
      visualizer({
        filename: "dist/bundle-stats.html",
        template: "treemap",
        gzipSize: true,
        brotliSize: true
      })
    ],
    build: { sourcemap: true }
  }
});
npm run build
open dist/bundle-stats.html

En Windows PowerShell:

start dist/bundle-stats.html

Busca elementos que no pertenecen a la primera vista: graficas de administracion, editores, mapas, video, procesadores Markdown, librerias de fechas y UI interna.

Source maps y Next.js

source-map-explorer usa los archivos JS y sus source maps para mostrar de donde viene cada parte del bundle.

npm install -D source-map-explorer
npm run build
npx source-map-explorer "dist/assets/*.js" --html dist/source-map-report.html

En Next.js, confirma primero la version y el builder. Segun el caso, usa el analizador oficial o @next/bundle-analyzer.

// next.config.mjs
import bundleAnalyzer from "@next/bundle-analyzer";

const withBundleAnalyzer = bundleAnalyzer({
  enabled: process.env.ANALYZE === "true"
});

export default withBundleAnalyzer({
  reactStrictMode: true
});
npm install -D @next/bundle-analyzer
ANALYZE=true npm run build

En PowerShell:

$env:ANALYZE="true"; npm run build

Dependencias duplicadas

Una libreria grande se ve rapido, pero los duplicados se esconden. Dos versiones de date-fns, mezcla de lodash y lodash-es, o dependencias peer mal alineadas pueden duplicar trabajo.

npm ls date-fns lodash lodash-es
npm dedupe

Con pnpm:

pnpm why date-fns
pnpm dedupe

Prompt recomendado:

Analiza el bundle de produccion de este repositorio.
1. Lista dependencias pesadas usando dist/bundle-stats.html o source-map-explorer
2. Usa npm ls o pnpm why para detectar paquetes duplicados
3. Separa candidatos en replace, dedupe, dynamic import y remove
4. Conserva UI existente, texto SEO, CTAs y eventos analytics
5. Haz el cambio minimo seguro y ejecuta npm run build mas el bundle budget check
CausaSolucionVerificacion
moment en todo el sitioIntl.DateTimeFormat o helper pequenozona horaria e idioma
import completo de lodashimport por funcion o API nativamezcla ESM/CommonJS
editor solo admincargar tras clic o ruta adminloading y error
graficas en homeseparar reportesresponsive
versiones duplicadasdedupe o alinear versionespeer dependency

dynamic import

dynamic import no borra codigo; lo mueve al momento en que el usuario lo necesita. Es util para reportes, editores, mapas y modales poco frecuentes.

// src/features/reports/ReportsButton.tsx
import { useState } from "react";

export function ReportsButton() {
  const [html, setHtml] = useState<string>("");
  const [loading, setLoading] = useState(false);

  async function handleClick() {
    setLoading(true);
    const { renderRevenueReport } = await import("./renderRevenueReport");
    setHtml(renderRevenueReport([12000, 18400, 9300]));
    setLoading(false);
  }

  return (
    <section>
      <button type="button" onClick={handleClick} disabled={loading}>
        {loading ? "Generando reporte" : "Ver reporte de ingresos"}
      </button>
      <output aria-live="polite">{html}</output>
    </section>
  );
}
// src/features/reports/renderRevenueReport.ts
export function renderRevenueReport(values: number[]): string {
  const total = values.reduce((sum, value) => sum + value, 0);
  return `Total del mes: ${new Intl.NumberFormat("es-ES").format(total)} EUR`;
}

En Next.js, deja el texto SEO, precios, enlaces de compra y CTA de consulta fuera del chunk tardio. Retrasa solo la UI pesada.

// app/admin/EditorSlot.tsx
"use client";

import dynamic from "next/dynamic";

const RichEditor = dynamic(() => import("./RichEditor"), {
  ssr: false,
  loading: () => <p aria-live="polite">Cargando editor...</p>
});

export function EditorSlot() {
  return <RichEditor initialMarkdown="# Draft" />;
}

Presupuesto en CI

Sin CI, el bundle vuelve a crecer. Este script falla si el total gzip o un archivo individual supera el presupuesto.

// scripts/check-bundle-budget.mjs
import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
import path from "node:path";
import { brotliCompressSync, gzipSync } from "node:zlib";

const targetDir = "dist/assets";
const maxTotalGzip = 220 * 1024;
const maxSingleGzip = 140 * 1024;

function walk(dir) {
  return readdirSync(dir, { withFileTypes: true }).flatMap((entry) => {
    const fullPath = path.join(dir, entry.name);
    if (entry.isDirectory()) return walk(fullPath);
    return /\.(js|css)$/.test(entry.name) ? [fullPath] : [];
  });
}

if (!existsSync(targetDir)) {
  console.error(`Missing ${targetDir}. Run npm run build first.`);
  process.exit(1);
}

const rows = walk(targetDir).map((file) => {
  const content = readFileSync(file);
  return {
    file,
    raw: statSync(file).size,
    gzip: gzipSync(content).byteLength,
    brotli: brotliCompressSync(content).byteLength
  };
});

const totalGzip = rows.reduce((sum, row) => sum + row.gzip, 0);
const tooLarge = rows.filter((row) => row.gzip > maxSingleGzip);

if (totalGzip > maxTotalGzip || tooLarge.length > 0) {
  console.error(`Bundle budget failed. total gzip=${totalGzip} bytes`);
  process.exit(1);
}

console.log(`Bundle budget passed. total gzip=${totalGzip} bytes`);
# .github/workflows/bundle-budget.yml
name: Bundle Budget
on: [pull_request]
jobs:
  bundle-budget:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 22
          cache: npm
      - run: npm ci
      - run: npm run build
      - run: node scripts/check-bundle-budget.mjs

El primer presupuesto debe ser realista: toma el valor actual, suma alrededor de 10% y pide explicacion cuando un PR lo supere.

Casos reales

Primero, un dashboard SaaS. La lista, busqueda, navegacion y CTA principal deben cargar pronto; graficas, auditoria, CSV y reportes de facturacion pueden ir en otro chunk.

Segundo, un sitio de contenidos o cursos. El texto, los enlaces de compra y la CTA de consulta deben renderizar temprano. La vista previa Markdown, recorte de imagenes y panel de campanas pueden esperar. Esto afecta anuncios, afiliados y leads; mide el resultado con analytics implementation.

Tercero, una landing con mapa, video, calculadora o formulario. La primera vista muestra oferta, precio y accion; los widgets pesados cargan al hacer scroll o clic. Revisa tambien video player y accesibilidad.

Cuarto, una libreria UI interna. Un import de @company/ui puede arrastrar DatePicker, Modal, Chart e iconos aunque solo uses Button. Divide exports y declara side effects de CSS y tema.

Errores frecuentes

No midas con dev build. No dividas cada componente en chunks pequenos. No publiques source maps sin una politica de seguridad. No congeles manualChunks para siempre. Y no dejes que Claude Code solo modifique codigo: pidelo tambien como reviewer.

Revisa este PR desde el punto de vista de bundle analysis.
- Son necesarias las dependencias del primer load?
- Hay versiones duplicadas?
- Los dynamic imports tienen loading y error state?
- Texto SEO, precios, CTA y analytics quedaron fuera de chunks tardios?
- El log del budget ayuda a encontrar la causa?
- Resume npm run build y las rutas de reportes generados.

Monetizacion

Reducir bundle no es solo limpieza tecnica. Si el primer render mejora, texto, productos, recursos gratuitos y CTA de consultoria aparecen antes. En ClaudeCodeLab eso impacta anuncios, venta de plantillas y solicitudes de formacion.

Para practicar, empieza por la hoja gratuita. Para plantillas reutilizables, revisa productos. Si tu equipo necesita ordenar Vite, Astro, Next.js, CLAUDE.md, CI y reglas de review, usa formacion y consultoria Claude Code.

Verificacion practica

Los ejemplos se comprobaron contra una estructura tipo Vite/React: el visualizer escribe HTML, source-map-explorer requiere source maps, y el script de presupuesto usa fs, path y zlib. La conclusion practica fue separar contenido critico de contenido diferible. Editores y graficas suelen ser buenos candidatos; texto, precios, enlaces de compra y CTA de consulta normalmente no.

Resumen

Un flujo serio con Claude Code empieza con evidencia: build de produccion, visualizacion, duplicados, dynamic import, presupuesto CI y review. Bundle analysis, tree shaking y code splitting forman una misma disciplina para mantener rapida una aplicacion que ya recibe trafico y genera ingresos.

#Claude Code #bundle analysis #Webpack #Vite #performance
Gratis

PDF gratis: cheatsheet de Claude Code

Introduce tu email y descarga una hoja con comandos, hábitos de revisión y flujos seguros.

Cuidamos tus datos y no enviamos spam.

Masa

Sobre el autor

Masa

Ingeniero enfocado en workflows prácticos con Claude Code.