av Rohit Kumar
Det här är vad vi kommer att bygga i den här handledningen: ett snyggt React-kort som det här.
I den här handledningen använder vi server-side rendering för att leverera ett HTML-svar när en användare eller en crawler klickar på en webbadress. Vi hanterar de senare förfrågningarna på klientsidan.
Varför behöver vi det?
Låt mig guida dig till svaret.
- Vad är skillnaden mellan rendering på klientsidan och rendering på serversidan?
- Konsekvenser av att rendera React på servern
- När ska du använda Server Side Rendering?
- SEO
- Förbättra prestanda
- React Rendered on Server
- React Rendered on Client’s Browser
- Hur fungerar det? – (4 enkla steg)
- Kom igång genom att konfigurera vår app
- Varför behöver vi kompilera källfilerna?
- Kopiera förkodade & statiska filer
- Server Side
- src/server.js
- 2. src/template.js
- Klientsidan
- src/bundle.js
- src/client.js
- Sätt ihop allt
- Index.js
- Bygg & Kör
- Preparat att bli en React Pro?
- Tack för att du läste detta.
Vad är skillnaden mellan rendering på klientsidan och rendering på serversidan?
I rendering på klientsidan laddar din webbläsare ner en minimal HTML-sida. Den render JavaScript och fyller innehållet i den.
Server-side rendering å andra sidan render React-komponenterna på servern. Utgången är HTML-innehåll.
Du kan kombinera dessa två för att skapa en isomorf app.
Konsekvenser av att rendera React på servern
- SSR kan förbättra prestandan om din applikation är liten. Men det kan också försämra prestandan om den är tung.
- Det ökar svarstiden (och det kan bli värre om servern är upptagen).
- Det ökar svarsstorleken, vilket innebär att sidan tar längre tid att ladda.
- Det ökar applikationens komplexitet.
När ska du använda Server Side Rendering?
Trots dessa konsekvenser av SSR finns det vissa situationer där du kan och bör använda det.
SEO
Alla webbplatser vill synas i sökningar. Rätta mig om jag har fel.
Tyvärr förstår/renderar sökmotorernas crawlers ännu inte JavaScript.
Detta innebär att de ser en tom sida, oavsett hur hjälpsam din webbplats är.
Många säger att Googles crawler nu renderar JavaScript.
För att testa detta distribuerade jag appen på Heroku. Här är vad jag såg i Google Search Console:
En tom sida.
Det här var den största anledningen till att jag utforskade server-side rendering. Särskilt när det är en hörnstenssida som en landningssida, blogg och så vidare.
För att verifiera om Google renderar din webbplats, besök:
Search Console Dashboard > Crawl > Fetch as Google. Ange sidans URL eller låt den vara tom för hemsidan.
Välj FETCH AND RENDER. När du är klar klickar du på för att se resultatet.
Förbättra prestanda
I SSR beror applikationens prestanda på serverns resurser och användarens nätverkshastighet. Detta gör den mycket användbar för innehållstunga webbplatser.
Till exempel: Säg att du har en mobiltelefon till medelpris med långsam internethastighet. Du försöker komma åt en webbplats som laddar ner 4 MB data innan du kan se något.
Skulle du kunna se något på skärmen inom 2-4 sekunder?
Skulle du besöka den webbplatsen igen?
Jag tror inte att du skulle göra det.
En annan stor förbättring är den första användarinteraktionstiden. Detta är skillnaden i tid från det att en användare trycker på URL:n till dess att de ser innehållet.
Här är jämförelsen. Jag testade den på en utvecklings-Mac.
React Rendered on Server
Den första interaktionstiden är 300ms. Hydrate avslutas efter 400 ms. Lastningshändelsen avslutas vid 500 ms ungefär. Du kan se detta genom att titta på bilden ovan.
React Rendered on Client’s Browser
Den första interaktionstiden är 400ms. Laddningshändelsen avslutas vid 470 ms.
Resultatet talar för sig självt. Det är en skillnad på 100 ms i första användarinteraktionstiden för en så liten app.
Hur fungerar det? – (4 enkla steg)
- Skapa en ny Redux Store vid varje begäran.
- Optionellt skicka några åtgärder.
- Hämta tillståndet från Store och utför SSR.
- Sänd det tillstånd som erhållits i föregående steg tillsammans med svaret.
Vi kommer att använda tillståndet som skickas i svaret för att skapa det initiala tillståndet på klientsidan.
Innan du börjar, klona/downloadar du det kompletta exemplet från Github och använder det som referens.
Kom igång genom att konfigurera vår app
Först öppnar du din favoritredigerare och shell. Skapa en ny mapp för din applikation. Låt oss börja.
npm init --yes
Fyller ut detaljerna. När package.json
har skapats kopierar du nedanstående beroenden och skript till den.
Installera alla beroenden genom att köra:
npm install
Du måste konfigurera Babel och webpack för att vårt byggskript ska fungera.
Babel omvandlar ESM och react till Node- och webbläsarförståelig kod.
Skapa en ny fil .babelrc
och lägg in raden nedan i den.
{ "presets": }
webpack paketerar vår app och dess beroenden i en enda fil. Skapa en annan fil webpack.config.js
med följande kod i den:
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: }}
Byggprocessen ger ut två filer:
-
assets/bundle.js
– ren app på klientsidan. -
assets/client.js
– kompanjon på klientsidan för SSR.
Mappen src/
innehåller källkoden. De Babel-kompilerade filerna hamnar i views/
. views
-katalogen skapas automatiskt om den inte finns.
Varför behöver vi kompilera källfilerna?
Anledningen är syntaxskillnaden mellan ESM & CommonJS. När vi skriver React och Redux använder vi import och export flitigt i alla filer.
Tyvärr fungerar de inte i Node. Här kommer Babel till undsättning. Skriptet nedan säger till Babel att kompilera alla filer i katalogen src
och lägga resultatet i views.
"babel": "babel src -d views",
Nu kan Node köra dem.
Kopiera förkodade & statiska filer
Om du redan har klonat förrådet, kopiera från det. Annars laddar du ner ssr-static.zip-filen från Dropbox. Extrahera den och förvara dessa tre mappar i din app-katalog. Här är vad de innehåller.
- React
App
och komponenter finns isrc/components
. - Redux-filer i
src/redux/
. -
assets/ & media/
: Innehåller statiska filer somstyle.css
och bilder.
Server Side
Skapa två nya filer som heter server.js
och template.js
i mappen src/
.
src/server.js
Trollet sker här. Detta är koden du har letat efter.
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 };};
Istället för att rendera vår app måste vi packa in den i en funktion och exportera den. Funktionen accepterar applikationens initialtillstånd.
Här är hur det fungerar.
- Pass
initialState
tillconfigureStore()
.configureStore()
återger en ny Store-instans. Håll den inne i variabelnstore
. - Anropa metoden
renderToString()
och ge vår App som indata. Den renderar vår app på servern och returnerar den HTML som produceras. Nu lagrar variabelncontent
HTML:n. - Hämta tillståndet från Redux Store genom att anropa
getState()
påstore
. Behåll det i en variabelpreloadedState
. - Returnerar
content
ochpreloadedState
. Vi skickar dessa till vår mall för att få den slutliga HTML-sidan.
2. src/template.js
template.js
exporterar en funktion. Den tar title
, state
och content
som indata. Den injicerar dem i mallen och returnerar det slutliga HTML-dokumentet.
För att överföra tillståndet fäster mallen state
till window.__STATE__
inuti en <scri
pt>-tagg.
Nu kan du läsa state
på klientsidan genom att få åtkomst till window.__STATE__
.
Vi inkluderar också klientsidan för SSR-kamraten assets/client.js
i en annan skripttagg.
Om du begär den rena klientversionen lägger den bara assets/bundle.js
i skripttaggen.
Klientsidan
Klientsidan är ganska okomplicerad.
src/bundle.js
Det är så här du skriver React- och Redux Provider
-omslaget. Det är vår renodlade app på klientsidan. Inga trick här.
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
Låter bekant? Ja, det finns inget speciellt förutom window.__STATE__.
Allt vi behöver göra är att hämta det initiala tillståndet från window.__STATE__
och skicka det till vår configureStore()
-funktion som det initiala tillståndet.
Vi tar en titt på vår nya klientfil:
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'));
Vi går igenom ändringarna:
- Ersätt
render()
medhydrate()
.hydrate()
är samma sak somrender()
men används för att hydrera element som återges avReactDOMServer
. Det säkerställer att innehållet är detsamma på servern och klienten. - Läs statusen från det globala fönsterobjektet
window.__STATE__
. Lagra det i en variabel och ta bortwindow.__STATE__
. - Skapa ett nytt lager med
state
som initialState.
Allt är klart här.
Sätt ihop allt
Index.js
Det här är ingångspunkten för vårt program. Den hanterar förfrågningar och templating.
Den deklarerar också en initialState
variabel. Jag har modellerat den med data i assets/data.json
filen. Vi kommer att skicka den till vår ssr()
-funktion.
Notera: När du hänvisar till en fil som är inne i src/
från en fil utanför src/
, använd normal require()
och ersätt src/
med views/
. Du vet varför (Babel-kompilering).
Routing
-
/
: Som standard serverrenderad hemsida. -
/client
: -
/exit
: Knapp för serverstopp. Endast tillgänglig i utveckling.
Bygg & Kör
Det är dags att bygga och köra vårt program. Vi kan göra detta med en enda kodrad.
npm run build && npm run start
Nu körs applikationen på http://localhost:3000.
Preparat att bli en React Pro?
Jag startar en ny serie från och med nästa måndag för att få dina React-kunskaper att brinna, omedelbart.
Tack för att du läste detta.
Om du gillar det och finner det användbart, följ mig på Twitter & Webflow.