Pontos-chave
- A renderização do lado do servidor do Angular constrói a página num servidor Node.js e envia HTML totalmente renderizado para o navegador, usando hidratação não destrutiva e reprodução de eventos para evitar oscilações na interface do utilizador.
- Plataformas sem servidor, como o Vercel e o AWS Lambda, provocam arranques a frio, o que acrescenta 2 a 3 segundos ao «Time-to-First-Byte» e anula as vantagens de velocidade que o SSR deveria proporcionar.
- Este guia mostra como criar uma aplicação Angular com SSR orientada por dados, que recupera dados de uma API externa no momento da renderização e os serializa diretamente no HTML.
- A aplicação final é implementada no Cloudways Velocity, um ambiente Node.js gerido e persistente, sem arranques a frio e com implementações automatizadas do GitHub.
Por predefinição, uma aplicação Angular é executada no navegador. O servidor envia uma tag praticamente vazia e, depois, o utilizador fica à espera enquanto os pacotes de JavaScript são descarregados e executados, antes de qualquer coisa aparecer na página.
Com uma ligação lenta, isso significa um ecrã em branco durante um ou dois segundos. E os rastreadores que não lidam bem com JavaScript acabam por quase não ver nada do teu conteúdo.
A renderização do lado do servidor no Angular resolve isto ao executar essa primeira renderização num servidor Node.js. O servidor constrói a página, recolhe os dados de que precisa e devolve imediatamente o HTML totalmente renderizado. Assim, o utilizador vê o conteúdo real quase instantaneamente e os rastreadores recebem uma página completa para analisar.
A questão é que a forma como implementas isto é tão importante quanto ativá-la. Se fizeres mal, ou perdes a velocidade que procuravas, ou o HTML renderizado nunca chega ao navegador da forma que pretendias.
Neste guia, vou explicar por que vale a pena usar o SSR do Angular e como ele funciona. Depois, vou criar uma aplicação Angular baseada em dados com o SSR ativado e implementar o seu resultado pré-renderizado num ambiente Node.js gerido (Cloudways Velocity), para que os utilizadores e os rastreadores tenham acesso a código HTML totalmente preenchido logo na primeira carga.
Por que usar a renderização do lado do servidor no Angular?
A renderização do lado do cliente (CSR) deixa todo o trabalho a cargo do navegador do utilizador. O servidor fornece-lhe um ficheiro HTML básico e, até que os teus pacotes de JavaScript sejam executados e as tuas chamadas à API sejam respondidas, o utilizador fica apenas a olhar para um ecrã em branco.
O SSR inverte essa situação e transfere o trabalho de volta para o servidor.
O que quero dizer é que, quando uma solicitação chega ao teu backend Node.js, o Angular percorre o seu ciclo de vida, obtém os dados da API, constrói a árvore de componentes e, em seguida, o servidor transforma esse DOM em HTML bruto e envia-o diretamente de volta.
O navegador exibe a página instantaneamente. Mas o Angular do lado do cliente ainda precisa entrar em ação para tornar tudo interativo, e o Angular moderno lida com essa transição através de duas funcionalidades que vale a pena conhecer.
A primeira é a hidratação não destrutiva. Em vez de apagar o HTML renderizado pelo servidor e voltar a renderizar tudo do zero (o que é que causa aquela trepidação irritante na interface), o Angular analisa o DOM que já está lá e limita-se a anexar os seus ouvintes de eventos a ele.
A segunda é a repetição de eventos. Imagina que um utilizador clica num botão antes de o JavaScript do lado do cliente ter terminado de carregar. O Angular guarda esse clique e repete-o assim que a hidratação terminar, para que nada se perca.
Mas tudo isto depende de uma coisa: uma resposta rápida do servidor. Se o teu processo Node ficar preso a tentar recuperar de um arranque a frio num ambiente serverless, nenhuma destas otimizações vai fazer diferença, porque o carregamento da página já está comprometido antes mesmo de elas terem oportunidade de entrar em ação.
O problema do arranque a frio no SSR sem servidor
Se olhares para plataformas como o Vercel, o Netlify ou o AWS Amplify, vais ver que promovem bastante a arquitetura sem servidor. Elas querem que implementes a tua aplicação Angular com SSR como uma função AWS Lambda (ou uma função Edge).
E a experiência do programador é mesmo fantástica. Basta ligares o teu repositório do GitHub, fazeres um push para o branch principal e eles tratam da compilação por ti. Mas, no que diz respeito especificamente ao SSR, a arquitetura tem falhas fundamentais.
Eis o motivo.
As funções sem servidor são efémeras. Para poupar dinheiro e recursos de computação, os fornecedores de serviços na nuvem não mantêm o teu servidor Node.js a funcionar 24 horas por dia, 7 dias por semana. Por isso, se a tua aplicação ficar 10 ou 15 minutos sem visitantes, o fornecedor desliga o contentor. Este entra em modo de suspensão.
Depois, o utilizador seguinte clica numa ligação para o teu site e, nessa altura, o fornecedor tem de iniciar um novo micro-container, carregar o ambiente de execução do Node.js, buscar o teu pacote «server.mjs» do Angular, executar o servidor Express e só depois executar a tua lógica de SSR do Angular para gerar efetivamente o HTML.
Todo esse processo de ativação chama-se «arranque a frio» e, normalmente, acrescenta 2 a 3 segundos ao teu «Time-to-First-Byte» (TTFB).
Pensa nisso por um segundo. Se passaste dias a otimizar a tua aplicação Angular para um TTFB de 200 ms e depois a integraste numa função sem servidor que fica inativa e acrescenta um atraso de 3000 ms, basicamente deitaste fora toda a vantagem de desempenho do SSR.
Portanto, para que as vantagens em termos de velocidade se façam realmente sentir, o teu servidor Node tem de ser persistente. Com isto quero dizer que fica ativo 24 horas por dia, 7 dias por semana, pronto para responder a pedidos instantaneamente, sem ter de iniciar um ambiente novo de cada vez.
Comparar opções de alojamento para SSR do Angular
Então, se o modelo «serverless» causa «cold starts», onde é que deves realmente colocar a tua aplicação Angular compilada? Na verdade, há três níveis a ter em conta para as aplicações Node.js.
| Tipo de alojamento | Estado do ambiente | Impacto no TTFB | DevOps necessário | Exemplos de fornecedores |
| Sem servidor | Efémero | Elevado, arranques a frio de 2-3 s | Baixo, automatizado | Vercel, AWS Lambda |
| VPS Raw | Persistente | Instantâneo | Alto, Nginx/PM2 manual | DigitalOcean, EC2 |
| Node.js gerido | Persistente | Instantâneo | Baixo, automatizado | Cloudways Velocity |
A primeira opção é o «serverless». Como já disse, é fácil de implementar, mas pagas por isso com os «cold starts». É ótimo para aplicações estáticas do lado do cliente, mas péssimo para SSR que exige muita computação.
Depois, há a opção do VPS puro. Alugas algo como um droplet Ubuntu de 5 dólares na DigitalOcean, o teu servidor Node fica ligado 24 horas por dia, 7 dias por semana, e não há nenhum arranque a frio.
O senão? Agora és tu o administrador de sistemas. Tens de te ligar ao servidor por SSH, instalar o Node, configurar um proxy reverso do Nginx para redirecionar a porta 4000 para a porta 80, configurar o PM2 para que a aplicação volte a funcionar se falhar e renovar manualmente os teus certificados SSL do Let’s Encrypt.
E depois há a opção gerida, que é a que eu uso mesmo para o SSR do Angular em produção. Plataformas como o Cloudways Velocity oferecem-te um contentor persistente, pelo que a tua aplicação Node fica ativa 24 horas por dia, 7 dias por semana, sem nenhum arranque a frio; só que agora é a plataforma que trata do proxy Nginx, do SSL e das implementações automáticas do GitHub por ti.
Assim, tens a velocidade pura de um VPS sem teres de te preocupar com a gestão do sistema.
Na próxima secção, vou criar a estrutura de uma nova aplicação Angular com SSR ativado e construir um componente que recupere dados no servidor, para que possamos comprovar que esta configuração funciona em produção.
Obtém a velocidade de um VPS sem o trabalho de administração de sistemas
O Cloudways Velocity oferece à tua aplicação Angular com SSR um contentor Node.js persistente com implementações automáticas do GitHub.
Criar uma aplicação Angular SSR orientada por dados
Uma aplicação estática do tipo «Hello World» não chega aqui. Preciso de algo que realmente faça trabalho do lado do servidor, para poder comprovar que a configuração de alojamento aguenta o tráfego.
Então, vou criar uma aplicação Angular simples e autónoma que chama uma API externa (JSONPlaceholder) e recupera uma lista de publicações. O objetivo é simples: ver como o Angular vai buscar esses dados durante a renderização e inseri-los no HTML antes mesmo de chegarem ao navegador.
Passo 1: Configurar o ambiente Angular
Antes de criar qualquer estrutura, preciso do Node no meu terminal. Como estou no meu portátil do trabalho, com restrições de TI, não consigo executar um instalador normal, por isso vou usar o ficheiro binário independente do Node.js. Isso significa que o CMD não sabe onde estão as minhas ferramentas do Node até eu lhe dizer. Para resolver isso, vou abrir o CMD e indicar-lhe a pasta onde descompactei o Node:
PATH=%PATH%;C:\Users\abdulrehman\Downloads\node-v24.18.0-win-x64\node-v24.18.0-win-x64
Com isso definido, vou usar o Angular CLI para criar um novo espaço de trabalho.
npx @angular/cli new angular-ssr-demo --ssr
Durante as instruções de configuração, basta premir Enter para manter o CSS padrão. Também ignorei a integração de ferramentas de IA para manter o meu espaço de trabalho organizado.

