Het beste van beide werelden: SSR met isomorf JavaScript

Server-side rendering, of SSR, is een zin die je vaak hoort in de frontend development community.

op het meest basale niveau is het renderen aan de serverzijde precies wat het beschrijft: renderen van toepassingen op de server. Je navigeert naar een website, het doet een verzoek aan de server, het maakt wat HTML, en je krijgt het volledig gerenderde resultaat terug in je browser. Vrij eenvoudig. Je vraagt je misschien af waarom de gemeenschap hier zelfs een modewoord voor heeft.

voor de opkomst van rijke en dynamische webapplicaties die sterk afhankelijk waren van JavaScript en jQuery, waren in wezen alle webapplicaties Server-gerenderd. PHP, WordPress, en zelfs gewoon basic HTML-sites zijn voorbeelden hiervan.

wanneer u een pagina op een van deze sites bezoekt, krijgt u alle HTML — gegevens terug. Als u op een link klikt, zal de browser een ander verzoek indienen bij de server. Na het antwoord, de browser zal vernieuwen en renderen van de volgende pagina van de grond af. Deze aanpak werkt goed, en het is al jaren; browsers zijn spectaculair snel in het renderen van statische HTML. Wat is er veranderd?

sinds het begin van de eeuw is het gebruik van JavaScript van een beetje hier en daar voor webpagina-interactiviteit veranderd in de onbetwiste taal van keuze op het web. We verzenden voortdurend meer logica en JavaScript naar de browser.

single-page frameworks zoals React en Hog hebben dit nieuwe tijdperk ingeluid van dynamische, complexe, data-gedreven client-gerenderde webapplicaties. Deze spa ‘ s verschillen van server-gerenderde applicaties omdat ze niet volledig gerenderde inhoud compleet met gegevens van de server ophalen voordat ze op het scherm worden weergegeven.

client-side gerenderde toepassingen maken hun inhoud in de browser met behulp van JavaScript. In plaats van het ophalen van alle inhoud van de server, ze gewoon halen een barebones HTML-pagina zonder body content en renderen alle inhoud binnen met behulp van JavaScript.

het voordeel hiervan is dat u de volledige pagina-verversingen vermijdt die gebeuren met volledig door de server gerenderde applicaties, wat een beetje schokkend kan zijn voor de gebruiker. Single-page client-gerenderde apps zal de inhoud op uw scherm bij te werken, halen gegevens uit API ‘ s, en bij te werken recht voor je zonder enige vorm van pagina te vernieuwen dan ook. Dit kenmerk is wat maakt moderne webapplicaties voelen snappy en” native ” als je interactie met hen.

client-side rendering trade-offs

It ‘ s not all sunshine and rainbows in the client-side rendering Spa world. Er zijn een aantal trade-offs die komen met het renderen van uw toepassing aan de kant van de klant. Twee primaire voorbeelden zijn SEO en initiële load prestaties.

SEO

aangezien client-gerenderde apps een kale HTML-pagina met zeer weinig inhoud retourneren voordat JavaScript begint en de rest weergeeft, kan het moeilijk zijn voor zoekmachines om de HTML-structuur van uw pagina te begrijpen, wat schadelijk is voor de zoekresultaten van uw site. Google heeft veel goed werk gedaan rond deze, maar het is nog steeds aan te raden om client-side rendering te voorkomen als SEO is bijzonder belangrijk.

initiële laadprestaties

met client-gerenderde apps ziet u over het algemeen de volgende dingen gebeuren wanneer u de pagina voor het eerst opent:

  • de app laadt wat basis HTML, zoals een app shell of statische navbar
  • u ziet een laadindicator van een soort
  • uw inhoud wordt dan gerenderd

het probleem met dit is dat uw applicatie niets zal tonen totdat het JavaScript volledig van het netwerk laadt en klaar is met het renderen van elementen op uw scherm.

