No tienes acceso a esta clase

¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera

Definición de la función principal para realizar el renderizado desde el servidor

10/22
Recursos

Aportes 42

Preguntas 11

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad?

o inicia sesión.

La verdad no es fácil es bastante complejo

A pesar que no me salen errores, siento que sólo estoy copiando código y no me están quedando claros los conceptos.

Me incomoda un poco cuando un profesor después de un montón de clases, miles de configuraciones, uno que otro error y otros cuantos typos dice algo como “ven qué fácil!!” …lo cierto es que no, no es fácil. Se requieren años de entrenamiento ninja para dominar el tema.

La cosa funciona porque uno va como borrego haciendo lo mismo que él hace, pero cuando tomamos este curso varios meses después de haber sido publicado, y algunas dependencias han sido actualizadas, se tienen aún más dificultades que en muchos casos se resuelven gracias a los comentarios dejados por los demás.

¿Se puede dominar?, Sí, definitivamente sí, pero requiere tiempo, por lo tanto NO, no es fácil.

PD: Desahogado, listo para la siguiente clase! 😃

<h1>Definiendo al función principal para realizar el renderizado desde el servidor</h1>

Para poder completar el SSR es necesario generar una función el cual va a enviar el html como respuesta para que el cliente sea capaz de renderizarlo

Para comenzar debemos importar las siguientes dependencias en el archivo server.js

import React from 'react'; 
import { renderToString } from 'react-dom/server'; //Funcion para renderear los componentes como string
import { Provider } from 'react-redux'; //redux
import { createStore } from 'redux'; //redux
import { renderRoutes } from 'react-router-config'; //router
import { StaticRouter } from 'react-router-dom'; //router
import serverRoutes from '../frontend/routes/serverRoutes'
import reducer from '../frontend/reducer'; //redux
import initialState from '../frontend/initialState'; //redux
//Recuerda instalar los paquetes necesarios con npm si no cuentas con ellos

Luego, vamos a definir una función dentro del mismo archivo que se encargara de preparar el las rutas y el redux

const renderApp = () => {
	const store = createStore(reducer, initialState);
	const html = renderToString(
		<Provider store={store}>
			<StaticRouter location={req.url} contenxt{{}}>
				{renderRoutes(serverRoutes)}
			</StaticRouter>
		</Provider>
	); //con esta funcion preparamos el provider para el redux y el router, 
		//dentro del router colocamos la funcion renderRoutes y le pasamos el archivo de las rutas
	res.send(html);
}

Después, creamos otra función la cual prepara la respuesta en HTML como string

const setResponse = (html) => {
	return(`<!DOCTYPE html>
  <html>
    <head>
      <link rel="stylesheet" href="assets/app.css" type="text/css"/> 
      <title>Platzi Video</title>
    </head>
    <body>
      <div id="app">${html}</div>
    </body>
    <script src="assets/app.js" type="text/javascript"></script>
  </html>`);
}

Con esta función, enviamos un template con nuestros estilos y nuestro javascript cambiando el body dependiendo de que ruta usemos

Posteriormente alteramos el la ruta del principal del server app.get para enviar las funciones previamente hechas

app.get('*', renderApp);

Y para terminar, modificamos la respuesta que envía la función renderApp de la siguiente forma

res.send(setResponse(html));

Una vez realizado esto, debemos instalar una dependencia para evitar que el servidor cargue estilos de CSS en el servidor, por ello instalamos la siguiente dependencia y agregamos una linea a index.js dentro del server

npm install ignore-styles

Linea a agregar en server/index.js

require('ignore-styles');

Y listo, podemos correr nuestra app y desactivar javascript en el cliente y todo debería funcionar sin mayor problema pues todo el renderizado esta sucediendo en el servidor

El profesor está introduciendo la propiedad context sin ningún tipo de contexto 👀

Si estan teniendo el mensaje de error “Invariant failed: You should not use <Switch> outside a <Router>”. Lo que tienen que hacer es actualizar la dependencia react-router-dom para que esté a la par de la dependencia react-router. El error proviene de tener estas 2 dependencias con versiones incompatibles.

Pueden actualizar con: npm install react-router-dom