Assim que a instalação terminar, vou ao meu diretório:
cd angular-ssr-demo
Usar o sinalizador –ssr diz ao Angular para gerar um ficheiro server.ts, que é o teu backend Express, e para configurar automaticamente os alvos de compilação do servidor dentro do angular.json.
O mais importante é que configura a hidratação moderna. Se eu abrir o ficheiro src/app/app.config.ts, quero manter as predefinições geradas pela CLI (como o provideBrowserGlobalErrorListeners), mas preciso de me certificar de que tanto o encaminhamento como a hidratação estão ativados, além do HttpClient, para que o próprio servidor possa fazer chamadas à API.

Vou também adicionar o withEventReplay(), que garante que quaisquer cliques que o utilizador faça antes de o JavaScript terminar de carregar sejam capturados, em vez de se perderem.
// src/app/app.config.ts
import { ApplicationConfig, provideBrowserGlobalErrorListeners } from '@angular/core';
import { provideRouter } from '@angular/router';
import { provideClientHydration, withEventReplay } from '@angular/platform-browser';
import { provideHttpClient, withFetch } from '@angular/common/http';
import { routes } from './app.routes';
export const appConfig: ApplicationConfig = {
providers: [
provideBrowserGlobalErrorListeners(),
provideRouter(routes),
// Enables non-destructive hydration and buffers early user clicks
provideClientHydration(withEventReplay()),
// withFetch() is required for SSR to make HTTP calls natively in Node
provideHttpClient(withFetch())
]
};

