Server-side rendering (SSR) is technique when content for a web page is rendered on the server using JavaScript. SSR speeds initial loading up that, in turn, helps increase Google PageSpeed Performance score for SPA (React.js, Vue.js, Angular, etc.). Usual approach is to use web server such as and render on the server in the fly. We all know that is quite fast, but we want to boost our web app to maximum available speed. Node.js Express.js Node.js Does SSR require Node.js? Commonly, React.js Apps have static numbers of routes. So, we can easily make rendered pages at the same stage when JavaScript bundles are generating. So, we can use these static HTML files with any web server that lets to implement routing logic. That basically means by getting a route, e.g: the web server returns according an HTML file that is created by using test.com/test ReactDOMServer.renderToString() React App Setup Let's first start with preparing front-end side as an example will be using . React.js We need to create a simple React.js website with three routes. At first, we should create a file with Routes for using it in React app and web server. ROUTES = { : , : , : , }; .exports = ROUTES; const HOME_PAGE '/' ABOUT '/about' CONTACT '/contact' // Keep it as CommonJS (Node.js) export module Normally, React.js app optimisation starts with code splitting. In our case is good to split code by routes. Good choice for it is using . This library has ready to go solution for SSR that is located in the npm package. The first package allow to use dynamic import inside React, therefore Webpack can split bundle by these imports . @loadable/component @loadable/server HomePage = loadable( ( ), { : const => () import './pages/home/HomePage' fallback , }); < /> Loading In addition, we should use instead of for SSR side. To achieve this we can have two different entry points: App.jsx and AppSsr.jsx, the last one includes: StaticRouter BrowserRouter { StaticRouter } ; Routes ; { ( <Routes /> ); } import from 'react-router' import from './Routes' ( ) function App { route } return < = > StaticRouter location {route} </ > StaticRouter Next task for us is creating a function that creates an HTML file by route. Using code looks like that: @loadable/server { ChunkExtractor } = ( ); { nodeExtractor = ChunkExtractor({ : nodeStats }); { : App } = nodeExtractor.requireEntrypoint(); webExtractor = ChunkExtractor({ : webStats }); jsx = webExtractor.collectChunks(React.createElement(App, { route })); innerHtml = renderToString(jsx); css = webExtractor.getCssString(); data = { innerHtml, : webExtractor.getLinkTags(), : webExtractor.getStyleTags(), : webExtractor.getScriptTags(), css, }; templateFile = path.resolve(__dirname, ); ejs.renderFile(templateFile, data, {}, (err, html) => { (err) { .error(err); (err); } { htmlMini = minify(html, { : , : , }); fs.writeFile( , htmlMini, , () => { .log( ); }); } }); } const require '@loadable/server' async ( ) function createServerHtmlByRoute route, fileName const new statsFile const default const new statsFile const const const await const linkTags styleTags scriptTags const './index-ssr.ejs' if console throw new Error else const minifyCSS true minifyJS true ` / .html` ${distPath} ${fileName} 'utf8' console `>>>>>>>>>>>>>>>> for Route: ----> .html --> Ok` ${route} ${fileName} So, now we can go throw our routes and create all HTML files that we need: { process.env.NODE_ENV = ; .entries(ROUTES).forEach( ([key, value]) => { routes.push([ value.substr( ), key.toLowerCase(), ]); { createServerHtmlByRoute(value, key.toLowerCase()); } (e) { .error(e); process.exit( ); } }); } async ( ) function generateSsr 'production' Object async 1 try await catch console 1 As you noticed in the function there is an HTML template which we are using for putting into it generated HTML and CSS: createServerHtmlByRoute <!DOCTYPE html> < = > html lang "en" < > head < = > style id "css-server-side" < %> %- css </ > style < %> %- linkTags </ > head < > body < = > div id "app" < %> %- innerHtml </ > div < %> %- scriptTags < %> %- styleTags </ > body </ > html It looks like this approach is not perfect because in this case, each HTML file contains some CSS duplicates, such as CSS libraries or common CSS. But it is the simplest solution for speed initial loading up. Another one is an feature - when a Web Server pushing CSS files with HTML together. HTTP/2 Server Push Finally, after running the build script we should get HTML files for all routes and default - index.html: Full example is located in the GitHub repository Thus, we got everything that we need from JavaScript/React.js side. will cover Rust Web server implementation. The next article You can check how this approach works in production by getting Google PageSpeed Insights Performance score for website. PageSpeed Green Happy coding! * Website vector created by slidesgo - www.freepik.com