Primero, es fácil seguir los pasos tipeando como simio tal cual lo hace el profe.
Segundo, ¿tan difícil es explicar los fundamentos o motivos por los cuales se hacen las cosas en el backend?
Ya van varios cursos donde se repite lo mismo “escribimos esto, el linter nos ayuda, escribimos lo otro, ahora lo otro, el linter nos ayuda”, está genial que se explique y relate cómo lo arma el profe pero quiero entender el porqué de las cosas.

Exlicación de “context”

En un entorno normal, cuando se encuentra un <Redirect>, cambia el estado de la App, y como consecuencia cambia lo que se muestra en pantalla. Pero un renderizado SSR es stateless, si en él se encuentra un <Redirect>, no se podrá cambiar el estado.
‎‎
Por eso el Static Router recibe un objeto context



Si se encuentra un Redirect, se va a guardar la nueva url en context.url, de esta manera,
desde el lado del server, podemos verificar si luego de la renderización, existe context.url,
si existe, redireccionamos manualmente.
‎‎

renderToString()
Renderiza un elemento React a su HTML inicial. React devolverá HTML en una cadena de texto. Puedes usar este método para generar HTML en el servidor y enviar el marcado en la solicitud inicial para que las páginas se carguen más rápido y permitir que los motores de búsqueda rastreen tus páginas con fines de SEO.

Desde: https://es.reactjs.org/docs/react-dom-server.html#rendertostring

Si van buscando un poco los paquetes individualmente y leyendo encontrarán el propósito del código. No se desanimen por no entender algo al principio. 😄

dice y muestra todo lo que hay que hacer y lo hace, pero no explica conceptualmente que está haciendo y para que… no es como el profe de webpack, ese profe es el mejor de todos

La idea general de esta clase es hacer un archivo de router que se despliegue desde el servidor de express, por ello lo hacemos en este archivo

  1. importamos las cosas que vamos a necesitar
import express from 'express';
import dotenv from 'dotenv';
import webpack from 'webpack';

/** 1. Importamos aqui los datos que usaremos */
//requerimos react para poder manejar componentes de react
import React from 'react';
// este metodo permite tomar un string y a partir de el poder renderizar en el DOM
import { renderToString } from 'react-dom/server';
// Componente contenedor del GlobalState, necesitamos un state para este router server
import { Provider } from 'react-redux'; 
// crea el store como en un entorno redux normal
import { createStore } from 'redux';
// renderRoutes es la configuraxion para poder renderizar un contenido a partir de una ruta estatica
import { renderRoutes } from 'react-router-config';
// es un componente con el cual podemos obtener la ruta actual
import { StaticRouter } from 'react-router-dom';
// es nuestro archivo que contiene todas las rutas configuradas en un array para poder acceder a los componentes dependiendo de la url
import serverRoutes from '../frontend/routes/serverRoutes';
//los reducers de datos para redux
import reducer from '../frontend/reducers/index';
// archivo que contiene el inicialstate
import initialState from '../frontend/initialState';

/* toma el archivo .env y toma sus constantes */
dotenv.config();
const { ENV, PORT } = process.env;
const app = express();

/* console.log cualquiera */
if (ENV === 'development') {
  console.log('Development config');

  // Definiendo las dependencias instaladas
  const webpackConfig = require('../../webpack.config');
  const webpackDevMiddleware = require('webpack-dev-middleware');
  const webpackHotMiddleware = require('webpack-hot-middleware');
  const compiler = webpack(webpackConfig);

  // esto es solo un objeto con datos de configuracion
  const serverConfig = { serverSideRender: true, publicPath: webpackConfig.output.publicPath };

  app.use(webpackDevMiddleware(compiler, serverConfig));
  app.use(webpackHotMiddleware(compiler));

} else console.log('Production config');


/** Componente main contenedor de HTML, la variable html contiene el router y por consecuencia todos los componentes que utilizamos en la SPA */
const setResponse = (html) => {
  return (`
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Video Storage</title>
      <link rel="stylesheet" href="assets/app.css" type="text/css">
    </head>
    <body>
      <div id="app">${html}</div>
      <script src="assets/app.js" type="text/javascript"></script>
    </body>
    </html>  
  `);
};