Passo 2: Criar o componente de recuperação de dados
Agora vou criar o componente que, na verdade, recupera as publicações e as apresenta. É esta parte que comprova o que estou a dizer: o servidor executa esta recuperação e o resultado acaba por aparecer no HTML antes mesmo de o navegador o ver.
Vou abrir o ficheiro src/app/app.ts e substituir o que lá está pelo meu próprio componente. Este define o formato de uma publicação, chama a API JSONPlaceholder dentro do ngOnInit e, depois, percorre os resultados no modelo para apresentar cada um deles.
// src/app/app.ts
import { Component, inject, OnInit } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { CommonModule } from '@angular/common';
interface Post {
id: number;
title: string;
}
@Component({
selector: 'app-root',
standalone: true,
imports: [CommonModule],
template: `
<main style="font-family: sans-serif; padding: 2rem;">
<h1>Angular SSR Data Fetching</h1>
<p>If you View Page Source, this list is baked into the raw HTML:</p>
<ul>
<li *ngFor="let post of posts">
<strong>{{ post.id }}</strong> - {{ post.title }}
</li>
</ul>
</main>
`
})
export class App implements OnInit {
private http = inject(HttpClient);
posts: Post[] = [];
ngOnInit() {
// The server waits for this request to finish before rendering the HTML
this.http.get<Post[]>('https://jsonplaceholder.typicode.com/posts?_limit=5')
.subscribe(data => {
this.posts = data;
});
}
}

