Jak zaimplementować renderowanie po stronie serwera w aplikacji React w trzech prostych krokach

By Rohit Kumar

Oto, co zbudujemy w tym samouczku: ładną kartę Reacta, taką jak ta.

W tym samouczku użyjemy renderowania po stronie serwera, aby dostarczyć odpowiedź HTML, gdy użytkownik lub crawler trafi na adres URL strony. Te ostatnie żądania będziemy obsługiwać po stronie klienta.

Dlaczego tego potrzebujemy?

Pozwól, że poprowadzę cię do odpowiedzi.

Jaka jest różnica między renderowaniem po stronie klienta a renderowaniem po stronie serwera?

W renderowaniu po stronie klienta, twoja przeglądarka pobiera minimalną stronę HTML. Renderuje ona JavaScript i wypełnia go treścią.

Renderowanie po stronie serwera, z drugiej strony, renderuje komponenty React na serwerze. Wyjściem jest zawartość HTML.

Możesz połączyć te dwie rzeczy, aby stworzyć izomorficzną aplikację.

Cons of Rendering React on the Server

  • SSR może poprawić wydajność, jeśli Twoja aplikacja jest mała. Ale może również pogorszyć wydajność, jeśli jest ciężka.
  • Podnosi czas odpowiedzi (i może być gorzej, jeśli serwer jest zajęty).
  • Podnosi rozmiar odpowiedzi, co oznacza, że strona zajmuje więcej czasu na załadowanie.
  • Podnosi złożoność aplikacji.

Kiedy powinieneś używać Server Side Rendering?

Mimo tych konsekwencji SSR, są pewne sytuacje, w których możesz i powinieneś go używać.

SEO

Każda strona chce się pojawiać w wyszukiwaniach. Popraw mnie, jeśli się mylę.

Niestety, wyszukiwarki nie rozumieją/renderują JavaScript.

To oznacza, że widzą pustą stronę, bez względu na to, jak pomocna jest twoja witryna.

Wielu ludzi twierdzi, że program indeksujący Google teraz renderuje JavaScript.

Aby to przetestować, wdrożyłem aplikację na Heroku. Oto co zobaczyłem w Google Search Console:

Google’s crawler does not render React

Pusta strona.

To był największy powód, dla którego badałem renderowanie po stronie serwera. Szczególnie, gdy jest to podstawowa strona, taka jak strona docelowa, blog i tak dalej.

Aby sprawdzić, czy Google renderuje twoją witrynę, odwiedź:

Search Console Dashboard > Crawl > Fetch as Google. Wpisz adres URL strony lub pozostaw go pustym dla strony głównej.

Wybierz WYKRYJ I RENDERUJ. Po zakończeniu kliknij, aby zobaczyć wynik.

Popraw wydajność

W SSR wydajność aplikacji zależy od zasobów serwera i szybkości sieci użytkownika. To czyni go bardzo użytecznym dla witryn o dużej zawartości.

Na przykład, powiedzmy, że masz średniej klasy telefon komórkowy z wolną prędkością Internetu. Próbujesz wejść na stronę, która pobiera 4MB danych, zanim możesz cokolwiek zobaczyć.

Czy byłbyś w stanie zobaczyć cokolwiek na swoim ekranie w ciągu 2-4 sekund?

Czy odwiedziłbyś tę stronę ponownie?

Nie sądzę, że byś to zrobił.

Innym znaczącym usprawnieniem jest Czas Pierwszej Interakcji Użytkownika. Jest to różnica w czasie od momentu, gdy użytkownik trafia na adres URL do momentu, gdy widzi treść.

Oto porównanie. Testowałem to na rozwojowym komputerze Mac.

React Rendered on Server

Raport wydajnościSSR (Chrome)

Czas pierwszej interakcji wynosi 300ms. Hydrate kończy się w 400ms. Zdarzenie load wychodzi w przybliżeniu po 500ms. Możesz to zobaczyć, sprawdzając powyższy obraz.

