Voltar para o Blog

Server-First Development: Como Astro, Remix e Next.js Estão Mudando o Jogo em 2025

Olá HaWkers, você percebeu que o pêndulo do desenvolvimento web está voltando para o servidor?

Depois de anos focando em Single Page Applications (SPAs) e client-side rendering, a indústria está redescobring os benefícios do servidor. Mas não estamos voltando ao passado - estamos criando algo novo e muito mais poderoso: Server-First Development.

O Que É Server-First e Por Que Agora

Server-First não significa abandonar interatividade client-side. É uma filosofia de design que prioriza:

1. Renderizar no servidor por padrão
2. Enviar apenas JavaScript necessário ao cliente
3. Otimizar automaticamente data fetching
4. Aproveitar infraestrutura serverless e edge computing

O movimento ganhou força em 2025 por três razões principais:

  • Performance: Páginas carregam mais rápido com HTML pré-renderizado
  • SEO: Bots indexam conteúdo completo imediatamente
  • Developer Experience: Código mais simples, menos estado gerenciado client-side

Astro: O Pioneiro do Server-First Moderno

Astro revolucionou o espaço com sua abordagem "Island Architecture" - renderize tudo no servidor, adicione interatividade apenas onde necessário.

Veja um exemplo prático de componente Astro:

---
// ProductList.astro - Renderizado no servidor
interface Props {
  category?: string;
}

const { category = 'all' } = Astro.props;

// Data fetching acontece no servidor, durante build ou request
const response = await fetch(`https://api.example.com/products?category=${category}`);
const products = await response.json();
---

<div class="product-list">
  <h2>Products - {category}</h2>

  <div class="products-grid">
    {products.map(product => (
      <article class="product-card">
        <img src={product.image} alt={product.name} />
        <h3>{product.name}</h3>
        <p>{product.description}</p>
        <p class="price">${product.price}</p>

        <!-- Apenas este botão precisa JavaScript -->
        <button
          class="add-to-cart"
          data-product-id={product.id}
        >
          Add to Cart
        </button>
      </article>
    ))}
  </div>
</div>

<!-- JavaScript só carrega para funcionalidade específica -->
<script>
  document.querySelectorAll('.add-to-cart').forEach(button => {
    button.addEventListener('click', (e) => {
      const productId = e.target.dataset.productId;
      // Lógica de adicionar ao carrinho
      addToCart(productId);
    });
  });
</script>

<style>
  .products-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
    gap: 2rem;
  }

  .product-card {
    border: 1px solid #ddd;
    border-radius: 8px;
    padding: 1rem;
  }

  .price {
    font-size: 1.5rem;
    font-weight: bold;
    color: #2563eb;
  }
</style>

O que torna isso poderoso: apenas o script do botão vai para o cliente. Todo o resto é HTML puro e rápido.

server-first architecture

Islands Architecture: O Segredo do Astro

A grande inovação do Astro é permitir "ilhas" de interatividade em um oceano de conteúdo estático:

---
// Page.astro
import StaticHeader from './StaticHeader.astro';
import InteractiveSearch from './InteractiveSearch.jsx';
import StaticContent from './StaticContent.astro';
import InteractiveComments from './InteractiveComments.vue';
---

<html>
  <head>
    <title>Island Architecture Demo</title>
  </head>
  <body>
    <!-- Componente estático - sem JS enviado -->
    <StaticHeader />

    <!-- Ilha interativa React - JS só para este componente -->
    <InteractiveSearch client:load />

    <!-- Conteúdo estático novamente -->
    <StaticContent />

    <!-- Ilha interativa Vue - carrega só quando visível -->
    <InteractiveComments client:visible />
  </body>
</html>

Diretivas de carregamento no Astro:

  • client:load - Carrega imediatamente
  • client:idle - Carrega quando navegador ficar idle
  • client:visible - Carrega quando entrar no viewport
  • client:media - Carrega baseado em media query
  • client:only - Apenas client-side (SSR desabilitado)

Remix: Server-First com Web Standards