/** Render App es la funcion que maneja la peticion hecha a cualquier ruta, como puedes ver, es practicamente el archivo contenedor del router de nuestra app anterior */
const renderApp = (req, res) => {
  // crea el estado de redux
  const store = createStore(reducer, initialState);
  
  // se crea el contenedor del dom y del router, si te fijas cada uno de esos componentes hace algo muy especificos.
  // Provider crea el estado
  // StaticRouter ayuda a manejar la ruta
  // renderRoutes obtiene el conjunto del archivo routes que creamos para el server
  const html = renderToString(
    <Provider store={store}>
      <StaticRouter location={req.url} context={{}}>
        {renderRoutes(serverRoutes)}
      </StaticRouter>
    </Provider>,
  );
  // por ultimo respondemos la peticion con el contenido de la ruta
  res.send(setResponse(html));
};

/** Aqui es donde se toma que cualquier peticion se vaya a nuestro archivo principal, que maneja el router, seria la funcion renderApp*/
//  como ves esto se renderiza en cada peticion
app.get('*', renderApp);

app.listen(PORT, (err) => {
  if (err) console.log(err);
  else console.log('Server running on port 3000');
});

Me sale error todavía:

Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object.
at ReactDOMServerRenderer.render (C:\Users\USUARIO\Desktop\Raphael\platzi\Express\PlatziVideo\node_modules\react-dom\cjs\react-dom-server.node.development.js:3743:17)
at ReactDOMServerRenderer.read (C:\Users\USUARIO\Desktop\Raphael\platzi\Express\PlatziVideo\node_modules\react-dom\cjs\react-dom-server.node.development.js:3373:29)
at renderToString (C:\Users\USUARIO\Desktop\Raphael\platzi\Express\PlatziVideo\node_modules\react-dom\cjs\react-dom-server.node.development.js:3988:27)
at renderApp (C:\Users\USUARIO\Desktop\Raphael\platzi\Express\PlatziVideo\src\server/server.js:50:16)
at Layer.handle [as handle_request] (C:\Users\USUARIO\Desktop\Raphael\platzi\Express\PlatziVideo\node_modules\express\lib\router\layer.js:95:5)
at next (C:\Users\USUARIO\Desktop\Raphael\platzi\Express\PlatziVideo\node_modules\express\lib\router\route.js:137:13)
at Route.dispatch (C:\Users\USUARIO\Desktop\Raphael\platzi\Express\PlatziVideo\node_modules\express\lib\router\route.js:112:3)
at Layer.handle [as handle_request] (C:\Users\USUARIO\Desktop\Raphael\platzi\Express\PlatziVideo\node_modules\express\lib\router\layer.js:95:5)
at C:\Users\USUARIO\Desktop\Raphael\platzi\Express\PlatziVideo\node_modules\express\lib\router\index.js:281:22
at param (C:\Users\USUARIO\Desktop\Raphael\platzi\Express\PlatziVideo\node_modules\express\lib\router\index.js:354:14)

Ayuda tengo este error

Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.
    at ReactDOMServerRenderer.render (/mnt/c/users/57305/documents/escuela_js/platzivideo/node_modules/react-dom/cjs/react-dom-server.node.development.js:3743:17)
    at ReactDOMServerRenderer.read (/mnt/c/users/57305/documents/escuela_js/platzivideo/node_modules/react-dom/cjs/react-dom-server.node.development.js:3373:29)
    at renderToString (/mnt/c/users/57305/documents/escuela_js/platzivideo/node_modules/react-dom/cjs/react-dom-server.node.development.js:3988:27)
    at renderApp (/mnt/c/users/57305/documents/escuela_js/platzivideo/src/server/server.js:122:16)
    at Layer.handle [as handle_request] (/mnt/c/users/57305/documents/escuela_js/platzivideo/node_modules/express/lib/router/layer.js:95:5)
    at next (/mnt/c/users/57305/documents/escuela_js/platzivideo/node_modules/express/lib/router/route.js:137:13)
    at Route.dispatch (/mnt/c/users/57305/documents/escuela_js/platzivideo/node_modules/express/lib/router/route.js:112:3)
    at Layer.handle [as handle_request] (/mnt/c/users/57305/documents/escuela_js/platzivideo/node_modules/express/lib/router/layer.js:95:5)
    at /mnt/c/users/57305/documents/escuela_js/platzivideo/node_modules/express/lib/router/index.js:281:22
    at param (/mnt/c/users/57305/documents/escuela_js/platzivideo/node_modules/express/lib/router/index.js:354:14)

Ayuda, me sale este error en mi proyecto y no se como solucionarlo

