Kuidas juurutada rakenduses React serveripoolne renderdamine kolme lihtsa sammuga

Autor Rohit Kumar

Selles õpetuses ehitame järgmist: selline kena React-kaart.

Selles õpetuses kasutame HTML-vastuse edastamiseks serveripoolset renderdamist, kui kasutaja või roomik tabab lehe URL-i. Viimaseid taotlusi käsitleme kliendi poolel.

Miks me seda vajame?

Las ma juhatan teid vastuseni.

Mis vahe on kliendipoolsel ja serveripoolsel renderdamisel?

In Kliendipoolne renderdamine, Brauser laadib minimaalne HTML leht. See renderdab JavaScripti ja täidab selle sisu.

Serveripoolne renderdamine muudab seevastu serveri React komponendid. Väljundiks on HTML-sisu.

Isomorfse rakenduse loomiseks saate need kaks ühendada.

Reaktsiooni renderdamise miinused serveris

  • SSR võib parandada jõudlust, kui teie rakendus on väike. Kuid see võib halvendada ka jõudlust, kui see on raske.
  • See pikendab reageerimisaega (ja see võib olla hullem, kui server on hõivatud).
  • See suurendab vastuse suurust, mis tähendab, et lehe laadimine võtab kauem aega.
  • See suurendab rakenduse keerukust.

Millal peaksite kasutama serveripoolset renderdamist?

Hoolimata nendest SSR-i tagajärgedest, on mõningaid olukordi, kus saate ja peaksite seda kasutama.

1. SEO

Iga veebisait soovib ilmuda otsingutes. Parandage mind, kui ma eksin.

Kahjuks ei saa otsingumootorite robotid veel JavaScripti mõista ega renderdada.

See tähendab, et nad näevad tühja lehte, hoolimata sellest, kui kasulik teie sait on.

Paljud inimesed ütlevad, et Google'i roomik renderdab nüüd JavaScripti.

Selle testimiseks juurutasin rakenduse Herokule. Siin on see, mida nägin Google Search Console'is:

Tühi leht.

See oli suurim põhjus, miks uurisin serveripoolset renderdamist. Eriti kui see on nurgakivi leht nagu sihtleht, ajaveeb jne.

Veenduge, et kontrollida, kas Google teie saidi renderdab, aadressil

Search Console'i ​​juhtpaneel> Roomamine> Too Google'ina. Sisestage lehe URL või jätke see avalehe jaoks tühjaks.

Valige FETCH AND RENDER. Kui olete lõpetanud, klõpsake tulemuse nägemiseks.

2. Parandage jõudlust

SSR-is sõltub rakenduse jõudlus serveri ressurssidest ja kasutaja võrgukiirusest. See muudab selle sisukate saitide jaoks väga kasulikuks.

Näiteks öelge, et teil on keskmise hinnaga kiire Interneti-kiirusega mobiiltelefon. Enne kui midagi näete, proovite pääseda saidile, mis laadib alla 4 MB andmeid.

Kas näete 2–4 sekundi jooksul oma ekraanil midagi?

Kas külastaksite seda saiti uuesti?

Ma ei usu, et sa seda teeksid.

Teine oluline edasiminek on esimese kasutaja interaktsiooni aeg. See on ajaline erinevus alates ajast, kui kasutaja URL-i jõuab, kuni sisu nägemiseni.

Siin on võrdlus. Testisin seda arendus-Macis.

Reageerimine on serveril esitatud

Esimene suhtlusaeg on 300 ms. Hüdraat lõpeb kiirusega 400 ms. Koormussündmus väljub umbes 500 ms kaugusel. Seda näete ülaltoodud pilti vaadates.

Reageerimine on esitatud kliendi brauseris

Esimene suhtlusaeg on 400 ms. Koormussündmus väljub 470 ms juures.

Tulemus räägib enda eest. Sellise väikese rakenduse esimese kasutaja suhtlemisajas on 100 ms erinevus.

Kuidas see töötab? - (4 lihtsat sammu)

  • Looge iga taotluse korral värske Redux Store.
  • Soovi korral saadetakse mõned toimingud.
  • Võtke riik poest välja ja sooritage SSR.
  • Saatke koos vastusega eelmises etapis saadud olek.

Lähteseisundi loomisel kliendipoolel kasutame vastuses antud olekut.

Enne alustamist kloonige / laadige täielik näide alla Githubist ja kasutage seda viitena.

Alustamine meie rakenduse seadistamisega

Esmalt avage oma lemmiktoimetaja ja kest. Looge oma rakendusele uus kaust. Alustame.

npm init --yes

Sisestage üksikasjad. Pärast package.jsonloomist kopeerige sinna allolevad sõltuvused ja skriptid.

Installige kõik sõltuvused, käivitades:

npm install

Peate konfigureerima Babeli ja veebipaki, et meie ehituskript töötaks.

Babel teisendab ESM-i ja reageerib sõlme ning brauserist arusaadavaks koodiks.

Looge uus fail .babelrcja pange sellesse rida allpool.

{ "presets": ["@babel/env", "@babel/react"] } 

webpack koondab meie rakenduse ja selle sõltuvused ühte faili. Looge järgmine fail, webpack.config.js milles on järgmine kood:

const path = require('path');module.exports = { entry: { client: './src/client.js', bundle: './src/bundle.js' }, output: { path: path.resolve(__dirname, 'assets'), filename: "[name].js" }, module: { rules: [ { test: /\.js$/, exclude: /node_modules/, loader: "babel-loader" } ] } }

Ehitamisprotsessi väljundi kaks faili:

  1. assets/bundle.js — pure client side app.
  2. assets/client.js — client side companion for SSR.

The src/ folder contains the source code. The Babel compiled files go into views/. views directory will be created automatically if not present.

Why do we need to compile source files?

The reason is the syntax difference between ESM & CommonJS. While writing React and Redux, we heavily use import and export in all files.

Unfortunately, they don’t work in Node. Here comes Babel to rescue. The script below tells Babel to compile all files in the src directory and put the result in views.

"babel": "babel src -d views",

Now, Node can run them.

Copy Precoded & Static files

If you have already cloned the repository, copy from it. Otherwise download ssr-static.zip file from Dropbox. Extract it and keep these three folders inside your app directory. Here’s what they contain.

  1. React App and components resides in src/components.
  2. Redux files in src/redux/.
  3. assets/ & media/: Contain static files such as style.css and images.

Server Side

Create two new files named server.js and template.js inside the src/ folder.

1. src/server.js

Magic happens here. This is the code you’ve been searching for.

import React from 'react'; import { renderToString } from 'react-dom/server'; import { Provider } from 'react-redux'; import configureStore from './redux/configureStore'; import App from './components/app'; module.exports = function render(initialState) { // Model the initial state const store = configureStore(initialState); let content = renderToString(); const preloadedState = store.getState(); return { content, preloadedState }; };

Instead of rendering our app, we need to wrap it into a function and export it. The function accepts the initial state of the application.

Here’s how it works.

  1. Pass initialState to configureStore(). configureStore()returns a new Store instance. Hold it inside the store variable.
  2. Call renderToString() method, providing our App as input. It renders our app on the server and returns the HTML produced. Now, the variable content stores the HTML.
  3. Get the state out of Redux Store by calling getState() on store. Keep it in a variable preloadedState.
  4. Return the content and preloadedState. We will pass these to our template to get the final HTML page.

2. src/template.js

template.js exports a function. It takes title, state and content as input. It injects them into the template and returns the final HTML document.

To pass along the state, the template attaches state to window.__STATE__ inside a pt> tag.

Now you can read state on the client side by accessing window.__STATE__.

We also include the SSR companion assets/client.js client-side application in another script tag.

If you request the pure client version, it only puts assets/bundle.js inside the script tag.

The Client Side

The client side is pretty straightforward.

1. src/bundle.js

This is how you write the React and Redux Provider wrap. It is our pure client-side app. No tricks here.

import React from 'react'; import { render } from 'react-dom'; import { Provider } from 'react-redux'; import configureStore from './redux/configureStore'; import App from './components/app'; const store = configureStore(); render( , document.querySelector('#app') );

2. src/client.js

Looks familiar? Yeah, there is nothing special except window.__STATE__. All we need to do is grab the initial state from window.__STATE__ and pass it to our configureStore() function as the initial state.

Let’s take a look at our new client file:

import React from 'react'; import { hydrate } from 'react-dom'; import { Provider } from 'react-redux'; import configureStore from './redux/configureStore'; import App from './components/app'; const state = window.__STATE__; delete window.__STATE__; const store = configureStore(state); hydrate( , document.querySelector('#app') );

Let’s review the changes:

  1. Replace render() with hydrate(). hydrate() is the same as render() but is used to hydrate elements rendered by ReactDOMServer. It ensures that the content is the same on the server and the client.
  2. Read the state from the global window object window.__STATE__. Store it in a variable and delete the window.__STATE__.
  3. Create a fresh store with state as initialState.

All done here.

Putting it all together

Index.js

This is the entry point of our application. It handles requests and templating.

It also declares an initialState variable. I have modelled it with data in the assets/data.json file. We will pass it to our ssr() function.

Note: While referencing a file that is inside src/ from a file outside src/ , use normal require() and replace src/ by views/. You know the reason (Babel compile).

Routing

  1. /: By default server-rendered homepage.
  2. /client: Pure client-side rendering example.
  3. /exit: Server stop button. Only available in development.

Build & Run

It’s time to build and run our application. We can do this with a single line of code.

npm run build && npm run start

Now, the application is running at //localhost:3000.

Ready to become a React Pro?

I am starting a new series from next Monday to get your React skills blazing, immediately.

Thank you for reading this.

If you like it and find it useful, follow me on Twitter & Webflow.