Remix adota uma abordagem diferente: abraçar web standards nativos e aproveitar ao máximo o servidor.

// routes/products.$category.tsx (Remix)
import { json, type LoaderFunctionArgs } from "@remix-run/node";
import { useLoaderData, Form } from "@remix-run/react";

// Loader roda no servidor
export async function loader({ params, request }: LoaderFunctionArgs) {
  const url = new URL(request.url);
  const search = url.searchParams.get("search") || "";

  const products = await db.product.findMany({
    where: {
      category: params.category,
      name: { contains: search }
    }
  });

  return json({ products, category: params.category });
}

// Action também roda no servidor
export async function action({ request }: ActionFunctionArgs) {
  const formData = await request.formData();
  const productId = formData.get("productId");

  await addToCart(productId);

  return json({ success: true });
}

// Componente renderizado no servidor + hidratado no cliente
export default function ProductsPage() {
  const { products, category } = useLoaderData<typeof loader>();

  return (
    <div className="products-page">
      <h1>Products: {category}</h1>

      {/* Form funciona mesmo sem JavaScript! */}
      <Form method="get" className="search-form">
        <input
          type="search"
          name="search"
          placeholder="Search products..."
        />
        <button type="submit">Search</button>
      </Form>

      <div className="products-grid">
        {products.map(product => (
          <article key={product.id} className="product-card">
            <img src={product.image} alt={product.name} />
            <h3>{product.name}</h3>
            <p>${product.price}</p>

            {/* Form funciona sem JS, mas com JS fica mais rápido */}
            <Form method="post">
              <input type="hidden" name="productId" value={product.id} />
              <button type="submit">Add to Cart</button>
            </Form>
          </article>
        ))}
      </div>
    </div>
  );
}

A filosofia Remix: funciona sem JavaScript, melhora com JavaScript.

Next.js 15: Server Components e App Router

Next.js abraçou completamente o Server-First com React Server Components:

// app/products/[category]/page.tsx (Next.js 15)
import { Suspense } from 'react';
import { ProductCard } from '@/components/ProductCard';
import { AddToCartButton } from '@/components/AddToCartButton';

// Server Component por padrão
async function ProductList({ category }: { category: string }) {
  // Fetch roda no servidor
  const products = await fetch(
    `https://api.example.com/products?category=${category}`,
    { next: { revalidate: 3600 } } // Cache por 1 hora
  ).then(res => res.json());

  return (
    <div className="products-grid">
      {products.map(product => (
        <article key={product.id}>
          <img src={product.image} alt={product.name} />
          <h3>{product.name}</h3>
          <p>${product.price}</p>

          {/* Client Component só onde necessário */}
          <AddToCartButton productId={product.id} />
        </article>
      ))}
    </div>
  );
}

// Page Component (Server)
export default function ProductsPage({
  params
}: {
  params: { category: string }
}) {
  return (
    <div>
      <h1>Products: {params.category}</h1>

      <Suspense fallback={<ProductsLoadingSkeleton />}>
        <ProductList category={params.category} />
      </Suspense>
    </div>
  );
}

// Streaming SSR automático!

Client Component quando necessário:

// components/AddToCartButton.tsx
'use client'; // Marca como Client Component

import { useState } from 'react';

export function AddToCartButton({ productId }: { productId: string }) {
  const [loading, setLoading] = useState(false);

  const handleClick = async () => {
    setLoading(true);
    await fetch('/api/cart', {
      method: 'POST',
      body: JSON.stringify({ productId })
    });
    setLoading(false);
  };

  return (
    <button onClick={handleClick} disabled={loading}>
      {loading ? 'Adding...' : 'Add to Cart'}
    </button>
  );
}

Comparação: Astro vs Remix vs Next.js

Aspecto Astro Remix Next.js 15
Filosofia Island Architecture Web Standards First React Server Components
Framework UI Agnostic (React, Vue, Svelte) React only React only
Data Fetching Build/request time Loader/Action pattern Server Components
JS Bundle Mínimo por padrão Progressive enhancement Automatic splitting
Melhor Para Content sites, blogs Web apps, forms Full-stack apps
Learning Curve Baixa Média Média-Alta
Performance ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐⭐

Data Fetching: O Coração do Server-First

O grande benefício do Server-First é data fetching otimizado:

// Astro - Fetch durante build ou request
---
const data = await fetch('https://api.example.com/data').then(r => r.json());
---

// Remix - Loader pattern
export async function loader() {
  const data = await db.query();
  return json(data);
}

// Next.js - Server Component
async function DataComponent() {
  const data = await fetchData(); // Roda no servidor
  return <div>{data}</div>;
}

// Todos evitam waterfall requests do client-side!

Vantagens:

Sem loading states complexos
Acesso direto ao banco de dados
Secrets seguros (não vazam para client)
Parallel data fetching automático
Menos JavaScript enviado ao cliente

SEO e Performance: Os Grandes Vencedores

Server-First entrega benefícios imensos para SEO e performance:

// Comparação de bundle size típico:

// SPA tradicional (React puro)
// - React runtime: ~130KB
// - Router: ~20KB
// - State management: ~15KB
// - Data fetching lib: ~10KB
// - Seu código: ~50KB+
// Total: ~225KB+ JavaScript

// Server-First (Astro/Remix/Next.js)
// - HTML inicial: completo e indexável
// - JavaScript: apenas para interatividade
// - Bundle típico: ~50-80KB
// Total: 3-4x menor!

Métricas Web Vitals melhoram drasticamente:

  • LCP (Largest Contentful Paint): 40-60% mais rápido
  • FID (First Input Delay): Quase zero (HTML já funcional)
  • CLS (Cumulative Layout Shift): Redução de 80%+

Edge Computing: O Próximo Nível do Server-First

Em 2025, Server-First combina perfeitamente com Edge Computing:

// Vercel Edge Function com Next.js
export const config = {
  runtime: 'edge', // Roda no Edge, perto do usuário
};

export default async function handler(request: Request) {
  const { searchParams } = new URL(request.url);
  const userId = searchParams.get('userId');

  // Roda no edge, latência baixíssima
  const userData = await fetch(`https://api.example.com/user/${userId}`);

  return new Response(JSON.stringify(userData), {
    headers: { 'content-type': 'application/json' }
  });
}

Edge + Server-First = velocidade global sem CDN complexo.

Quando Usar Cada Framework

Use Astro quando:

  • Site content-heavy (blog, docs, marketing)
  • Quer usar múltiplos frameworks UI
  • Performance é prioridade máxima
  • Não precisa de muita interatividade

Use Remix quando:

  • App web tradicional com forms
  • Quer progressive enhancement
  • Prefere web standards a abstrações
  • Precisa de nested routing robusto

Use Next.js quando:

  • Full-stack app complexo
  • Já usa React
  • Quer server components nativos
  • Precisa de API routes integradas

O Futuro: Server-First Everywhere

Server-First está se tornando o padrão:

  • Nuxt 4 (Vue): Server Components planejados
  • SvelteKit: Já server-first por padrão
  • Solid Start: Server-first com Solid
  • Qwik: Resumability - próximo nível de server-first

O JavaScript do futuro roda no servidor, envia apenas o mínimo para o cliente.

Se você quer explorar mais sobre arquiteturas modernas, confira: Serverless e Edge Computing: Arquitetura 2025 onde exploramos infraestrutura cloud moderna.

Bora pra cima! 🦅

📚 Quer Aprofundar Seus Conhecimentos em JavaScript?

Este artigo cobriu Server-First Development, mas há muito mais para explorar no mundo do desenvolvimento moderno.

Desenvolvedores que investem em conhecimento sólido e estruturado tendem a ter mais oportunidades no mercado.

Material de Estudo Completo

Se você quer dominar JavaScript do básico ao avançado, preparei um guia completo:

Opções de investimento:

  • R$9,90 (pagamento único)

👉 Conhecer o Guia JavaScript

💡 Material atualizado com as melhores práticas do mercado

Comentários (0)

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

Adicionar comentário