Como configurei o HttpClient com o withFetch() já no Passo 1, o servidor consegue executar esta chamada HTTP de forma nativa durante a renderização. Assim, quando a página chega ao navegador, a lista de publicações já está incluída no HTML.
Passo 3: Testar a aplicação localmente
Para confirmar que o servidor está mesmo a fazer o trabalho de renderização, vou iniciar o servidor de desenvolvimento local.
npm run start
Assim que o servidor estiver a funcionar, na minha janela do prompt de comandos, devo ver«Application bundle generation complete.»

Depois disso, vou abrir http://localhost:4200 no meu navegador.

A aparência da página não é propriamente o que me interessa neste teste. O que quero mesmo verificar é o que o servidor enviou inicialmente.
Então, vou copiar o primeiro item da lista na página e, depois, ver o código-fonte da página.

Se eu usar CTRL+F para procurar o que copiei, em vez de uma estrutura vazia à espera do JavaScript, consigo ver os dados do meu post já incorporados no HTML bruto que o servidor enviou. O Angular foi buscar os dados enquanto criava a página e serializou-os diretamente na resposta.

É esse o objetivo da renderização do lado do servidor: o conteúdo já está lá no primeiro carregamento, antes de qualquer JavaScript do lado do cliente ser executado.
Agora que a aplicação funciona, o próximo passo é prepará-la para produção e colocá-la no ar.
Passo 4: Compilar a aplicação para produção
Como a recuperação de dados funciona localmente, o próximo passo é compilar a aplicação para produção.
npm run build

Uma compilação normal do Angular do lado do cliente limita-se a colocar uma série de ficheiros estáticos numa única pasta, mas a compilação SSR funciona de forma diferente e cria uma estrutura específica dentro de dist/angular-ssr-demo/.
Quando abro essa pasta «dist», vejo duas pastas principais. A pasta «browser/» contém os recursos padrão do lado do cliente: os CSS, as imagens e os pacotes de JavaScript que assumem o controlo assim que a hidratação começa. A pasta «server/» contém o servidor Node.js Express compilado que faz a renderização propriamente dita.
A parte que me interessa para a implementação é a pasta «browser/ ». Durante a compilação, o Angular pré-renderiza a minha rota e coloca os dados obtidos diretamente no HTML dentro dessa pasta. Por isso, quando fizer a implementação, é para essa pasta que vou indicar ao Cloudways, já que ela contém páginas totalmente renderizadas e prontas a serem servidas.
Passo 5: Implementar o Angular SSR no Cloudways Velocity
Agora vou colocar isto a funcionar no Cloudways Velocity, um ambiente Node.js gerido que trata do proxy Nginx, do SSL e das implementações automáticas do GitHub por mim.
Primeiro, vou fazer o commit de todo o projeto e enviá-lo para um novo repositório no GitHub. O Git já ignora o «node_modules» e a pasta «dist» por predefinição, por isso esses ficam de fora.



