A renderização do servidor (do inglês, SSR) é uma técnica popular para renderizar um aplicativo de página única (do inglês, SPA) no servidor e então enviar uma página totalmente renderizada ao cliente. Isso permite que componentes dinâmicos sejam servidos como uma marcação HTML estática.
Essa abordagem pode ser útil para o motor de otimização de busca (do inglês, SEO) quando a indexação não manipular o JavaScript corretamente. Ela também pode ser benéfica em situações em que baixar um pacote grande do JavaScript for um processo difícil por conta de uma rede lenta.
Neste tutorial, você irá inicializar um aplicativo React usando o Create React App e então modificar o projeto para habilitar a renderização do servidor.
No final deste tutorial, você terá um projeto funcional com um aplicativo React do lado do cliente e um aplicativo Express do lado do servidor.
Nota: De maneira alternativa, o Next.js oferece uma abordagem moderna para criar aplicativos estáticos e renderizados no servidor desenvolvidos com o React.
Para completar este tutorial, você precisará de:
Este tutorial foi verificado com o Node v14.4.0 e o npm
v6.14.5.
Primeiro, vamos usar o npx para iniciar um novo aplicativo React usando a versão mais recente do Create React App.
Vamos chamar nosso aplicativo my-ssr-app:
- npx create-react-app@3.4.1 my-ssr-app
Em seguida, vamos usar o cd
para entrar no novo diretório:
cd my-ssr-app
Por fim, iniciamos nosso novo aplicativo de cliente para verificar a instalação:
- npm start
Você deve ver um exemplo de aplicativo do React em exibição na janela do seu navegador.
Agora, vamos criar um componente <Home>
:
- nano src/Home.js
Depois, adicione o código a seguir ao arquivo Home.js
:
import React from 'react';
export default props => {
return <h1>Hello {props.name}!</h1>;
};
Isso irá criar um cabeçalho <h1>
com uma mensagem "Hello"
dirigida a um nome.
Em seguida, vamos renderizar o <Home>
no componente <App>
. Abra o arquivo App.js
:
- nano src/App.js
Depois disso, substitua as linhas de código existentes por essas novas linhas:
import React from 'react';
import Home from './Home';
export default () => {
return <Home name="Sammy" />;
};
Isso passa adiante um name
ao componente <Home>
, de forma que a mensagem que esperamos receber é "Hello Sammy!"
.
No arquivo index.js
do nosso aplicativo, vamos usar o método hydrate
do ReactDOM ao invés do render
, para indicar ao renderizador DOM que estamos reabastecendo o aplicativo após um render do servidor.
Vamos abrir o arquivo index.js
:
- nano index.js
Em seguida, substitua o conteúdo do arquivo index.js
pelo seguinte código:
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
ReactDOM.hydrate(<App />, document.getElementById('root'));
Aqui termina a configuração do lado do cliente. Podemos seguir agora para a configuração do lado do servidor.
Agora que temos nosso aplicativo instalado, vamos configurar um servidor que irá enviar uma versão renderizada. Vamos usar o Express para o nosso servidor. Vamos adicioná-lo ao projeto inserindo o seguinte comando em sua janela de terminal:
- npm install express@4.17.1
Ou, usando o yarn:
- yarn add express@4.17.1
Em seguida, crie um diretório server
próximo ao diretório src
do aplicativo:
- mkdir server
Depois disso, crie um novo arquivo index.js
que irá conter o código do servidor Express:
- nano server/index.js
Adicione as importações necessárias e defina algumas constantes:
import path from 'path';
import fs from 'fs';
import React from 'react';
import express from 'express';
import ReactDOMServer from 'react-dom/server';
import App from '../src/App';
const PORT = process.env.PORT || 3006;
const app = express();
Em seguida, adicione o código do servidor com algum gerenciamento de erro:
// ...
app.get('/', (req, res) => {
const app = ReactDOMServer.renderToString(<App />);
const indexFile = path.resolve('./build/index.html');
fs.readFile(indexFile, 'utf8', (err, data) => {
if (err) {
console.error('Something went wrong:', err);
return res.status(500).send('Oops, better luck next time!');
}
return res.send(
data.replace('<div id="root"></div>', `<div id="root">${app}</div>`)
);
});
});
app.use(express.static('./build'));
app.listen(PORT, () => {
console.log(`Server is listening on port ${PORT}`);
});
Como pode ver, podemos importar nosso componente <App>
do aplicativo cliente diretamente do servidor.
Três coisas importantes estão acontecendo aqui:
build
como arquivos estáticos.ReactDOMServer
, o renderToString
, para renderizar nosso aplicativo em uma string HTML estática.index.html
do aplicativo cliente construído, injetamos o conteúdo estático do nosso aplicativo no <div>
com um id
de "root"
e enviamos isso como a resposta à solicitação.npm
Para que o código do nosso servidor funcione, vamos precisar empacotar e transcompila-lo usando o webpack e o Babel. Para fazer isso, vamos adicionar as dependências de desenvolvimento ao projeto inserindo o seguinte comando em sua janela de terminal:
- npm install webpack@4.42.0 webpack-cli@3.3.12 webpack-node-externals@1.7.2 @babel/core@7.10.4 babel-loader@8.1.0 @babel/preset-env@7.10.4 @babel/preset-react@7.10.4 --save-dev
Ou, usando o yarn:
- yarn add webpack@4.42.0 webpack-cli@3.3.12 webpack-node-externals@1.7.2 @babel/core@7.10.4 babel-loader@8.1.0 @babel/preset-env@7.10.4 @babel/preset-react@7.10.4 --dev
Nota: uma versão anterior deste tutorial instalava o babel-core
, babel-preset-env
e babel-preset-react-app
. Esses pacotes foram arquivados desde então e, ao invés deles, as versões de repositório único são utilizadas.
Em seguida, crie um arquivo de configuração do Babel:
- nano .babelrc.json
Depois disso, adicione as predefinições do env
e do react-app
:
{
"presets": [
"@babel/preset-env",
"@babel/preset-react"
]
}
Nota: uma versão anterior deste tutorial usava um arquivo .babelrc
(sem extensão de arquivo .json
). Esse era um arquivo de configuração para o Babel 6, o que não é mais o caso para o Babel 7.<
Agora, vamos criar uma configuração do webpack para o servidor que usa o Babel Loader para transcompilar o código. Comece criando o arquivo:
- nano webpack.server.js
Depois, adicione as configurações a seguir ao arquivo webpack.server.js
:
const path = require('path');
const nodeExternals = require('webpack-node-externals');
module.exports = {
entry: './server/index.js',
target: 'node',
externals: [nodeExternals()],
output: {
path: path.resolve('server-build'),
filename: 'index.js'
},
module: {
rules: [
{
test: /\.js$/,
use: 'babel-loader'
}
]
}
};
Com essa configuração, nosso pacote de servidor transcompilado será enviado para a pasta server-build
em um arquivo chamado index.js
.
Observe o uso de target: 'node'
e externals: [nodeExternals()]
de webpack-node-externals
, que irá omitir os arquivos de node_modules
no pacote. O servidor pode acessar esses arquivos diretamente.
Isso completa a instalação de dependência e webpack, assim como a configuração do Babel.
Agora, vamos revisitar o package.json
para adicionar scripts auxiliares do npm
:
- nano package.json
Vamos adicionar os scripts dev:build-server
, dev:start
, e dev
ao arquivo package.json
para compilar e servir nosso aplicativo SSR facilmente:
"scripts": {
"dev:build-server": "NODE_ENV=development webpack --config webpack.server.js --mode=development -w",
"dev:start": "nodemon ./server-build/index.js",
"dev": "npm-run-all --parallel build dev:*",
...
},
Usamos o nodemon
para reiniciar o servidor quando fazemos alterações nele. E usamos o npm-run-all
para executar vários comandos em paralelo.
Vamos instalar esses pacotes agora inserindo os seguintes comandos em sua janela de terminal:
- npm install nodemon@2.0.4 npm-run-all@4.1.5 --save-dev
Ou, usando o yarn:
- yarn add nodemon@2.0.4 npm-run-all@4.1.5 --dev
Com isso no lugar, é possível executar o seguinte para compilar o aplicativo do cliente, empacotar e transcompilar o código do servidor e iniciar o servidor em :3006
:
- npm run dev
Ou, usando o yarn:
- yarn run dev
Nossa configuração do webpack do servidor irá monitorar alterações e nosso servidor irá reiniciar nas alterações. No entanto, para o aplicativo cliente, ainda precisamos compilá-lo cada vez que fizermos alterações. Há um problema aberto para isso aqui.
Agora, abra http://localhost:3006/
no seu navegador Web e você verá seu aplicativo do servidor renderizado.
Anteriormente, o código fonte revelava:
Output<div id="root"></div>
Mas agora, com as alterações feitas, o código fonte revela:
Output<div id="root"><h1 data-reactroot="">Hello <!-- -->Sammy<!-- -->!</h1></div>
O renderizador do servidor converteu o componente <App>
em HTML com sucesso.
Neste tutorial, você inicializou um aplicativo React e habilitou a renderização do servidor.
Com este post, apenas abordamos o mais básico dentro de tudo aquilo que é possível. As coisas tendem a ficar um pouco mais complicadas quando o encaminhamento, coleta de dados, ou o Redux também precisam fazer parte de um aplicativo renderizado no servidor.
Um dos principais benefícios de usar o SSR é ter um aplicativo que pode ser rastreado por seu conteúdo, mesmo por rastreadores que não executam código JavaScript. Isso pode ajudar com a otimização de mecanismos de busca (SEO) e fornecendo metadados aos canais de mídia social.
O SSR também pode ajudar com o desempenho, pois um aplicativo totalmente carregado é enviado do servidor na primeira solicitação. Para aplicativos não triviais, a efetividade desse método pode variar, pois o SSR requer uma configuração que pode ficar um tanto complicada e cria uma carga maior no servidor. Saber quando usar a renderização do servidor para o seu aplicativo React depende de suas necessidades específicas e quais recursos fazem mais sentido para o seu caso de uso.
Se quiser aprender mais sobre o React, dê uma olhada em nossa série Como programar no React.js, ou confira nossa página do tópico React para exercícios e projetos de programação.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!