[nodemon] starting `node src/backend/index.js`
file:///D:/GitHub/plataformaDatos/src/backend/server.js:55
        <Provider store={store}>
        ^

SyntaxError: Unexpected token '<'
    at Loader.moduleStrategy (internal/modules/esm/translators.js:141:18)
[nodemon] app crashed - waiting for file changes before starting...
Terminate batch job (Y/N)?
^C
D:\GitHub\plataformaDatos>node ./src/backend/index.js
file:///D:/GitHub/plataformaDatos/src/backend/server.js:55
        <Provider store={store}>
        ^

SyntaxError: Unexpected token '<'
    at Loader.moduleStrategy (internal/modules/esm/translators.js:141:18)

Mi codigo tiene todo lo que el codigo del profesor contiene

const renderApp = (req, res) => {
    const store = createStore(reducer, estadoInicial);
    const html = renderToString(
        <Provider store={store}>
            <StaticRouter location={req.url} context={{}}>
                {renderRoutes(rutasServidor)}
            </StaticRouter>
        </Provider>
    );
    res.send(setResponse(html));
}

Parte de ser buen maestro o maestra se trata de reconocer la dificultad de adquirir conocimiento. reconocerlo como algo sencillo solo muestra la falta de experiencia del maestro o maestra.

Echarle un vistazo a este artículo Static Router

Opté por dejar de seguir al profe, y descargar el código en la última clase, leer código, investigar lo que no entienda y quedarme solo con los pocos tips que da el profe.

Necesito ayuda 👋. Estoy agregando imagenes con formato : .webp

Me da error:

assets/img/imgtest.webp:1
RIFF��
    

SyntaxError: Invalid or unexpected token
    at wrapSafe (internal/modules/cjs/loader.js:979:16)
    at Module._compile (internal/modules/cjs/loader.js:1027:27)
    at Module._extensions..js (internal/modules/cjs/loader.js:1092:10)

El codigo de mi webpack:

const path = require("path");
const webpack = require("webpack");

// const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const { loader } = require("mini-css-extract-plugin");

module.exports = {
  entry: [
    "./src/frontend/index.js",
    "webpack-hot-middleware/client?path=/__webpack_hmr&timeout=2000&reload=true",
  ],
  mode: "development",
  output: {
    path: path.resolve(__dirname, "dist"),
    filename: "assets/app.js",
    publicPath: "/",
  },
  resolve: {
    extensions: [".js", ".jsx"],
  },
  module: {
    rules: [
      {
        test: /\.(js|jsx)$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader",
        },
      },
      {
        test: /\.html$/,
        use: [
          {
            loader: "html-loader",
          },
        ],
      },
      {
        test: /\.(s*)css$/,
        use: [
          {
            loader: MiniCssExtractPlugin.loader,
          },
          "css-loader",
        ],
      },
      {
        test: /\.(png|jpg|gif|webp)$/,
        use: [
          {
            loader: "file-loader",
            options: {
              name: "assets/[hash].[ext]",
            },
          },
        ],
      },
    ],
  },
  devServer: {
    historyApiFallback: true,
  },
  plugins: [
    new webpack.HotModuleReplacementPlugin(),
    new MiniCssExtractPlugin({
      filename: "assets/app.css",
    }),
    
  ],
};
 

Alguna idea.

Les comparto mi interpretación sobre las cosas que estamos importando en el servidor.

import React from 'react';
// para renderizar a travez de un string
import {renderToString} from 'react-dom/server';
// provider de redux
import { Provider } from 'react-redux';
// store de redux
import { createStore } from 'redux';
// router estátíco desde el backend
import {StaticRouter} from 'react-router-dom'
// función que recibe las rutas del front y sus componentes
// a renderizar por medio de un array
import { renderRoutes} from 'react-router-config'
// archivo con array de rutas definidas para el ssr
import serverRoutes from '../frontend/routes/serverRoutes'
// reducer de redux el cual se encarga de modificar el state
import reducer from '../frontend/reducers/index';
// state inicial que utiliza el reducer para iniciar el estado de redux
import initialState from '../frontend/initialState';

mmm…no es tan sencillo, creo que debe haber una forma de automatizar este proceso, en angular se puede hacer esto con un solo comando por consola y solo tienes q configurar un archivo con las rutas

Muchas librerías mucho contenido bastante código movido creo que fácil es para el que sabe, tocara practicar.

