Det bedste fra begge verdener: SSR med isomorf JavaScript

server-side rendering, eller SSR, er en sætning, som du ofte hører i frontend udvikling samfund.

på det mest basale niveau er server-side rendering præcis, hvad den beskriver: rendering applikationer på serveren. Du navigerer til en hjemmeside, det gør en anmodning til serveren, det gør nogle HTML, og du får den fuldt gengivet resultat tilbage i din bro.ser. Ret ligetil. Du kan spørge dig selv, hvorfor samfundet selv har et modeord for dette.

før fremkomsten af rige og dynamiske internetapplikationer, der var stærkt afhængige af JavaScript og jforespørgsel, blev stort set alle internetapplikationer servergengivet. PHP, ordtryk og endda bare grundlæggende HTML-sider er eksempler på dette.

når du besøger en side på en af disse sider, får du alle HTML — data og alle tilbage. Hvis du klikker på et link, sender bro.sereren en anden anmodning til serveren. Efter svaret opdateres og gengives den næste side fra bunden. Denne tilgang fungerer godt, og det har i årevis; brugerne er utroligt hurtige til at gengive statisk HTML. Hvad har ændret sig?

siden århundredskiftet er JavaScript-brugen gået fra et lille drys her og der for interaktivitet på hjemmesiden til det ubestridte sprog, du vælger på nettet. Vi sender hele tiden mere logik og JavaScript til serveren.

single-page rammer som React og Vue har indvarslet denne nye æra af dynamiske, komplekse, datadrevne klient-renderet internet applikationer. Disse kurbade adskiller sig fra servergengivne applikationer, fordi de ikke henter fuldt gengivet indhold komplet med data fra serveren, før de gengives på skærmen.

klientside-gengivne applikationer gengiver deres indhold i bro.ser ved hjælp af JavaScript. I stedet for at hente alt indhold fra serveren, henter de simpelthen en barebones HTML-side uden kropsindhold og gengiver alt indhold inde ved hjælp af JavaScript.

fordelen ved dette er, at du undgår de fulde sideopdateringer, der sker med fuldt servergengivne applikationer, hvilket kan være lidt skurrende for brugeren. Enkeltsidede klient-gengivne apps opdaterer indhold på din skærm, henter data fra API ‘ er og opdaterer lige foran dig uden nogen form for sideopdatering overhovedet. Denne egenskab er det, der får moderne internetapplikationer til at føle sig snappy og “indfødte”, når du interagerer med dem.

klient-side rendering trade-offs

det er ikke alle solskin og regnbuer i klient-side-afsmeltet SPA verden. Der er nogle afvejninger, der kommer med at gøre din ansøgning på klientsiden. To primære eksempler er SEO og initial load performance.

SEO

da klientgengivne apps returnerer en HTML-side med meget lidt indhold, før JavaScript sparker ind og gengiver resten, kan det være svært for søgemaskinerne at forstå HTML-strukturen på din side, hvilket er skadeligt for din sides søgerangering. Google har gjort en masse godt arbejde omkring dette, men det anbefales stadig at undgå rendering på klientsiden, hvis SEO er særlig vigtig.

Initial load performance

med klientgengivne apps ser du generelt følgende ting ske, når du først åbner siden:

  • appen indlæser nogle grundlæggende HTML, som en appskal eller statisk navbar
  • du ser en indlæsningsindikator af en slags
  • dit indhold gengives derefter

problemet med dette er, at din applikation ikke viser noget, før JavaScript indlæses helt fra netværket og er færdig med at gengive elementer på din skærm.

i en nøddeskal er problemet med klientsiden generelt, at du ikke kan kontrollere, hvilken klientenhed nogen bruger din applikation på-hvad enten det er deres avancerede smartphone, kraftfulde high — end desktop maskine eller $100 lavere smartphone.

vi kontrollerer dog serveren. Vi kan næsten altid give vores server mere CPU og hukommelse og justere den for at få den til at fungere bedre for vores brugere.

det bedste fra begge verdener

vi kan få det bedste fra begge verdener, når vi bruger server-side rendering med moderne frontend teknologier. Den måde, dette generelt fungerer på, er, at serveren gengiver og sender den fuldt gengivne applikation tilbage ved første belastning. Det næste skridt, kendt som hydrering, er, hvor din JavaScript bundle vil blive hentet og udført. Dette lægger event handlere og ledninger ting op som din klient-side router.