In een notendop, het probleem met client-side prestaties in het algemeen is dat je niet kunt controleren op welk client — apparaat iemand gebruikt uw toepassing op-of het nu hun state-of-the-art smartphone, krachtige high-end desktop machine, of $100 lagere-end smartphone.

wij beheren echter wel de server. We kunnen bijna altijd geven onze server meer CPU en geheugen en tweak het om het beter te laten presteren voor onze gebruikers.

het beste van beide werelden

we kunnen het beste van beide werelden hebben bij het gebruik van server-side rendering met moderne frontend technologieën. De manier waarop dit over het algemeen werkt is dat de server de volledig gerenderde toepassing weergeeft en terugstuurt bij de eerste lading. De volgende stap, bekend als hydratatie, is waar uw JavaScript bundel zal worden gedownload en uitgevoerd. Dit hecht event handlers en bedrading dingen zoals uw client-side router.

met deze aanpak, krijgt u ALLE voordelen van SSR op de eerste belasting, dan zal elke interactie vanaf dat punt vooruit worden behandeld door client-side JavaScript. Dit zorgt voor een snelle, SEO-vriendelijke eerste lading, gevolgd door de dynamische single-page web app ervaring die we kennen en liefde.

toepassingen zoals deze staan bekend als universele toepassingen omdat dezelfde JavaScript draait op de client en de server. Misschien hoor je ook de liefhebber term “isomorf” worden gebruikt, wat precies hetzelfde betekent.

Tutorial: Het implementeren van SSR

SSR is ook niet zonder compromissen. Het voegt overhead aan uw ontwikkeling door de invoering van een meer complexe configuratie, evenals het hosten en beheren van uw eigen server. Deze problemen zijn de reden waarom ongelooflijke frameworks zoals Next.js en Razzle zijn erg populair: ze abstraheren het SSR-configuratiegedeelte en laten je focussen op het schrijven van UI-code.

in deze tutorial gaan we geen SSR frameworks gebruiken. De beste manier om te leren hoe iets werkt is door het daadwerkelijk te bouwen, dus we gaan leren hoe we de eenvoudigste SSR setup kunnen maken die we kunnen bieden:

  • Global CDN
  • volledig functionele backend API
  • geen servers of infrastructuur om
  • Single-command implementatie

we gaan een universele Server-gerenderde React applicatie implementeren die is gemaakt met create-react-app op Amazon Web Services (AWS). Je hoeft geen ervaring met AWS te hebben om mee te volgen.

onze tools

om onze applicatie te bouwen, gaan we gebruik maken van een paar verschillende AWS-diensten.

  • AWS Amplify: A high-level framework for managing AWS services, mainly for mobile and web development
  • AWS Lambda: Run code in de cloud zonder servers te beheren
  • AWS Cloudfront (CDN): een content delivery network dat verantwoordelijk is voor het leveren en cachen van content over de hele wereld
  • AWS Simple Storage Service (S3): waar we onze statische assets (JS, CSS, etc.)

Architectuurdiagram

onze Lambda-functie is verantwoordelijk voor de serverweergave van onze React-toepassing. We zullen S3 gebruiken om onze statische content op te slaan en Cloudfront CDN om het te bedienen. U hoeft geen voorkennis van deze diensten hebben, als AWS Amplify zal het super eenvoudig voor ons om ze te maken.

ons Architectuurdiagram

ons Architectuurdiagram

het bouwen van onze applicatie

Allereerst moet u de AWS Amplify CLI installeren en een AWS-account aanmaken als u er nog geen hebt. U kunt dit doen door het volgen van deze korte gids.

Project setup

nu Amplify is geconfigureerd, kunnen we beginnen met het opzetten van ons React project. We gaan de fantastische create-react-app gebruiken om ons te helpen. Ervan uitgaande dat je Node hebt.JS en npm geïnstalleerd, we kunnen draaien:

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

Selecteer de standaard opties in de AWS Amplify wizard.

ons React project is nu bootstrapped met Amplify en klaar voor ons om onze “server” voor SSR toe te voegen. We doen dit door amplify add api uit te voeren en enkele vragen te beantwoorden:

$ 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

Hiermee worden de relevante sjablonen, mappen en code gecreëerd die nodig zijn voor onze AWS-infrastructuur en backend: een AWS Lambda-functie die een kleine Express-server zal draaien die verantwoordelijk is voor het renderen van onze React-applicatie.

voordat we onze infrastructuur implementeren, moeten we enkele wijzigingen aanbrengen in onze React-applicatie om deze voor te bereiden op server-side rendering. Open src/App.js (de belangrijkste app-component voor uw React-toepassing) en plak in het volgende:

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

vervolgens moeten we een script maken dat onze React applicatie op de server zal weergeven. Dit wordt gedaan met de functie renderToString in het pakket react-dom/server. Deze functie is verantwoordelijk voor het nemen van onze <App /> component en het renderen op de server kant als een string, klaar om te worden geretourneerd als volledig gerenderde HTML aan de client.

Maak een bestand aan op src/render.js met de volgende code:

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

Geweldig – onze client-side React app heeft alle code die het nodig heeft om te worden weergegeven op de server kant. Dit betekent dat we nu het server-side eindpunt moeten coderen dat onze React applicatie zal weergeven.

we hebben echter een probleem – we moeten de src/render functie en onze <App /> component code draaien op de server. De server weet niets over React of zelfs ES modules standaard. Om deze reden gaan we de code van de React applicatie met behulp van Babel naar de serverzijde vertalen.

om dit te doen, installeren we een paar Babel afhankelijkheden in ons project.

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

maak vervolgens een .babelrc aan in de root van uw project. Dit bestand wordt gebruikt om Babel in te stellen en het te vertellen welke plugins/voorinstellingen te gebruiken.

{ "presets":}

ten slotte, laten we onze package.json bijwerken om onze code te transpileren als onderdeel van de bouwstap. Dit zal de bestanden omzetten naar de amplify/backend/function/amplifyssr/src/client map, waar we alle universele JavaScript zullen opslaan die zowel op de client als op de server voor SSR uitgevoerd moet worden.

 "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 van de app in Lambda

de build configuratie is voltooid! Laten we in amplify/backend/function/amplifyssr/src springen en react en react-dom installeren, omdat ze beide nodig zijn voor de Lambda om SSR uit te voeren.

yarn add react react-dom

nu voor het configureren van onze Express server, die zal draaien op Lambda. De Lambda-functie werd automatisch voor ons gegenereerd toen we de stap amplify add api eerder voltooiden en een API REST en ExpressJS kozen.

Amplify heeft de Express-server al geconfigureerd voor ons om op Lambda te draaien, dus alles wat we nu moeten doen is een eindpunt toevoegen aan de server-render onze React-applicatie wanneer iemand de API-URL in de browser raakt. Werk uw amplify/backend/function/amplifyssr/src/app.js bestand bij om de volgende code te bevatten:

/* 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

onze Express server is nu SSR-ready en we kunnen onze React-applicatie implementeren.

Hosting en final touch

zodra we de server-gerenderde HTML terug ontvangen van de eerste render van onze app, zullen we dan de client-side JavaScript bundel ophalen om het van daaruit over te nemen en ons een volledig interactieve SPA te geven.

we hebben een plek nodig om onze JavaScript-en statische bestanden aan de client-kant te hosten. In AWS, de dienst die meestal wordt gebruikt voor dit is S3 (Simple Storage Service), een massaal schaalbare cloud object store.

we gaan er ook een CDN voor zetten voor globale caching en prestaties. Met Amplify, kunnen we beide bronnen voor ons project maken door een paar commando ‘ s uit onze project root directory te draaien:

$ 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)

u kunt nu uw volledige infrastructuur implementeren, inclusief uw Express Server Lambda-functie, S3 bucket en CDN, door het commando amplify publish uit te voeren.

uw console-uitvoer toont alle relevante bronnen van uw sjablonen die voor u worden gemaakt door Amplify. Houd er rekening mee dat het maken van een CloudFront CDN een tijdje kan duren, dus wees geduldig. Zodra uw resources zijn aangemaakt, wordt uw CloudFront CDN URL weergegeven in de terminal.

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

het laatste wat we moeten doen is React vertellen van waar we onze client-side bundel moeten ophalen nadat de app door de server is gerenderd. Dit wordt gedaan in de create-react-app met de omgevingsvariabele PUBLIC_URL. Laten we onze React app package.json scripts opnieuw bijwerken om er als volgt uit te zien:

 "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" },

herbouw en implementeer uw applicatie naar AWS met deze bijgewerkte configuratie.

amplify publish

we zouden nu een volledig server-side-rendered React app moeten hebben die draait op AWS!

het uitvoeren van onze app

uw SSR API URL is te vinden op amplify/backend/amplify-meta.json. Zoek naar RootUrl in uw JSON-bestand en u zou de URL moeten zien waarop u uw nieuwe server-gerenderde toepassing kunt bezoeken. Het moet er ongeveer als volgt uitzien:

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

bezoek de API Gateway URL in uw browser op <your-api-url>/ssr en u zou uw glanzende nieuwe server-gerenderde React applicatie moeten zien! Als u op het tabblad Netwerk in uw browser van uw keuze duikt en de verzoeken bekijkt, zult u merken dat het verzoek aan /ssr een volledig gerenderde HTML-reactie heeft met onze React-toepassing weergegeven in <body> van het document.

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

u ziet ook de verzoeken die vanuit de browser naar uw Cloudfront URL worden gedaan om het client-side JavaScript te laden dat het renderen van hier zal overnemen, wat ons het beste geeft van zowel de client-side als server-side rendering werelden.

waar te gaan vanaf hier

deze tutorial is bedoeld om u zo snel mogelijk aan de slag te krijgen met server-side rendering zonder u zorgen te hoeven maken over het beheer van infrastructuur, CDN ‘ s en meer. Na gebruik van de serverless aanpak, zijn er een paar leuke verbeteringen die we kunnen maken aan onze setup.

Provisioned concurrency

een manier waarop AWS Lambda extreem goedkoop kan blijven is dat Lambda-functies die al een tijdje niet zijn geraakt, inactief worden.”Dit betekent in wezen dat wanneer we ze opnieuw uitvoeren, er zal zijn wat bekend staat als een” koude start ” — een initialisatie vertraging die moet gebeuren voordat de Lambda reageert.

hierna is de lambda gedurende een bepaalde tijd weer “warm” en reageert hij snel op Volgende verzoeken tot de volgende lange periode van niet-actief gebruik. Dit kan leiden tot enigszins onbetrouwbare responstijden.

ondanks het feit dat Lambda “serverless” is, gebruikt Lambda lichtgewicht containers om verzoeken te verwerken. Elke container kan slechts één verzoek op een bepaald moment verwerken. Naast het probleem van de koude start na een inactieve periode, geldt hetzelfde ook wanneer veel gelijktijdige verzoeken dezelfde Lambda-functie raken, waardoor meer gelijktijdige containers of werknemers koud worden gestart voordat ze reageren.

in het verleden hebben veel ingenieurs dit probleem opgelost door scripts te schrijven om de Lambda periodiek te pingen om het warm te houden. Er is nu een veel betere AWS-inheemse manier om dit op te lossen, en het is bekend als Provisioned Concurrency.

met provisioned Concurrency kunt u heel eenvoudig een bepaald aantal speciale containers aanvragen Om warm te blijven voor een specifieke Lambda-functie. Dit geeft u een veel consistentere SSR responstijd in tijden van hoge en sporadische belasting.

Lambda versies

u kunt meerdere Lambda versies voor uw functies maken en het verkeer tussen hen verdelen. Dit is zeer krachtig in onze SSR applicatie omdat het ons in staat stelt om updates te maken aan de Lambda kant en A / B testen met een kleiner deel van de gebruikers.

u kunt verschillende versies van uw Lambda publiceren en het verkeer tussen hen verdelen in gewichten die u opgeeft. Bijvoorbeeld, kunt u een server-render een CTA banner voor sommige gebruikers om betrokkenheid te meten, maar niet maken voor anderen. U kunt dit doen met Lambda versies.

Full-stack webapplicatie

zoals eerder uitgelegd, AWS Amplify maakt al een REST API en een Express server voor ons, waarin we een eindpunt hebben gemaakt naar server-render onze React applicatie. We kunnen altijd meer code en endpoints toevoegen aan deze Express server op amplify/backend/function/amplifyssr/src/app.js, waardoor we onze app kunnen veranderen in een full-stack webapplicatie, compleet met database, authenticatie en meer.

u kunt gebruik maken van de fantastische suite van AWS Amplify tools om deze resources te creëren of aan te sluiten op uw eigen infrastructuur — zelfs als het niet wordt gehost op AWS. U kunt behandelen uw AWS Lambda backend als elke andere Express server en bouwen op de top van het.

u hebt al uw volledige deployment pipeline ingesteld door amplify publish uit te voeren, zodat u zich kunt concentreren op het schrijven van code. Het uitgangspunt in deze tutorial geeft je totale flexibiliteit om te doen wat je wilt vanaf hier.

conclusie

server-side rendering hoeft niet moeilijk te zijn. We kunnen volledig beheerde tools gebruiken zoals Next of Razzle, die op zichzelf geweldig zijn, maar voor veel teams kan dit een veel te grote paradigmaverschuiving zijn gezien hun bestaande code of vereisten. Met behulp van een eenvoudige, onderhoudsarme, aangepaste aanpak kan het leven gemakkelijker te maken, vooral als u al met behulp van AWS of Amplify voor uw project.

SSR kan een ton waarde toevoegen aan uw webapplicaties en een broodnodige performance of SEO boost bieden. We hebben het geluk in de web development community tools te hebben die CDN ‘s, serverloze backends en volledig gehoste webapplicaties kunnen maken met een paar commando’ s of klikken.

zelfs als je denkt dat je SSR niet nodig hebt, is het een veel voorkomend en veel voorkomend onderwerp in het JavaScript-ecosysteem. Het hebben van een begrip van de voordelen en trade-offs zal van pas komen voor bijna iedereen die betrokken zijn bij de ontwikkeling van het web gebied.

ik hoop dat je iets geleerd vandaag-bedankt voor het lezen! Voel je vrij om uit te reiken naar mij of volg me op Twitter, waar ik tweet en blog over JavaScript, Python, AWS, automatisering, en no-code ontwikkeling.

volledige zichtbaarheid in productie React apps

Debugging React applicaties kan moeilijk zijn, vooral wanneer gebruikers problemen ondervinden die moeilijk te reproduceren zijn. Als je geà nteresseerd bent in het monitoren en volgen van Redux state, automatisch JavaScript-fouten opduiken, en het bijhouden van langzame netwerkverzoeken en de laadtijd van componenten, probeer LogRocket. LogRocket Dashboard gratis Trial Banner

LogRocket is als een DVR voor web apps, het opnemen van letterlijk alles wat er gebeurt op uw React app. In plaats van te raden waarom problemen zich voordoen, kunt u aggregeren en rapporteren in welke staat uw aanvraag zich bevond toen een probleem zich voordeed. LogRocket controleert ook de prestaties van uw app, rapportage met statistieken zoals client CPU belasting, client geheugengebruik, en meer.

het logrocket Redux middleware pakket voegt een extra laag zichtbaarheid toe aan uw gebruikerssessies. LogRocket logt alle acties en staat van uw Redux stores.

moderniseren hoe u debuggen uw React apps-start gratis monitoring.

Geef een antwoord

Het e-mailadres wordt niet gepubliceerd.