Dejo una lectura que trata de lo mismo solo que con un proyecto pequeño espero sirva, click aqui

Vaya, me exploto la cabeza, que clase mas magnifica.

"Esto se arregla de manera súper sencilla, ‘ignóralo’ " ^^ entiendo el concepto pero en primera instancia me pareció gracioso C: bastante interesante!

Solucioné mi problema copiando el archivo serverRoutes.js del profesor que está en la sección de enlaces.

SSR la verdad si es bastante difícil pero siempre hay nuevos retos no?

Para todos los que están teniendo el problema de React.createElement: type is invalid, al parecer es un bug en alguna librería. Yo lo solucione cambiando el nombre al archivo Home.jsx a Homee.jsx y funciono.
Algo esta muy raro pero espero les funcione.
PD: Me tarde dos días en encontrar el funcionamiento.

Tengo ese error 😦

Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.
    at ReactDOMServerRenderer.render (C:\Users\lucas\Desktop\ReactApp\node_modules\react-dom\cjs\react-dom-server.node.development.js:3743:17)
    at ReactDOMServerRenderer.read (C:\Users\lucas\Desktop\ReactApp\node_modules\react-dom\cjs\react-dom-server.node.development.js:3373:29)
    at renderToString (C:\Users\lucas\Desktop\ReactApp\node_modules\react-dom\cjs\react-dom-server.node.development.js:3988:27)
    at renderApp (C:\Users\lucas\Desktop\ReactApp\src\server\/server.js:52:16)
    at Layer.handle [as handle_request] (C:\Users\lucas\Desktop\ReactApp\node_modules\express\lib\router\layer.js:95:5)
    at next (C:\Users\lucas\Desktop\ReactApp\node_modules\express\lib\router\route.js:137:13)
    at Route.dispatch (C:\Users\lucas\Desktop\ReactApp\node_modules\express\lib\router\route.js:112:3)
    at Layer.handle [as handle_request] (C:\Users\lucas\Desktop\ReactApp\node_modules\express\lib\router\layer.js:95:5)
    at C:\Users\lucas\Desktop\ReactApp\node_modules\express\lib\router\index.js:281:22
    at param (C:\Users\lucas\Desktop\ReactApp\node_modules\express\lib\router\index.js:354:14)```

Para las personas que nos les quedo claro el tema de SSR, aquí les dejos un video un poquito largo pero que en mi opinión explica muy bien el tema.
Hasta el minuto 16 es la base teórica, del 16 en adelante se muestra un ejemplo practico.

Server side rendering en react

La clase me resultó complicada, el proceso es claro desde un punto de vista “copy paste” de lo que hace el profesor, pero no deja en claro cuales son los pasos del proceso sin ahondar en detalles.
Desde el punto de vista macro esto es muy sencillo:

  • Importamos dependencias necesarias -> dependencias que usamos en las siguientes funciones
  • Creamos una función renderApp -> acá está toda la app, con el router y redux.
  • Creamos una función setResponse -> este es el html de nuestra app
  • Usamos estas funciones -> en el get ejecutamos renderApp y en el send setResponse
  • Aplicamos ignore-styles -> esto hace que no se rendericen estilos en el server

Este curso mas bien debería ser ‘terminando de codear Platzi Video’. Pura programación de las tecnologías y lo único explicativo respecto al título del curso (curso de Server Side Render con Express) es la explicación entre SSR & CSR. Sumándole que en el examen una de sus consultas es en que archivo se hiso tal cosa y no es un archivo de una tecnología sino es cuando uno crea un archivo - por ejemplo - llamado promise.js y crea una promesa aleatoria.
En lo personal esa tipo de pregunta me es algo irrelevante.

Estuvo bastante complejo jaja pero creo que entendí el 70 u 80% eso si tal vez con mucha práctica sea capaz de hacerlo solo jaja

“Ser enviados al servidor, desde el servidor y hacia el cliente”… Pésimo.

Yo lo que entiendo del curso es que estamos creando una arquitectura como Laravel pero desacoplado en distintos frameworks y librerías de Javascript, ya que lo estamos renderizando del lado del server (el frontend y respuestas de apis) en una sola respuesta, así como lo hace cualquier framework de PHP.

Ojo: no estoy diciendo que estamos haciendo un Laravel o que PHP es mejor, solo me da esa impresión, ya que estos frameworks ya devuelven la respuesta armada con todo y datos, sin necesidad de que el cliente haga peticiones a las APIs para obtener las fuentes de información.

Muy buena clase Profe! aprendi mucho, es un poco complejo el tema, pero, nada que no podamos arreglar con un poco de investigación

Tengo el mismo error que varios compañeros con la función renderToString en el archivo server.js al querer entrar al localhost:3000.

Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.
    at ReactDOMServerRenderer.render (/Users/nmanograsso/Proyectos/retrogames--front/node_modules/react-dom/cjs/react-dom-server.node.development.js:3743:17)
    at ReactDOMServerRenderer.read (/Users/nmanograsso/Proyectos/retrogames--front/node_modules/react-dom/cjs/react-dom-server.node.development.js:3373:29)
    at renderToString (/Users/nmanograsso/Proyectos/retrogames--front/node_modules/react-dom/cjs/react-dom-server.node.development.js:3988:27)
    at renderApp (/Users/nmanograsso/Proyectos/retrogames--front/src/server/server.js:53:16)
    at Layer.handle [as handle_request] (/Users/nmanograsso/Proyectos/retrogames--front/node_modules/express/lib/router/layer.js:95:5)
    at next (/Users/nmanograsso/Proyectos/retrogames--front/node_modules/express/lib/router/route.js:137:13)
    at Route.dispatch (/Users/nmanograsso/Proyectos/retrogames--front/node_modules/express/lib/router/route.js:112:3)
    at Layer.handle [as handle_request] (/Users/nmanograsso/Proyectos/retrogames--front/node_modules/express/lib/router/layer.js:95:5)
    at /Users/nmanograsso/Proyectos/retrogames--front/node_modules/express/lib/router/index.js:281:22
    at param (/Users/nmanograsso/Proyectos/retrogames--front/node_modules/express/lib/router/index.js:354:14)

Intenté las soluciones que están en los comment y busqué en StackOverflow pero no lo pude solucionar. También intente copiar el archivo server.js de la sección de enlaces, el archivo serverRoutes.js y el proyecto entero pero no funcionó 🤯.

Por el momento la unica solución que encontré es borrar la ruta Home (antes de esto también intenté renombrar el archivo) del archivo serverRoutes quedando de la siguiente manera

import Login from '../containers/Login';
import Register from '../containers/Register';
import NotFound from '../containers/NotFound';
import Player from '../containers/Player';

const routes = [
  {
    exact: true,
    path: '/login',
    component: Login,
  },
  {
    exact: true,
    path: '/register',
    component: Register,
  },
  {
    exact: true,
    path: '/player/:id',
    component: Player,
  },
  {
    name: 'NotFound',
    component: NotFound,
  },
];

export default routes;

Se que no es lo mas pro esta solución pero voy a seguir probando e investigando, y si encuentro algo mejor lo comparto 😁

Toooodas las configuraciones necesarias para hacer SSR 😱

Bueno, según lo que yo entendí (me corrigen si me equivoco) no es tan complicado.

Creamos la función renderApp(), en la cual creamos el store para poder manejar el estado inicial desde el lado del servidor. Luego creamos la constante html que va a convertir en string todos nuestros componentes de la app(en pocas palabras).
Y lo pasamos como parámetro de setResponse()

const renderApp = (req, res) => {
  const store = createStore(reducer, initialState);
  const html = renderToString(
    <Provider store={store}>
      <StaticRouter location={req.url} context={{}}>
        {renderRoutes(serverRoutes)}
      </StaticRouter>
    </Provider>,
  );

  res.send(setResponse(html));
};

En setResponse() vamos a retornar con un template string el html de nuestra app recibiendo por parámetro el JSX hecho string en el div que contiene toda nuestra app.

const setResponse = (html) => {
  return (
    `
    <!DOCTYPE html>
    <html>
      <head>
        <link rel="stylesheet" href="assets/app.css" type="text/css"/>
        <title>Platzi Video</title>
      </head>
      <body>
        <div id="app">${html}</div>
        <script src="assets/app.js" type="text/javascript"></script>
      </body>
    </html>
  `
  )
}

Hecho esto pasamos la función renderApp() a ↓↓ para que se renderice cuando hacemos el llamado a cualquier ruta

app.get('*', renderApp);

Dificil!

Pues es bastante complejo este tema del SSR y si en especial esta clase va múy rápido.

Super facil… .-.

Complejo…