React Rendered on Client’s Browser

Raport wydajności po stronie klienta (Chrome)

Pierwszy czas interakcji wynosi 400ms. Zdarzenie load kończy się w 470ms.

Wynik mówi sam za siebie. Jest 100ms różnicy w Czasie Pierwszej Interakcji Użytkownika dla tak małej aplikacji.

Jak to działa? – (4 proste kroki)

  • Utwórz świeży Sklep Redux na każde żądanie.
  • Opcjonalnie wyślij niektóre akcje.
  • Wyciągnij stan ze Sklepu i wykonaj SSR.
  • Wyślij stan uzyskany w poprzednim kroku wraz z odpowiedzią.

Użyjemy stanu przekazanego w odpowiedzi do utworzenia stanu początkowego po stronie klienta.

Zanim zaczniesz, sklonuj/pobierz kompletny przykład z Githuba i użyj go jako odniesienia.

Rozpoczęcie pracy poprzez skonfigurowanie naszej aplikacji

Najpierw otwórz swój ulubiony edytor i powłokę. Utwórz nowy folder dla swojej aplikacji. Zaczynajmy.

npm init --yes

Wypełnij szczegóły. Po utworzeniu package.json skopiuj do niego poniższe zależności i skrypty.

Zainstaluj wszystkie zależności, uruchamiając:

npm install

Trzeba skonfigurować Babel i webpack, aby nasz skrypt budowania działał.

Babel przekształca ESM i react w kod zrozumiały dla Node i przeglądarki.

Utwórz nowy plik .babelrc i umieść w nim poniższą linię.

{ "presets": }

webpack łączy naszą aplikację i jej zależności w jeden plik. Utwórz kolejny plik webpack.config.js z następującym kodem:

const path = require('path');module.exports = { entry: { client: './src/client.js', bundle: './src/bundle.js' }, output: { path: path.resolve(__dirname, 'assets'), filename: ".js" }, module: { rules: }}

W wyniku procesu budowania powstają dwa pliki:

  1. assets/bundle.js – czysta aplikacja po stronie klienta.
  2. assets/client.js – towarzysz po stronie klienta dla SSR.

Folder src/ zawiera kod źródłowy. Skompilowane pliki Babel trafiają do views/. views katalog zostanie utworzony automatycznie, jeśli nie jest obecny.

Dlaczego musimy kompilować pliki źródłowe?

Powodem jest różnica w składni pomiędzy ESM & CommonJS. Podczas pisania React i Redux, mocno używamy import i export we wszystkich plikach.

Niestety, nie działają one w Node. Tutaj na ratunek przychodzi Babel. Poniższy skrypt każe Babelowi skompilować wszystkie pliki w katalogu src i umieścić wynik w views.

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

Teraz Node może je uruchomić.

Kopiowanie prekodowanych & plików statycznych

Jeśli już sklonowałeś repozytorium, skopiuj z niego. W przeciwnym razie pobierz plik ssr-static.zip z Dropbox. Rozpakuj go i zachowaj te trzy foldery w swoim katalogu aplikacji. Oto, co zawierają.

  1. React App i komponenty rezydują w src/components.
  2. Pliki Redux w src/redux/.
  3. assets/ & media/: Zawierają pliki statyczne, takie jak style.css i obrazy.

Server Side

Utwórz dwa nowe pliki o nazwach server.js i template.js wewnątrz folderu src/.

src/server.js

Magia dzieje się tutaj. To jest kod, którego szukałeś.

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(<Provider store={store} ><App /></Provider>); const preloadedState = store.getState(); return { content, preloadedState };};

Zamiast renderować naszą aplikację, musimy zawinąć ją w funkcję i wyeksportować. Funkcja przyjmuje stan początkowy aplikacji.

