Voltar para o Blog

Vanilla JavaScript em 2026: Por Que Desenvolvedores Estao Abandonando Frameworks

Ola HaWkers, algo interessante esta acontecendo no ecossistema JavaScript: desenvolvedores experientes estao cada vez mais optando por JavaScript puro em vez de frameworks complexos. O que antes era visto como "voltar ao passado" agora e considerado uma escolha estrategica e sofisticada.

Vamos entender esse movimento, quando faz sentido usar vanilla JavaScript e como as APIs modernas do navegador tornaram isso viavel em 2026.

O Cansaco dos Frameworks

Framework Fatigue E Real

A comunidade JavaScript esta exausta de mudancas constantes.

Sintomas do framework fatigue:

  • Novo framework promissor a cada 6 meses
  • Atualizacoes major com breaking changes frequentes
  • Tempo gasto aprendendo ao inves de construindo
  • Dependencias que viram vulnerabilidades
  • Build tools que mudam constantemente

Linha do tempo da complexidade:

Ano O Que Era Necessario
2010 jQuery
2014 Gulp, Bower, Angular 1.x
2016 Webpack, React, Redux, Babel
2018 Create React App, TypeScript, CSS-in-JS
2020 Next.js, Vite, Tailwind, State machines
2022 Server Components, Edge Functions, Hydration
2024 AI coding assistants, Meta-frameworks

O problema:

"Passei mais tempo configurando build tools do que escrevendo codigo de produto." - Desenvolvedor anonimo em survey 2025

JavaScript Moderno E Poderoso

As APIs Que Mudaram Tudo

O navegador evoluiu drasticamente. Muitas razoes para usar frameworks simplesmente nao existem mais.

Selecao de elementos (antigo problema que jQuery resolvia):

// Antes: precisavamos do jQuery
$('.cards .item');

// Hoje: nativo e igualmente simples
document.querySelectorAll('.cards .item');

// Com helper opcional
const $ = (sel) => document.querySelector(sel);
const $$ = (sel) => [...document.querySelectorAll(sel)];

// Uso
const items = $$('.cards .item');
items.forEach(item => item.classList.add('active'));

Manipulacao de classes:

// Antigamente: jQuery ou codigo complexo
element.className = element.className.replace('old', 'new');

// Hoje: classList API limpa e poderosa
element.classList.add('new');
element.classList.remove('old');
element.classList.toggle('active');
element.classList.replace('old', 'new');
element.classList.contains('active'); // boolean

Fetch API vs bibliotecas HTTP:

// Fetch moderno com async/await
async function fetchUsers() {
  try {
    const response = await fetch('/api/users', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ page: 1 }),
    });

    if (!response.ok) {
      throw new Error(`HTTP error: ${response.status}`);
    }

    return await response.json();
  } catch (error) {
    console.error('Fetch failed:', error);
    throw error;
  }
}

// Com AbortController para cancelamento
const controller = new AbortController();

fetch('/api/data', { signal: controller.signal })
  .then(res => res.json())
  .then(data => console.log(data));

// Cancelar a requisicao
controller.abort();

Web Components: Componentes Nativos

Criando Componentes Sem Framework

Web Components permitem encapsulamento real de componentes.

// Definindo um componente customizado
class UserCard extends HTMLElement {
  constructor() {
    super();
    this.attachShadow({ mode: 'open' });
  }

  // Atributos observados para reatividade
  static get observedAttributes() {
    return ['name', 'email', 'avatar'];
  }

  // Lifecycle: quando conectado ao DOM
  connectedCallback() {
    this.render();
  }

  // Lifecycle: quando atributo muda
  attributeChangedCallback(name, oldValue, newValue) {
    if (oldValue !== newValue) {
      this.render();
    }
  }

  render() {
    const name = this.getAttribute('name') || 'Anonimo';
    const email = this.getAttribute('email') || '';
    const avatar = this.getAttribute('avatar') || '/default-avatar.png';

    this.shadowRoot.innerHTML = `
      <style>
        :host {
          display: block;
          padding: 1rem;
          border-radius: 8px;
          background: var(--card-bg, #fff);
          box-shadow: 0 2px 4px rgba(0,0,0,0.1);
        }
        .card {
          display: flex;
          align-items: center;
          gap: 1rem;
        }
        img {
          width: 48px;
          height: 48px;
          border-radius: 50%;
        }
        h3 {
          margin: 0 0 0.25rem;
          font-size: 1.1rem;
        }
        p {
          margin: 0;
          color: #666;
          font-size: 0.9rem;
        }
      </style>
      <div class="card">
        <img src="${avatar}" alt="${name}">
        <div>
          <h3>${name}</h3>
          <p>${email}</p>
        </div>
      </div>
    `;
  }
}

