CSR VS SSR com ReactJS
Talvez uma das decisões mais importantes e fundamentais seja como renderizar nosso aplicativo da web quando começamos a arquitetar um novo aplicativo da web. É por isso que hoje quero falar sobre duas formas de renderização, renderização do lado do cliente e renderização do lado do servidor. Claro, esses dois padrões não são os únicos, e vamos discutir sobre renderização progressiva e outros padrões em um futuro próximo.
Terminologia que vou usar
Renderização
- SSR: Server-Side Rendering — renderizando um aplicativo universal ou do lado do cliente para HTML no servidor.
- CSR: Client-Side Rendering — renderizando um aplicativo em um navegador, geralmente usando o DOM.
- Reidratação: “inicialização” de visualizações JavaScript no cliente de modo que elas reutilizem a árvore DOM e os dados do HTML renderizado pelo servidor.
- FP: First Paint — a primeira vez que qualquer pixel se torna visível para o usuário.
- FCP: First Contentful Paint — o momento em que o conteúdo solicitado (corpo do artigo, etc.) se torna visível.
- TTI: Time To Interactive — o tempo em que uma página se torna interativa (eventos conectados, etc).
- TTFB: Time to First Byte — o tempo entre inserir um link e o primeiro bit de conteúdo que chega
RSE — Estrutura.
Considere que temos html com tag div vazia e js empacotado no servidor. A renderização CSR se parece com:
O html consiste apenas em uma única tag div raiz e todas as outras coisas, como exibição e atualização do DOM, são tratadas pelo JS.
Pacotes e desempenho
Se pensarmos no desempenho, primeiro veremos que à medida que a complexidade da página aumenta, a complexidade e o tamanho do JS também aumentam e o tempo para obtê-lo do servidor também aumenta. Isso causará atraso para FCP e TTI da página.
Prós e contras
Prós
- O CSR fornece a maneira de ter SPA que suporta páginas para navegar sem atualizar. Isso foi importante por muito tempo e agora é possível que os sites comecem a agir como aplicativos dinâmicos.
No entanto, existem algumas armadilhas:
- Desempenho. À medida que a complexidade da página aumenta, temos que esperar mais que o JS veja o FCP.
- Seo. Assim como os visitantes do usuário, os bots fazem solicitações para visualizar a página. Este é um processo bem conhecido como crawling. Durante o primeiro estágio, o Googlebots rastreia o código-fonte da sua página e indexa todo o conteúdo visível (não javascript). Mas não temos nada visível até que o JS seja executado para construir o dom. Durante esta fase de renderização, ele voltará (às vezes esse tempo leva a meses) e agora obtendo o conteúdo real de sua página disponível para rastreamento e, eventualmente, adicionando-o ao índice.
- Carregamento lento. Com o carregamento lento, podemos evitar o carregamento de recursos não críticos. Essa abordagem reduzirá o tempo inicial de carregamento da página.
- Divisão de código agressiva. Isso nos ajuda a criar vários pacotes que podem ser carregados dinamicamente durante o tempo de execução. Também nos permite carregar recursos JS preguiçosamente. A divisão de código é suportada por bundlers como Turbopack ou Webpack .
- Cache com service workers. Ele pode ser usado para armazenar em cache o shell do aplicativo offline e aumentar o tempo de desempenho.
Vamos dar uma olhada no que é SSR. É o método mais antigo para gerar o HTML completo para o conteúdo da página a ser renderizado durante a solicitação do usuário. Para esta implementação, precisamos construir o html no lado do servidor e enviá-lo para o navegador para que o navegador possa facilmente construir um FCP .
O navegador faz uma solicitação no servidor e obtém o html não apenas raiz vazia, mas também gerado com o conteúdo nele. Assim, o navegador mostra o conteúdo o mais rápido possível. Agora o navegador começa a baixar seu pacote, o usuário ainda vê o conteúdo na tela, mas ainda não é interativo. Somente após o download do seu pacote, ele anexa ouvintes de eventos ao seu html e se torna interativo. A este processo chamamos de Hidratação ou Reidratação .
SSR - prós e contras
Prós
Menos Javascript habilita o navegador para FCP e TTI mais rápidos.
Já que estamos evitando enviar muito Javascript para o Cliente FCP e os usuários estão apenas esperando pelo TTI. Quando temos muitos elementos de interface do usuário na página, o SSR tem muito menos JS do que o CSR, portanto, o tempo para obter os scripts é menor, mesmo que às vezes tenhamos FP=FCP=TTI.
SEO
Os bots dos mecanismos de pesquisa estão obtendo o conteúdo facilmente no primeiro estágio, para que agora possam indexar a página. Então, agora que estamos obtendo um SEO muito bom na página.
Contras
Às vezes, podemos ter um TTFB lento . Isso seria um cenário em que o usuário tem uma rede lenta ou o código do servidor não é otimizado.
Como todo o nosso código não está disponível no lado do cliente, as chamadas frequentes ao servidor causam recarregamentos de página inteira e, às vezes, isso aumenta o tempo entre as interações. Portanto, SPA não é possível com SSR.
Vamos criar um aplicativo React SSR simples com o Express .
npx create-react-app ssr-react
Vamos escrever componente: contador com métodos de aumento e diminuição.
import React, { useState } from "react";
const App = ({ initialValue }) => {
const [count, setCount] = useState(initialValue);
return (
<>
<div className="App">
<button onClick={() => setCount(count + 1)}>Increase</button>
<div style={{ margin: "20px" }}>{count}</div>
<button onClick={() => setCount(count - 1)}>Decrease</button>
</div>
</>
);
};
export default App;
npm i express --save
import express from "express";
const app = express();
app.listen(3000, function () {
console.log("server running on 3000");
});
import express from "express";
import fs from "fs";
import path from "path";
import App from "../src/App";
import React from "react";
import ReactDOMServer from "react-dom/server";
const app = express();
app.get("/page", async (req, res) => {
fs.readFile(path.resolve("./build/index.html"), "utf-8", (err, data) => {
if (err) {
return res.status(500).send("Error happened");
}
const html = `<div id="root">${ReactDOMServer.renderToString(
<App />
)}</div>`;
return res.send(data.replace('<div id="root"></div>', html));
});
});
app.use(express.static(path.resolve(__dirname, "..", "build")));
app.listen(3000, function () {
console.log("server running on 3000");
});
Portanto, estamos usando o JSX no lado do servidor e precisamos oferecer suporte a ele, portanto, adicionamos o babel a ele.
npm i @babel/preset-env @babel/preset-react @babel/register ignore-styles --save-dev
require("ignore-styles");
require("@babel/register")({
ignore: [/(node_module)/],
presets: ["@babel/preset-env", "@babel/preset-react"],
});
require("./server");
import React, { StrictMode } from "react";
import { hydrateRoot } from "react-dom/client";
import App from "./App";
hydrateRoot(document.getElementById("root"), <App initialValue={10} />);
"ssr": "node server/index.js",
É isso.
O código-fonte do Github está aqui .





































![O que é uma lista vinculada, afinal? [Parte 1]](https://post.nghiatu.com/assets/images/m/max/724/1*Xokk6XOjWyIGCBujkJsCzQ.jpeg)