Enviar apenas os dados necessários para o cliente

Version: 1.0.0

Ao carregar dados de APIs externas usando Loaders e enviá-los para a Section, é possível que o tamanho do payload impacte negativamente a performance do site. O impacto ocorre tanto no tempo inicial de carregamento como também na hidratação, onde a página é "inicializada" no browser para que possa ser interativa (usar useEffect, useSignal, etc...). É possível visualizar no tamanho do JSON final através da aba Performance no CMS deco.

288067513-db3a14e1-c0ac-47f8-83b9-afc8db60de71

Quando o tamanho do JSON passa de ~500kb, é provável que a UI não precise do dado completo, mas sim alguma parte dele (ou então uma computação sobre outros valores). Para diminuir esse tamanho e melhorar a performance da página, é possível filtrar os dados ainda no Loader para que apenas o necessário seja passado para a UI.

Código de exemplo - 1

Nesse primeiro exemplo, mostraremos como evitar enviar muitos dados para uma Island.

Digamos que existe um componente chamado ProductCard, que recebe todo o JSON de um produto.

  import Image from "apps/website/components/Image.tsx"
  
  export default function ProductCard({product} : Props){
    return(
      <div>
        <Image src={product.image} width="100" height="100"/>
      </div>
    )
  }

Nele, você deseja incluir uma Island para criar o botão de comprar.

  import BuyButton from "$store/components/ui"
  import Image from "apps/website/components/Image.tsx"

  export default function ProductCard({product} : Props){

    return(
      <div>
        <Image src={product.image} width="100" height="100"/>
        <BuyButton />
      </div>
    )
  }

É possível que esse BuyButton, precise de algumas informações do produto para poder adicionar ao carrinho.

Aqui que devemos tomar cuidado a quantidade de dados enviados para a Island.

Por exemplo, é bem possível que o botão de comprar não precise receber dados de imagem.

O ideal é enviar apenas os dados necessários

❌ Abordagem errada:

  import BuyButton from "$store/components/ui"
  import Image from "apps/website/components/Image.tsx"

  export default function ProductCard({product} : Props){

    return(
      <div>
        <Image src={product.image} width="100" height="100"/>
        <BuyButton product={product} />
      </div>
    )
  }

✅ Abordagem correta:

  import BuyButton from "$store/components/ui"
  import Image from "apps/website/components/Image.tsx"

  export default function ProductCard({product} : Props){

    return(
      <div>
        <Image src={product.image} width="100" height="100"/>
        <BuyButton id={product.id} seller={product.seller}/>
      </div>
    )
  }

A abordagem correta envia apenas os dados de ID e Seller, que no exemplo, são os únicos necessários na Island.

Assim, no momento de hidratação, o JSON que a Island irá carregar não será tão grande.

Código de exemplo - 2

Neste exemplo, vamos mostrar como evitar enviar um dado muito grande para uma section.

Digamos que temos um loader inline para buscar as cores do produto e retornar em uma section.

export default function Colors({colors}){

  return colors.map(color => <span>{color}</span>)
}

export const loader = async () => {
  const colors = await fetch("/product/colors").then(r => r.json())

  return colors;
}

Esse componente parece correto, certo?

Porém, após uma investigação, verificamos que o dado retornado trazia também as imagens do produto.

Exemplo do retorno da API:

colors = [
  {
    "color": "red"
    "images": [...]
  },
  {
    "color": "green"
    "images": [...]
  },
  {
    "color": "orange"
    "images": [...]
  },
}]

Os dados de imagem nesse retorno, não serão utilizados na section, então não precisamos enviá-los.

Podemos filtrar dessa forma:

export default function Colors({colors}){

  return colors.map(color => <span>{color}</span>)
}

export const loader = async () => {
  const result = await fetch("/product/colors").then(r => r.json())
  const colors = result.map(item => item.color)
  return colors;
}

Dessa forma, apenas os dados utilizados serão enviados, evitando uma sobrecarga desnecessária.

Benefícios

  • Redução significativa no tamanho do JSON transmitido.
  • Melhoria perceptível no desempenho da página, especialmente em termos de carregamento.

Ao implementar esse processo de pré-processamento de dados, é possível otimizar a performance da página, garantindo que apenas as informações cruciais sejam enviadas e processadas, proporcionando um desempenho mais otimizado para o usuário.