med denne tilgang får du alle fordelene ved SSR på den indledende belastning, så vil hver interaktion fra det tidspunkt fremad blive håndteret af klientsiden JavaScript. Dette giver en hurtig, SEO-venlig startbelastning efterfulgt af den dynamiske enkeltsidede app-oplevelse, som vi kender og elsker.

applikationer som dette er kendt som universelle applikationer, fordi det samme JavaScript kører på klienten og serveren. Du kan også høre det mere avancerede udtryk “isomorf”, der bruges, hvilket betyder nøjagtigt det samme.

Tutorial: implementering SSR

SSR er ikke uden sine afvejninger, enten. Det tilføjer overhead til din udvikling ved at indføre en mere kompleks konfiguration samt at skulle være vært og administrere din egen server. Disse problemer er grunden til utrolige rammer som næste.js og rase er meget populære: de abstraherer SSR-konfigurationsdelen væk og lader dig fokusere på at skrive UI-kode.

i denne tutorial vil vi ikke bruge nogen SSR-rammer. Den bedste måde at lære, hvordan noget fungerer, er ved faktisk at opbygge det, så vi vil lære at oprette den enkleste SSR-opsætning, vi muligvis kan, der vil give:

  • global CDN
  • fuldt funktionel backend API
  • ingen servere eller infrastruktur til at styre
  • single-command deployment

vi vil implementere en universal server-renderet React-applikation oprettet med create-react-app på . Du behøver ikke at have erfaring med AV for at følge med.

vores værktøjer

for at opbygge vores applikation skal vi gøre brug af et par forskellige tjenester.

  • AV forstærker: En ramme på højt niveau til styring af AV-tjenester, hovedsageligt til mobil-og internetudvikling
  • av Lambda: Kør kode i skyen uden at administrere servere
  • av Cloudfront (CDN): et indholdsleveringsnetværk, der er ansvarligt for levering og caching af indhold over hele verden
  • av simpel lagringstjeneste (S3): hvor vi gemmer vores statiske aktiver (JS, CSS osv.)

arkitektur diagram

vores Lambda funktion er ansvarlig for server-rendering vores React ansøgning. Vi bruger S3 til at gemme vores statiske indhold og CloudFront CDN til at servere det. Du behøver ikke at have nogen forudgående kendskab til disse tjenester, da vi gør det super nemt for os at oprette dem.

 vores arkitektur Diagram

vores Arkitekturdiagram

opbygning af vores applikation

først og fremmest skal du installere AV-forstærkeren CLI og oprette en av-konto, hvis du ikke allerede har en. Det kan du gøre ved at følge denne korte vejledning.

projektopsætning

nu hvor Amplify er konfigureret, kan vi begynde at konfigurere vores React-projekt. Vi vil bruge den fantastiske create-react-app til at hjælpe os. Forudsat at du har Node.JS og npm installeret, Vi kan køre:

npx create-react-app amplify-ssrcd amplify-ssr yarn add aws-amplify amplify init

Vælg standardindstillingerne i guiden forstærker.

vores React-projekt er nu bootstrapped med Amplify og klar til at tilføje vores “server” til SSR. Vi gør dette ved at køre amplify add api og besvare nogle spørgsmål:

$ amplify add api? Please select from one of the below mentioned services: REST? Provide a friendly name for your resource to be used as a label for this category in the project: amplifyssr? Provide a path (e.g., /items): /ssr? Choose a Lambda source: Create a new Lambda function? Provide a friendly name for your resource to be used as a label for this category in the project: amplifyssr? Provide the AWS Lambda function name: ssr? Choose the function runtime that you want to use: NodeJS? Choose the function template that you want to use: Serverless expressJS function? Do you want to access other resources created in this project from your Lambda function? N? Do you want to edit the local lambda function now? N? Restrict API access: N? Do you want to add another path? N

dette vil skabe de relevante skabeloner, mapper og kode, der er nødvendige for vores av-infrastruktur og backend: en av Lambda-funktion, der kører en lille Ekspresserver, der er ansvarlig for at gengive vores React-applikation.

før vi implementerer vores infrastruktur, er der nogle ændringer, vi skal foretage i Vores React-applikation for at forberede den til gengivelse på serversiden. Åbn src/App.js (den vigtigste app-komponent til din React-applikation) og indsæt i følgende:

import React from 'react';function App() { return ( <div className="App"> <header className="App-header"> Server Rendered React App </header> </div> );}export default App;

Dernæst skal vi oprette et script, der vil gøre vores React-applikation på serversiden. Dette gøres med funktionen renderToString i pakken react-dom/server. Denne funktion er ansvarlig for at tage vores <App /> komponent og gøre den på serversiden som en streng, klar til at blive returneret som fuldt gengivet HTML til klienten.

Opret en fil på src/render.js med følgende kode:

import React from "react";import { renderToString } from "react-dom/server";import App from "./App";export default () => renderToString(<App />);

Great – vores klient-side React app har al den kode, den skal gengives på serversiden. Det betyder, at vi nu skal kode op server-side endepunkt, der vil gøre vores React ansøgning.

vi har dog et problem — vi har brug for src/render – funktionen og vores <App /> komponentkode, der skal køres på serversiden. Serveren ved som standard ikke noget om React eller endda ES-moduler. Af denne grund vil vi transpilere koden fra React-applikationen ved hjælp af Babel til serversiden.

for at gøre dette, lad os installere et par Babel-afhængigheder i vores projekt.

yarn add --dev @babel/core @babel/cli @babel/preset-react @babel/preset-env

opret derefter en .babelrc ved roden af dit projekt. Denne fil bruges til at konfigurere Babel og fortælle den, hvilke plugins/forudindstillinger der skal bruges.

{ "presets":}

lad os endelig opdatere vores package.json for at transpilere vores kode som en del af byggetrinnet. Dette transpilerer filerne i amplify/backend/function/amplifyssr/src/client – mappen, hvor vi gemmer alt det universelle JavaScript, der skal køres på klientsiden såvel som serveren til SSR.

 "scripts": { "start": "react-scripts start", "transpile": "babel src --out-dir amplify/backend/function/amplifyssr/src/client --copy-files", "build": "npm run transpile && react-scripts build && npm run copy", "copy": "cp build/index.html amplify/backend/function/amplifyssr/src/client", "test": "react-scripts test", "eject": "react-scripts eject" },

Rendering app i Lambda

build konfiguration er færdig! Lad os hoppe ind i amplify/backend/function/amplifyssr/src og installere react og react-dom, da de begge er nødvendige for, at Lambda kan udføre SSR.

yarn add react react-dom

nu for at konfigurere vores Ekspresserver, som kører på Lambda. Lambda-funktionen blev automatisk genereret for os, da vi afsluttede amplify add api trin tidligere og valgte en REST og ExpressJS API.

Amplify har allerede konfigureret Ekspresserveren til at køre på Lambda, så alt hvad vi skal gøre nu er at tilføje et slutpunkt til serveren-gør vores React-applikation, når nogen rammer API-URL ‘ en i Bro.sereren. Opdater din amplify/backend/function/amplifyssr/src/app.js fil, så den indeholder følgende kode:

/* Amplify Params - DO NOT EDIT ENV REGIONAmplify Params - DO NOT EDIT */const express = require('express')const bodyParser = require('body-parser')const awsServerlessExpressMiddleware = require('aws-serverless-express/middleware')const fs = require('fs');const render = require('./client/render').default;// declare a new express appconst app = express()app.use(bodyParser.json())app.use(awsServerlessExpressMiddleware.eventContext())// Enable CORS for all methodsapp.use(function(req, res, next) { res.header("Access-Control-Allow-Origin", "*") res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept") next()});app.get('*', function(req, res) { // Read the index.html file from the create-react-app build const html = fs.readFileSync("./client/index.html", "utf-8"); // Server side render the react application const markup = render(); // Replace the empty body of index.html with the fully server rendered react application and send it back to the client res.send(html.replace(`<div></div>`, `<div>${markup}</div>`))});module.exports = app

vores Ekspresserver er nu SSR-klar, og vi kan implementere vores React-applikation.

Hosting og sidste hånd

når vi først har modtaget den server-gengivne HTML tilbage fra vores apps oprindelige gengivelse, henter vi derefter JavaScript-bundtet på klientsiden for at overtage derfra og give os et fuldt interaktivt SPA.

vi har brug for et sted at være vært for vores JavaScript og statiske filer på klientsiden. Den service, der generelt bruges til dette, er S3 (Simple Storage Service), en massivt skalerbar skyobjektbutik.

vi vil også sætte en CDN foran den til global caching og ydeevne. Med Amplify kan vi oprette begge disse ressourcer til vores projekt ved at køre et par kommandoer fra vores project root directory:

$ amplify add hostingSelect the plugin module to execute Amazon CloudFront and S3? Select the environment setup: PROD (S3 with CloudFront using HTTPS)? hosting bucket name (name your bucket or use the default)

du kan nu installere hele din infrastruktur, inklusive din Ekspresserver Lambda-funktion, S3 bucket og CDN, ved at køre kommandoen amplify publish.

din konsoloutput viser alle de relevante ressourcer fra dine skabeloner, der oprettes til dig af Amplify. Bemærk, at det kan tage et stykke tid at oprette en CloudFront CDN, så vær tålmodig. Når dine ressourcer er oprettet, vises din CloudFront CDN-URL i terminalen.

Publish started for S3AndCloudFront✔ Uploaded files successfully.Your app is published successfully.https://d3gdcgc9a6lz30.cloudfront.net

det sidste, vi skal gøre, er at fortælle React, hvorfra vi skal hente vores klientside-pakke, efter at appen er gengivet af serveren. Dette gøres i create-react-app ved hjælp af miljøvariablen PUBLIC_URL. Lad os opdatere vores React app package.json scripts igen for at se ud som følgende:

 "scripts": { "start": "react-scripts start", "transpile": "babel src --out-dir amplify/backend/function/amplifyssr/src/client --copy-files", "build": "npm run transpile && PUBLIC_URL=<your-cloudfront-url> react-scripts build && npm run copy", "copy": "cp build/index.html amplify/backend/function/amplifyssr/src/client", "test": "react-scripts test", "eject": "react-scripts eject" },

Genopbyg og implementer din applikation med denne opdaterede konfiguration.

amplify publish

vi skal nu have en fuldt server-side-renderet React app kører på Av!

kører vores app

din SSR API URL kan findes på amplify/backend/amplify-meta.json. Se efter RootUrl i din JSON-fil, og du skal se den URL, hvor du kan besøge din nye servergengivne applikation. Det skal se ud som følgende:

"output": { "ApiName": "amplifyssr", "RootUrl": "https://g6nfj3bvsg.execute-api.eu-west-1.amazonaws.com/dev", "ApiId": "g6nfj3bvsg"}, 

besøg API-porten URL i din bro. ser på <your-api-url>/ssr og du bør se din skinnende nye server-renderet React ansøgning! Hvis du dykker ned i fanen Netværk i din valgte bro.ser og ser anmodningerne, vil du bemærke, at anmodningen til /ssr har et fuldt gengivet HTML-svar med vores React-applikation gengivet inde i <body> i dokumentet.

<div> <div class="App" data-reactroot=""> <header class="App-header">Server Rendered React App</header> </div></div>

du vil også bemærke anmodningerne, der fremsættes til din Cloudfront URL fra bro.ser for at indlæse klientsiden JavaScript, der overtager gengivelsen herfra, hvilket giver os det bedste fra både klientsiden og serversiden rendering verdener.

hvor skal vi hen herfra

denne tutorial er beregnet til at få dig i gang med gengivelse på serversiden så hurtigt som muligt uden at bekymre dig om styring af infrastruktur, CDN ‘ er og mere. Efter at have brugt den serverløse tilgang, der er et par gode forbedringer, vi kan gøre til vores opsætning.

klargjort samtidighed

en måde, hvorpå Lambda er i stand til at forblive ekstremt billig, er, at Lambda-funktioner, der ikke er blevet ramt i et stykke tid, vil gå “inaktiv.”Dette betyder i det væsentlige, at når vi udfører dem igen, vil der være det, der er kendt som en “koldstart” — en initialiseringsforsinkelse, der skal ske, før Lambda reagerer.

efter dette er lambda derefter “varm” igen i en periode og vil svare på efterfølgende anmodninger hurtigt indtil den næste lange tomgangsperiode. Dette kan forårsage lidt upålidelige responstider.

til trods for at være “serverløs” bruger Lambda lette containere til at behandle eventuelle anmodninger. Hver container kan kun behandle en anmodning til enhver tid. Ud over koldstartproblemet efter en inaktiv periode gælder det samme også, når mange samtidige anmodninger rammer den samme Lambda-funktion, hvilket får flere samtidige containere eller arbejdere til at blive koldstartet, før de reagerer.

tidligere har mange ingeniører løst dette problem ved at skrive scripts for at pinge Lambda med jævne mellemrum for at holde det varmt. Der er nu en meget bedre måde at løse dette på, og det er kendt som klargjort samtidighed.

med klargjort samtidighed kan du meget nemt anmode om et givet antal dedikerede containere for at holde varmen til en bestemt Lambda-funktion. Dette giver dig en meget mere konsistent SSR-responstid i tider med høj og sporadisk belastning.

Lambda-versioner

du kan oprette flere Lambda-versioner til dine funktioner og opdele trafikken mellem dem. Dette er meget kraftfuldt i vores SSR-applikation, da det giver os mulighed for at foretage opdateringer på Lambda-siden og A/B teste dem med en mindre del af brugerne.

du kan udgive flere versioner af din Lambda og opdele trafikken mellem dem i vægte, som du angiver. Det kan f.eks. være en god ide at servere et CTA-banner, så nogle brugere kan måle engagement, men ikke gengive det for andre. Du kan gøre dette med Lambda versioner.

Full-stack applikation

som forklaret tidligere opretter vi allerede en REST API og en Ekspresserver til os, hvor vi har oprettet et slutpunkt til server-render vores React-applikation. Vi kan altid tilføje mere kode og slutpunkter til denne Ekspresserver på amplify/backend/function/amplifyssr/src/app.js, så vi kan gøre vores app til en full-stack-applikation, komplet med database, godkendelse og mere.

du kan gøre brug af den fantastiske pakke med Forstærkningsværktøjer til at oprette disse ressourcer eller tilslutte til din egen infrastruktur — selvom den ikke er hostet på . Du kan behandle din Lambda backend som enhver anden Ekspresserver og bygge oven på den.

du har allerede hele din installationspipeline oprettet ved at køre amplify publish, så du kan fokusere på at skrive kode. Udgangspunktet i denne tutorial giver dig total fleksibilitet til at gøre, hvad du vil herfra.

konklusion

server-side rendering behøver ikke at være svært. Vi kan bruge fuldt administrerede værktøjer som næste eller rase, som er fantastiske i sig selv, men for mange hold kan dette være alt for stort et paradigmeskift i betragtning af deres eksisterende kode eller krav. Brug af en enkel, lav vedligeholdelse, brugerdefineret tilgang kan gøre livet lettere, især hvis du allerede bruger AV eller forstærker til dit projekt.

SSR kan tilføje et ton af værdi til dine internetapplikationer og give en tiltrængt ydeevne eller SEO boost. Vi er heldige i internetudviklingssamfundet at have værktøjer, der kan oprette CDN ‘ er, serverløse backends og fuldt hostede internetapplikationer med et par kommandoer eller klik.

selvom du ikke tror, du har brug for SSR, er det et meget udbredt og almindeligt emne i JavaScript-økosystemet. At have en forståelse af dens fordele og afvejninger vil være praktisk for næsten alle, der er involveret i internetudviklingssfæren.

jeg håber du lærte noget i dag-tak for læsning! Du er velkommen til at kontakte mig eller følge mig på kvidre, hvor jeg kvidrer og blogger om JavaScript, Python, automatisering og No-code udvikling.

fuld synlighed i produktion React apps

Debugging React applikationer kan være svært, især når brugerne oplever problemer, der er vanskelige at reproducere. Hvis du er interesseret i overvågning og sporing af JavaScript-tilstand, automatisk overfladebehandling af JavaScript-fejl og sporing af langsomme netværksanmodninger og komponentbelastningstid, kan du prøve LogRocket. LogRocket Dashboard gratis Prøvebanner

LogRocket er som en DVR til internetapps, der optager bogstaveligt talt alt, hvad der sker på din React-app. I stedet for at gætte, hvorfor der opstår problemer, kan du samle og rapportere om, hvilken tilstand din ansøgning var i, da der opstod et problem. LogRocket overvåger også din apps ydeevne, rapportering med målinger som klient CPU-belastning, brug af klienthukommelse og mere.

pakken med mellemvare tilføjer et ekstra lag af synlighed til dine brugersessioner. LogRocket logger alle handlinger og tilstand fra dine butikker.

moderniser, hvordan du debugger dine React — apps-start Overvågning Gratis.

Skriv et svar

Din e-mailadresse vil ikke blive publiceret.