// Registrar o componente
customElements.define('user-card', UserCard);

Uso no HTML:

<user-card
  name="Jeff Bruchado"
  email="jeff@example.com"
  avatar="/jeff.jpg">
</user-card>

<!-- Interagindo via JavaScript -->
<script>
  const card = document.querySelector('user-card');
  card.setAttribute('name', 'Novo Nome');
</script>

Estado Sem Redux

Gerenciamento de Estado Nativo

Voce nao precisa de Redux ou Context API para gerenciar estado.

// Store simples com Proxy para reatividade
function createStore(initialState) {
  const listeners = new Set();

  const state = new Proxy(initialState, {
    set(target, property, value) {
      target[property] = value;
      listeners.forEach(listener => listener(state));
      return true;
    }
  });

  return {
    getState: () => state,
    subscribe: (listener) => {
      listeners.add(listener);
      return () => listeners.delete(listener);
    },
    setState: (updates) => {
      Object.assign(state, updates);
    }
  };
}

// Uso
const store = createStore({
  user: null,
  cart: [],
  loading: false
});

// Subscribing para mudancas
store.subscribe((state) => {
  console.log('State changed:', state);
  updateUI(state);
});

// Atualizando estado
store.setState({ loading: true });
store.setState({ user: { name: 'Jeff' }, loading: false });

Estado com Custom Events:

// Event-driven state management
class StateManager extends EventTarget {
  #state = {};

  constructor(initialState = {}) {
    super();
    this.#state = { ...initialState };
  }

  get state() {
    return { ...this.#state };
  }

  setState(updates) {
    const prevState = { ...this.#state };
    this.#state = { ...this.#state, ...updates };

    this.dispatchEvent(new CustomEvent('statechange', {
      detail: { prevState, state: this.state }
    }));
  }
}

// Uso
const appState = new StateManager({ count: 0 });

appState.addEventListener('statechange', (e) => {
  const { state } = e.detail;
  document.querySelector('#count').textContent = state.count;
});

document.querySelector('#increment').onclick = () => {
  appState.setState({ count: appState.state.count + 1 });
};

Roteamento Client-Side

SPA Routing Sem Framework

A History API permite criar SPAs sem React Router ou Vue Router.

// Router minimalista
class Router {
  constructor() {
    this.routes = new Map();
    this.currentRoute = null;

    // Interceptar cliques em links
    document.addEventListener('click', (e) => {
      if (e.target.matches('a[data-link]')) {
        e.preventDefault();
        this.navigate(e.target.href);
      }
    });

    // Lidar com botao voltar/avancar
    window.addEventListener('popstate', () => {
      this.handleRoute(window.location.pathname);
    });
  }

  addRoute(path, handler) {
    this.routes.set(path, handler);
    return this;
  }

  navigate(url) {
    const path = new URL(url, window.location.origin).pathname;
    window.history.pushState(null, '', path);
    this.handleRoute(path);
  }

  handleRoute(path) {
    // Matching com parametros
    for (const [routePath, handler] of this.routes) {
      const params = this.matchRoute(routePath, path);
      if (params !== null) {
        this.currentRoute = { path, params, handler };
        handler(params);
        return;
      }
    }

    // 404
    const notFound = this.routes.get('*');
    if (notFound) notFound({});
  }

  matchRoute(routePath, path) {
    const routeParts = routePath.split('/');
    const pathParts = path.split('/');

    if (routeParts.length !== pathParts.length) return null;

    const params = {};

    for (let i = 0; i < routeParts.length; i++) {
      if (routeParts[i].startsWith(':')) {
        params[routeParts[i].slice(1)] = pathParts[i];
      } else if (routeParts[i] !== pathParts[i]) {
        return null;
      }
    }

    return params;
  }

  start() {
    this.handleRoute(window.location.pathname);
  }
}

// Configuracao
const router = new Router()
  .addRoute('/', () => renderHome())
  .addRoute('/users', () => renderUsers())
  .addRoute('/users/:id', ({ id }) => renderUser(id))
  .addRoute('*', () => render404());

router.start();

Performance: A Grande Vantagem

Numeros Que Impressionam

Sites em vanilla JavaScript tendem a ser significativamente mais rapidos.

Comparacao de bundle size:

Abordagem Bundle Size TTI
React + Redux + Router ~150 KB ~2.5s
Vue + Vuex + Router ~100 KB ~2.0s
Svelte + Routing ~30 KB ~1.2s
Vanilla JS otimizado ~5-15 KB ~0.5s

Core Web Vitals tipicos:

// Vanilla JS bem escrito
{
  LCP: '0.8s',  // Largest Contentful Paint
  FID: '10ms',  // First Input Delay
  CLS: '0.01',  // Cumulative Layout Shift
  TTI: '0.5s'   // Time to Interactive
}

// Framework tipico
{
  LCP: '2.5s',
  FID: '100ms',
  CLS: '0.1',
  TTI: '3.0s'
}

Lazy loading nativo:

// Carregar modulos sob demanda
async function loadModule(moduleName) {
  const modules = {
    charts: () => import('./modules/charts.js'),
    editor: () => import('./modules/editor.js'),
    admin: () => import('./modules/admin.js'),
  };

  const loader = modules[moduleName];
  if (!loader) throw new Error(`Module ${moduleName} not found`);

  return await loader();
}

// Uso
document.querySelector('#showChart').onclick = async () => {
  const { renderChart } = await loadModule('charts');
  renderChart('#chart-container', data);
};

Quando Usar Cada Abordagem

O Framework Certo Para o Problema Certo

Vanilla JavaScript nao e sempre a resposta certa.

Use vanilla JavaScript quando:

  • Landing pages e sites institucionais
  • Blogs e sites de conteudo
  • Aplicacoes simples com pouca interatividade
  • Widgets embedaveis
  • Performance e prioridade maxima
  • Voce quer evitar dependencias

Use frameworks quando:

  • Aplicacoes complexas com muito estado
  • Equipes grandes que precisam de padroes
  • SPAs com dezenas de telas
  • Necessidade de ecossistema maduro (UI libs, etc)
  • Time ja experiente no framework
  • Prototipagem rapida

Abordagem hibrida:

// Use vanilla JS para a base
// Adicione bibliotecas especificas conforme necessario

// Para graficos
import Chart from 'chart.js/auto';

// Para datas complexas
import { format, parseISO } from 'date-fns';

// Para formularios complexos
// ... mantenha em vanilla ou use lib especifica

// Nao precisa de framework inteiro para usar uma lib

Recursos Para Aprender Mais

Ferramentas e Bibliotecas Leves

Se voce quer simplicidade mas precisa de ajuda pontual.

Bibliotecas minimalistas:

Biblioteca Tamanho Proposito
Alpine.js 15 KB Reatividade simples
htmx 14 KB AJAX declarativo
Lit 5 KB Web Components
Preact 3 KB React-like minimo
Petite Vue 6 KB Vue minimalista

Polyfills modernos (cada vez menos necessarios):

<!-- Apenas se precisar suportar navegadores antigos -->
<script src="https://polyfill.io/v3/polyfill.min.js?features=fetch,Promise,Array.from"></script>

Build tools simples:

// esbuild - bundler extremamente rapido
// package.json
{
  "scripts": {
    "build": "esbuild src/main.js --bundle --minify --outfile=dist/app.js"
  }
}

// Sem configuracao complexa, sem plugins interminaveis

Conclusao

O movimento de retorno ao vanilla JavaScript nao e sobre rejeitar progresso, mas sobre escolher a ferramenta certa para cada trabalho. Em 2026, o JavaScript nativo e poderoso o suficiente para a maioria das aplicacoes web, e muitos desenvolvedores estao descobrindo que menos dependencias significa menos problemas.

Pontos principais:

  1. O navegador moderno e incrivelmente capaz
  2. Web Components permitem componentizacao nativa
  3. Gerenciamento de estado nao precisa de biblioteca
  4. Performance melhora drasticamente sem frameworks
  5. A escolha depende do contexto do projeto

Recomendacoes:

  • Avalie se realmente precisa de um framework
  • Aprenda as APIs nativas antes de frameworks
  • Considere abordagem hibrida quando fizer sentido
  • Priorize simplicidade e manutencao a longo prazo
  • Frameworks ainda sao uteis para casos complexos

Se voce quer aprofundar seus conhecimentos em JavaScript moderno, recomendo a leitura: ES2026 Novos Recursos: O Que Muda no JavaScript.

Bora pra cima! 🦅

Comentários (0)

Esse artigo ainda não possui comentários 😢. Seja o primeiro! 🚀🦅

Adicionar comentário