Assim que estiver publicado, vou entrar no Cloudways e configurar a implementação.
Vou começar por lançar uma aplicação Velocity a partir do painel do Cloudways e escolher o tamanho do servidor.


A seguir, vou ligar a minha conta do GitHub e selecionar o repositório «angular-server-side-rendering» que acabei de publicar.


Agora, o Cloudways define automaticamente as configurações da minha aplicação. Define o framework como Angular, o ramo como «main» e a versão do Node como v24. Não preciso de configurar nada disto manualmente.

Há uma configuração que preciso definir no sítio certo, que é o «Output Directory». A compilação do Angular produz os seus ficheiros pré-renderizados e prontos para o navegador dentro de uma subpasta chamada «browser», por isso vou definir o «Output Directory» para:
dist/angular-ssr-demo/browser

Essa é a pasta que contém o HTML pré-renderizado com os meus dados já incluídos, juntamente com os pacotes do lado do cliente que preenchem a página assim que esta carrega.
Assim que clico em «Deploy», o Cloudways puxa o repositório, executa o «npm install», faz a compilação e apresenta esse resultado pré-renderizado.


Quando termina, a aplicação fica ativa na URL temporária da Cloudways. Abro a opção «Ver código-fonte da página» e lá estão os dados da minha publicação, mesmo no HTML bruto, exatamente como estavam localmente.


Conclusão
O SSR do Angular não é só uma opção a marcar para teres uma pontuação melhor no Lighthouse. Muda a forma como a tua aplicação funciona de verdade, passando de uma compilação estática para um processo ativo do lado do servidor, e vale a pena teres isso em conta quando decidires onde a vais hospedar.
A vantagem é simples: quem quer que carregue a página, ou qualquer rastreador que a indexe, obtém conteúdo real de imediato, em vez de uma estrutura vazia à espera do JavaScript.
E se implementares esse resultado pré-renderizado num host gerido como o Cloudways Velocity, tens tudo isso sem precisares de mexer no Nginx nem de te preocupares com servidores.
Implemente a tua aplicação Angular SSR no Cloudways
Liga o teu repositório, define o diretório de saída e obtém alojamento Node.js persistente sem nenhum arranque a frio.
P. O SSR do Angular gera pedidos HTTP duplicados no cliente?
Não, e essa é, na verdade, uma das melhores partes do seu funcionamento. O Angular serializa os dados que foi buscar no servidor diretamente para o conteúdo HTML; assim, quando o HttpClient do lado do cliente entra em ação, ele simplesmente reutiliza esses dados já existentes, em vez de enviar a mesma solicitação de rede uma segunda vez.
P. Qual é a principal diferença entre o Angular SSR e o SSG (pré-renderização)?
A diferença resume-se ao momento em que o HTML é gerado. O SSR gera HTML novo a cada pedido ao servidor, o que é exatamente o que queres quando os dados são em tempo real e estão em constante mudança. O SSG gera todo o seu HTML estático de uma só vez, antecipadamente, durante o comando «npm run build», o que o torna a melhor opção para conteúdos que não mudam muito entre as implementações.
P. O SSR vai resolver todos os problemas de desempenho da minha aplicação?
Não totalmente, e vale a pena ser sincero sobre quais são os seus limites. O SSR melhora o carregamento inicial da página, por isso o teu TTFB e o FCP ficam melhores, e também ajuda na indexação para SEO. Mas assim que a hidratação terminar, não vai adiantar nada em relação a código do lado do cliente mal escrito ou recursos pesados e não otimizados, e esses continuam a ser algo que tens de resolver por ti próprio.
Start Growing with Cloudways Today.
Our Clients Love us because we never compromise on these
[email protected]
O Abdul é um profissional de marketing experiente em tecnologia, movido a café e criativo, que adora manter-se a par das últimas actualizações de software e gadgets tecnológicos. É também um escritor técnico competente que consegue explicar conceitos complexos de forma simples para um público alargado. Abdul gosta de partilhar os seus conhecimentos sobre a indústria da nuvem através de manuais de utilizador, documentação e publicações em blogues.