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?
- Cons of Rendering React on the Server
- Kiedy powinieneś używać Server Side Rendering?
- SEO
- Popraw wydajność
- React Rendered on Server
- React Rendered on Client’s Browser
- Jak to działa? – (4 proste kroki)
- Rozpoczęcie pracy poprzez skonfigurowanie naszej aplikacji
- Dlaczego musimy kompilować pliki źródłowe?
- Kopiowanie prekodowanych & plików statycznych
- Server Side
- src/server.js
- 2. src/template.js
- Strona klienta
- src/bundle.js
- src/client.js
- Układanie tego wszystkiego razem
- Index.js
- Build & Run
- Ready to become a React Pro?
- Dziękuję za przeczytanie tego.
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:
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
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
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:
-
assets/bundle.js
– czysta aplikacja po stronie klienta. -
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ą.
- React
App
i komponenty rezydują wsrc/components
. - Pliki Redux w
src/redux/
. -
assets/ & media/
: Zawierają pliki statyczne, takie jakstyle.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.
- Przekaż
initialState
doconfigureStore()
.configureStore()
zwróci nową instancję Store. Trzymaj ją wewnątrz zmiennejstore
. - Wywołaj metodę
renderToString()
, podając naszą aplikację jako dane wejściowe. Renderuje ona naszą aplikację na serwerze i zwraca wyprodukowany HTML. Teraz zmiennacontent
przechowuje HTML. - Wyciągnij stan z Redux Store, wywołując
getState()
nastore
. Przechowuj go w zmiennejpreloadedState
. - Zwróć
content
ipreloadedState
. 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 <scri
pt>.
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:
- Zastąp
render()
przezhydrate()
.hydrate()
jest taki sam jakrender()
, ale jest używany do uwodnienia elementów renderowanych przezReactDOMServer
. Zapewnia to, że zawartość jest taka sama na serwerze i na kliencie. - Odczytaj stan z globalnego obiektu okna
window.__STATE__
. Przechowaj go w zmiennej i usuńwindow.__STATE__
. - 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
-
/
: Domyślnie strona główna renderowana przez serwer. -
/client
: Przykład czystego renderowania po stronie klienta. -
/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.
Dziękuję za przeczytanie tego.
Jeśli Ci się to podoba i uważasz to za przydatne, śledź mnie na Twitterze & Webflow.
.