Oto jak to działa.

  1. Przekaż initialState do configureStore(). configureStore() zwróci nową instancję Store. Trzymaj ją wewnątrz zmiennej store.
  2. Wywołaj metodę renderToString(), podając naszą aplikację jako dane wejściowe. Renderuje ona naszą aplikację na serwerze i zwraca wyprodukowany HTML. Teraz zmienna content przechowuje HTML.
  3. Wyciągnij stan z Redux Store, wywołując getState() na store. Przechowuj go w zmiennej preloadedState.
  4. Zwróć content i preloadedState. Przekażemy je do naszego szablonu, aby uzyskać ostateczną stronę HTML.

2. src/template.js

template.js eksportuje funkcję. Pobiera ona title, state i content jako dane wejściowe. Wstrzykuje je do szablonu i zwraca końcowy dokument HTML.

Aby przekazać stan, szablon dołącza state do window.__STATE__ wewnątrz znacznika <script>.

Teraz można odczytać state po stronie klienta, uzyskując dostęp do window.__STATE__.

Włączamy również aplikację SSR companion assets/client.js po stronie klienta w innym znaczniku skryptu.

Jeśli zażądasz czystej wersji klienta, umieszcza ona tylko assets/bundle.js wewnątrz znacznika skryptu.

Strona klienta

Strona klienta jest całkiem prosta.

src/bundle.js

Tak właśnie piszesz opakowanie React i Redux Provider. To jest nasza czysta aplikacja po stronie klienta. Nie ma tu żadnych sztuczek.

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( <Provider store={store} > <App /> </Provider>, document.querySelector('#app'));

src/client.js

Wygląda znajomo? Tak, nie ma tu nic specjalnego oprócz window.__STATE__.Wszystko, co musimy zrobić, to pobrać stan początkowy z window.__STATE__ i przekazać go do naszej funkcji configureStore() jako stan początkowy.

Przyjrzyjrzyjmy się naszemu nowemu plikowi klienta:

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( <Provider store={store} > <App /> </Provider>, document.querySelector('#app'));

Przejrzyjmy zmiany:

  1. Zastąp render() przez hydrate(). hydrate() jest taki sam jak render(), ale jest używany do uwodnienia elementów renderowanych przez ReactDOMServer. Zapewnia to, że zawartość jest taka sama na serwerze i na kliencie.
  2. Odczytaj stan z globalnego obiektu okna window.__STATE__. Przechowaj go w zmiennej i usuń window.__STATE__.
  3. Utwórz świeży sklep z state jako initialState.

Wszystko zrobione tutaj.

Układanie tego wszystkiego razem

Index.js

To jest punkt wejścia naszej aplikacji. Obsługuje żądania i szablonowanie.

Deklaruje również zmienną initialState. Wymodelowałem ją za pomocą danych w pliku assets/data.json . Przekażemy ją do naszej funkcji ssr().

Uwaga: Podczas odwoływania się do pliku, który jest wewnątrz src/ z pliku poza src/ , użyj normalnego require() i zastąp src/ przez views/. Znasz powód (kompilacja Babel).

Routing

  1. /: Domyślnie strona główna renderowana przez serwer.
  2. /client: Przykład czystego renderowania po stronie klienta.
  3. /exit: Przycisk zatrzymania serwera. Dostępny tylko w wersji rozwojowej.

Build & Run

Czas zbudować i uruchomić naszą aplikację. Możemy to zrobić za pomocą jednej linii kodu.

npm run build && npm run start

Teraz aplikacja jest uruchomiona na http://localhost:3000.

Ready to become a React Pro?

Od najbliższego poniedziałku rozpoczynam nową serię, dzięki której Twoje umiejętności w zakresie React będą płonąć, natychmiast.

link do subskrypcji poniżej ?

Dziękuję za przeczytanie tego.

Jeśli Ci się to podoba i uważasz to za przydatne, śledź mnie na Twitterze & Webflow.

.

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany.