Najlepsze z obu światów: SSR z izomorficznym JavaScript

renderowanie po stronie serwera, lub SSR, jest frazą, którą często słyszysz w społeczności programistów frontend.

na najbardziej podstawowym poziomie renderowanie po stronie serwera jest dokładnie tym, co opisuje: renderowaniem aplikacji na serwerze. Nawigujesz do strony internetowej, wysyła żądanie do serwera, renderuje kod HTML i w pełni renderowany wynik wraca do przeglądarki. Całkiem proste. Być może zadajesz sobie pytanie, dlaczego społeczność ma na to hasło.

przed powstaniem bogatych i dynamicznych aplikacji internetowych, które w dużej mierze opierały się na JavaScript i jQuery, zasadniczo wszystkie aplikacje internetowe były renderowane przez serwer. PHP, WordPress, a nawet tylko podstawowe strony HTML są tego przykładami.

kiedy odwiedzasz stronę na jednej z tych witryn, odzyskujesz wszystkie dane HTML i wszystkie. Jeśli klikniesz łącze, przeglądarka wyśle kolejne żądanie do serwera. Po odpowiedzi przeglądarka odświeży i wyrenderuje następną stronę od podstaw. Takie podejście działa dobrze i od lat; przeglądarki są spektakularnie szybkie w renderowaniu statycznego HTML. Co się zmieniło?

od przełomu wieków użycie JavaScript zmieniło się z odrobiny tu i tam dla interaktywności stron internetowych w niekwestionowany język wyboru w Internecie. Stale wysyłamy więcej logiki i JavaScript do przeglądarki.

jednostronicowe frameworki, takie jak React i Vue, zapoczątkowały nową erę dynamicznych, złożonych, opartych na danych, renderowanych przez Klienta aplikacji internetowych. Te uzdrowiska różnią się od aplikacji renderowanych przez serwer, ponieważ nie pobierają w pełni renderowanej zawartości wraz z danymi z serwera przed renderowaniem na ekranie.

aplikacje renderowane po stronie klienta renderują swoją zawartość w przeglądarce przy użyciu JavaScript. Zamiast pobierać całą zawartość z serwera, po prostu pobierają stronę HTML bez kości bez zawartości ciała i renderują całą zawartość wewnątrz za pomocą JavaScript.

zaletą tego jest to, że unikasz pełnego odświeżania strony, które dzieje się w pełni renderowanych przez serwer aplikacjach, co może być trochę wstrząsające dla użytkownika. Jednostronicowe aplikacje renderowane przez Klienta aktualizują zawartość na ekranie, pobierają dane z interfejsów API i aktualizują bezpośrednio przed tobą bez odświeżania strony. Ta cecha sprawia, że nowoczesne aplikacje internetowe czują się zgryźliwe i” natywne ” podczas interakcji z nimi.

kompromisy renderowania po stronie klienta

to nie tylko słońce i tęcza w świecie Spa renderowanym po stronie klienta. Istnieją pewne kompromisy związane z renderowaniem aplikacji po stronie klienta. Dwa podstawowe przykłady to SEO i początkowa wydajność obciążenia.

SEO

ponieważ aplikacje renderowane przez Klienta zwracają gołą stronę HTML z bardzo małą zawartością, zanim JavaScript uruchomi się i renderuje resztę, roboty indeksujące mogą mieć trudności z zrozumieniem struktury HTML Twojej strony, co jest szkodliwe dla rankingów wyszukiwania Twojej witryny. Google wykonał wiele dobrej pracy wokół tego, ale nadal zaleca się unikanie renderowania po stronie klienta, jeśli SEO jest szczególnie ważne.

wydajność początkowego ładowania

w przypadku aplikacji renderowanych przez klienta zwykle po pierwszym otwarciu strony pojawiają się następujące rzeczy:

  • aplikacja ładuje niektóre podstawowe HTML, takie jak powłoka aplikacji lub statyczny pasek nawigacyjny
  • widzisz jakiś wskaźnik ładowania
  • twoja zawartość jest renderowana

problem z tym polega na tym, że aplikacja nie wyświetli niczego, dopóki JavaScript nie załaduje się całkowicie z sieci i nie zakończy renderowania elementów na ekranie.

w skrócie, problem z wydajnością po stronie klienta w ogóle polega na tym, że nie możesz kontrolować, na jakim urządzeniu klienckim ktoś używa Twojej aplikacji-czy to ich najnowocześniejszy smartfon, potężny wysokiej klasy komputer stacjonarny, czy smartfon o niższej wartości 100 USD.

kontrolujemy jednak serwer. Prawie zawsze możemy dać naszemu serwerowi więcej procesora i pamięci oraz dostosować go, aby działał lepiej dla naszych użytkowników.

the best of both worlds

możemy mieć to, co najlepsze z obu światów, korzystając z renderowania po stronie serwera z nowoczesnymi technologiami frontend. Ogólnie działa to tak, że serwer renderuje i odsyła w pełni renderowaną aplikację przy pierwszym załadowaniu. Następnym krokiem, znanym jako hydration, jest pobranie i wykonanie pakietu JavaScript. Umożliwia to podłączenie obsługi zdarzeń i podłączenie rzeczy, takich jak router po stronie klienta.

dzięki takiemu podejściu uzyskujesz wszystkie korzyści SSR przy początkowym obciążeniu, a każda interakcja od tego momentu będzie obsługiwana przez JavaScript po stronie klienta. Zapewnia to szybkie, przyjazne dla SEO początkowe Ładowanie, a następnie dynamiczną jednostronicową aplikację internetową, którą znamy i kochamy.

aplikacje takie jak ta są znane jako aplikacje uniwersalne, ponieważ ten sam JavaScript działa na kliencie i serwerze. Można również usłyszeć bardziej wymyślne określenie „izomorficzny”, które oznacza dokładnie to samo.

Tutorial: wdrażanie SSR

SSR nie jest również pozbawione kompromisów. Dodaje narzut do rozwoju, wprowadzając bardziej złożoną konfigurację, a także hostując i zarządzając własnym serwerem. Te problemy są dlaczego niesamowite ramy Jak Next.js i Razzle są bardzo popularne: odciągają część konfiguracji SSR i pozwalają skupić się na pisaniu kodu UI.

w tym samouczku nie będziemy używać żadnych frameworków SSR. Najlepszym sposobem, aby dowiedzieć się, jak coś działa, jest budowanie go, więc nauczymy się, jak stworzyć najprostszą konfigurację SSR, którą ewentualnie możemy zapewnić:

  • Globalny CDN
  • w pełni funkcjonalny interfejs API backendu
  • brak serwerów i infrastruktury do zarządzania
  • wdrożenie pojedynczego polecenia

zamierzamy wdrożyć uniwersalną aplikację React renderowaną na serwerze utworzoną za pomocą create-react-app na Amazon Web Services (AWS). Nie musisz mieć doświadczenia z AWS, aby kontynuować.

nasze narzędzia

w celu zbudowania naszej aplikacji wykorzystamy kilka różnych usług AWS.

  • Wzmacniacz AWS: Framework wysokiego poziomu do zarządzania usługami AWS, głównie na potrzeby tworzenia aplikacji mobilnych i internetowych
  • AWS Lambda: uruchamianie kodu w chmurze bez zarządzania serwerami
  • AWS Cloudfront (CDN): sieć dostarczania treści odpowiedzialna za dostarczanie i buforowanie treści na całym świecie
  • AWS Simple Storage Service (S3): gdzie będziemy przechowywać nasze zasoby statyczne (JS, CSS itp.)

schemat architektury

Nasza funkcja Lambda odpowiada za renderowanie serwera naszej aplikacji Reactowej. Będziemy używać S3 do przechowywania naszej statycznej zawartości i CloudFront CDN do jej obsługi. Nie musisz mieć żadnej wcześniejszej wiedzy na temat tych usług, ponieważ AWS Amplify sprawi, że ich tworzenie będzie dla nas bardzo proste.

nasz schemat architektury

nasz schemat architektury

Budowanie naszej aplikacji

przede wszystkim musisz zainstalować AWS Amplify CLI i utworzyć konto AWS, jeśli jeszcze go nie masz. Możesz to zrobić, postępując zgodnie z tym krótkim przewodnikiem.

konfiguracja projektu

po skonfigurowaniu Amplify możemy rozpocząć konfigurację naszego projektu Reactowego. Użyjemy fantastycznej aplikacji create-react, aby nam pomóc. Zakładając, że masz węzeł.JS i npm zainstalowane, możemy uruchomić:

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

Wybierz domyślne opcje w kreatorze wzmacniania AWS.

nasz projekt Reactowy jest teraz uruchomiony z Amplify i gotowy do dodania naszego „serwera” dla SSR. Robimy to uruchamiając amplify add api i odpowiadając na kilka pytań:

$ 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

stworzy to odpowiednie szablony,katalogi i kod potrzebny do naszej infrastruktury AWS i zaplecza: funkcję AWS Lambda, która uruchomi mały serwer ekspresowy odpowiedzialny za renderowanie naszej aplikacji React.

zanim wdrożymy naszą infrastrukturę, musimy wprowadzić pewne zmiany w naszej aplikacji Reactowej, aby przygotować ją do renderowania po stronie serwera. Otwórz src/App.js(główny komponent aplikacji Reactowej) i wklej poniższy:

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

następnie musimy stworzyć skrypt, który renderuje naszą aplikację Reactową po stronie serwera. Odbywa się to za pomocą funkcji renderToString w pakiecie react-dom/server. Ta funkcja jest odpowiedzialna za pobranie naszego komponentu <App /> i renderowanie go po stronie serwera jako łańcuch znaków, gotowy do zwrócenia jako w pełni renderowany HTML do klienta.

Utwórz plik pod adresem src/render.js z następującym kodem:

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

świetnie – nasza aplikacja reagująca po stronie klienta ma cały kod, który musi być renderowany po stronie serwera. Oznacza to, że musimy teraz zakodować punkt końcowy po stronie serwera, który wyrenderuje naszą aplikację Reactową.

mamy jednak problem – potrzebujemy funkcji src/render i naszego kodu komponentu <App /> do uruchomienia po stronie serwera. Serwer domyślnie nie wie nic o Reaccie, a nawet o modułach ES. Z tego powodu przenosimy kod z aplikacji Reactowej za pomocą Babel na stronę serwera.

aby to zrobić, zainstalujmy kilka zależności Babel w naszym projekcie.

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

następnie utwórz .babelrc u źródła projektu. Ten plik jest używany do konfiguracji Babel i powiedzieć, które wtyczki / presety używać.

{ "presets":}

na koniec zaktualizujmy nasz package.json, aby transpilować nasz kod w ramach kroku budowania. Spowoduje to przeniesienie plików do katalogu amplify/backend/function/amplifyssr/src/client, gdzie będziemy przechowywać cały uniwersalny JavaScript, który musi być uruchomiony po stronie klienta, a także serwera dla 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" },

renderowanie aplikacji w Lambda

konfiguracja kompilacji jest zakończona! Przejdźmy do amplify/backend/function/amplifyssr/src i zainstalujmy react i react-dom, ponieważ oba będą wymagane, aby Lambda wykonała SSR.

yarn add react react-dom

teraz skonfiguruj nasz serwer Express, który będzie działał na Lambda. Funkcja Lambda została dla nas wygenerowana automatycznie, gdy zakończyliśmy krok amplify add api wcześniej i wybraliśmy API REST i ExpressJS.

Amplify skonfigurował już Serwer Express, aby działał na Lambdzie, więc wszystko, co musimy teraz zrobić, to dodać punkt końcowy do serwera-renderować naszą aplikację Reactową, gdy ktoś trafi w ADRES URL API w przeglądarce. Zaktualizuj plik amplify/backend/function/amplifyssr/src/app.js, aby zawierał następujący kod:

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

nasz serwer Express jest teraz gotowy na SSR i możemy wdrożyć naszą aplikację React.

Hosting i ostatnie poprawki

po otrzymaniu renderowanego przez serwer HTML z początkowego renderowania naszej aplikacji, pobierzemy Pakiet JavaScript po stronie klienta, aby przejąć stamtąd i dać nam w pełni interaktywne SPA.

musimy gdzieś hostować nasze pliki JavaScript i statyczne po stronie klienta. W AWS usługa zwykle używana do tego celu to S3 (Simple Storage Service), masowo skalowalny magazyn obiektów w chmurze.

zamierzamy również umieścić CDN przed nim w celu globalnego buforowania i wydajności. Dzięki Amplify możemy utworzyć oba te zasoby dla naszego projektu, uruchamiając kilka poleceń z naszego katalogu głównego projektu:

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

możesz teraz wdrożyć całą swoją infrastrukturę, w tym funkcję Lambda serwera Express, S3 bucket i CDN, uruchamiając polecenie amplify publish.

wyjście konsoli pokaże wszystkie istotne zasoby z szablonów utworzonych dla Ciebie przez Amplify. Pamiętaj, że tworzenie CloudFront CDN może trochę potrwać, więc bądź cierpliwy. Po utworzeniu zasobów adres URL CloudFront CDN zostanie wyświetlony w terminalu.

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

ostatnią rzeczą, jaką musimy zrobić, to powiedzieć Reactowi, skąd ma pobrać nasz pakiet po stronie klienta po renderowaniu aplikacji przez serwer. Odbywa się to w create-react-app przy użyciu zmiennej środowiskowej PUBLIC_URL. Zaktualizujmy ponownie nasze Skrypty React app package.json, aby wyglądały następująco:

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

Przebuduj i wdroż aplikację w AWS dzięki tej zaktualizowanej konfiguracji.

amplify publish

powinniśmy teraz mieć w pełni renderowaną po stronie serwera aplikację React działającą na AWS!

uruchamianie naszej aplikacji

adres URL API SSR można znaleźć pod adresem amplify/backend/amplify-meta.json. Poszukaj RootUrl w pliku JSON i powinieneś zobaczyć adres URL, pod którym możesz odwiedzić nową aplikację renderowaną na serwerze. Powinno to wyglądać mniej więcej tak:

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

odwiedź adres URL bramy API w przeglądarce pod adresem <your-api-url>/ssr i powinieneś zobaczyć swoją nową, błyszczącą, renderowaną na serwerze aplikację React! Jeśli zanurzysz się w karcie Sieć w wybranej przeglądarce i przejrzysz żądania, zauważysz, że żądanie do /ssr ma w pełni renderowaną odpowiedź HTML, a nasza aplikacja React renderowana jest wewnątrz <body> dokumentu.

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

zauważysz również żądania wysyłane do adresu URL Cloudfront z przeglądarki, aby załadować JavaScript po stronie klienta, który przejmie renderowanie stąd, dając nam najlepsze zarówno światy renderowania po stronie klienta, jak i serwera.

dokąd się stąd udać

ten poradnik ma na celu jak najszybsze uruchomienie renderowania po stronie serwera bez martwienia się o zarządzanie infrastrukturą, CDN i nie tylko. Po użyciu podejścia bezserwerowego możemy wprowadzić kilka fajnych ulepszeń do naszej konfiguracji.

Aprowizowana współbieżność

jednym ze sposobów, w jaki AWS Lambda jest w stanie pozostać wyjątkowo tanim, jest to, że funkcje Lambda, które nie zostały trafione przez jakiś czas, będą „bezczynne”.”Zasadniczo oznacza to, że kiedy wykonamy je ponownie, nastąpi tzw.” zimny start ” — opóźnienie inicjalizacji, które musi nastąpić, zanim Lambda odpowie.

po tym czasie lambda jest ponownie „ciepła” przez pewien czas i szybko reaguje na kolejne żądania, aż do następnego długiego okresu bezczynności. Może to powodować nieco zawodne czasy reakcji.

pomimo tego, że Lambda jest „bezserwerowa”, używa lekkich kontenerów do przetwarzania wszelkich żądań. Każdy kontener może w danym momencie przetworzyć tylko jedno żądanie. Oprócz problemu zimnego startu po okresie bezczynności, to samo dotyczy sytuacji, gdy wiele równoczesnych żądań uderza w tę samą funkcję Lambda, co powoduje, że więcej współbieżnych kontenerów lub workerów jest uruchamianych na zimno przed udzieleniem odpowiedzi.

w przeszłości wielu inżynierów rozwiązało ten problem, pisząc skrypty do okresowego pingowania Lambda, aby utrzymać ciepło. Istnieje teraz znacznie lepszy natywny sposób rozwiązania tego problemu przez AWS, znany jako Aprowizowana współbieżność.

dzięki Aprowizowanej współbieżności możesz bardzo łatwo zażądać określonej liczby dedykowanych kontenerów, aby zachować ciepło dla określonej funkcji Lambda. Zapewni to znacznie bardziej spójny czas reakcji SSR w czasach dużego i sporadycznego obciążenia.

wersje Lambda

możesz utworzyć kilka wersji Lambda dla swoich funkcji i podzielić ruch między nimi. Jest to bardzo potężne w naszej aplikacji SSR, ponieważ pozwala nam dokonywać aktualizacji Po stronie Lambda i A / B testować je z mniejszą częścią użytkowników.

możesz opublikować kilka wersji swojego Lambda i podzielić ruch między nimi w określonych wagach. Na przykład możesz chcieć renderować baner CTA dla niektórych użytkowników, aby zmierzyć zaangażowanie, ale nie renderować go dla innych. Możesz to zrobić z wersjami Lambda.

pełna aplikacja webowa

jak wyjaśniono wcześniej, AWS Amplify tworzy dla nas REST API i Serwer Express, w którym stworzyliśmy endpoint to server-render naszą aplikację React. Zawsze możemy dodać więcej kodu i punktów końcowych do tego serwera ekspresowego pod adresem amplify/backend/function/amplifyssr/src/app.js, umożliwiając nam przekształcenie naszej aplikacji w pełną aplikację internetową, wraz z bazą danych,uwierzytelnianiem i innymi.

możesz skorzystać z fantastycznego pakietu narzędzi AWS Amplify, aby utworzyć te zasoby lub podłączyć je do własnej infrastruktury — nawet jeśli nie jest ona hostowana na AWS. Możesz traktować swój backend AWS Lambda jak każdy inny serwer Express i budować na nim.

masz już skonfigurowany cały potok wdrażania, uruchamiając amplify publish, więc możesz skupić się na pisaniu kodu. Punkt wyjścia w tym samouczku daje całkowitą elastyczność, aby robić to,co chcesz stąd.

wniosek

renderowanie po stronie serwera nie musi być trudne. Możemy używać w pełni zarządzanych narzędzi, takich jak Next lub Razzle, które same w sobie są niesamowite, ale dla wielu zespołów może to być zbyt duża zmiana paradygmatu, biorąc pod uwagę ich istniejący kod lub wymagania. Korzystanie z prostego, łatwego w utrzymaniu, niestandardowego podejścia może ułatwić życie, zwłaszcza jeśli używasz już AWS lub Amplify w swoim projekcie.

SSR może dodać mnóstwo wartości do Twoich aplikacji internetowych i zapewnić bardzo potrzebną wydajność lub zwiększenie SEO. Mamy szczęście w społeczności programistów internetowych, że mamy narzędzia, które mogą tworzyć CDN, backendy bezserwerowe i w pełni hostowane aplikacje internetowe za pomocą kilku poleceń lub kliknięć.

nawet jeśli uważasz, że nie potrzebujesz SSR, jest to bardzo powszechny i powszechny temat w ekosystemie JavaScript. Zrozumienie jego zalet i kompromisów przyda się prawie każdemu zaangażowanemu w sferę tworzenia stron internetowych.

mam nadzieję, że nauczyłeś się czegoś dzisiaj-dzięki za przeczytanie! Skontaktuj się ze mną lub Śledź mnie na Twitterze, gdzie tweetuję i bloguję o JavaScript, Pythonie, AWS, automatyzacji i rozwoju bez kodu.

pełny wgląd w produkcyjne Aplikacje Reactowe

debugowanie aplikacji Reactowych może być trudne, zwłaszcza gdy użytkownicy doświadczają problemów, które są trudne do odtworzenia. Jeśli interesuje Cię monitorowanie i śledzenie stanu Redux, automatyczne wykrywanie błędów JavaScript oraz śledzenie powolnych żądań sieci i czasu ładowania komponentów, wypróbuj LogRocket. darmowy baner próbny LogRocket Dashboard

LogRocket jest jak rejestrator dla aplikacji internetowych, nagrywając dosłownie wszystko, co dzieje się w Twojej aplikacji React. Zamiast zgadywać, dlaczego pojawiają się problemy, możesz agregować i raportować, w jakim stanie była Twoja aplikacja, gdy wystąpił problem. LogRocket monitoruje również wydajność aplikacji, raportując za pomocą takich danych, jak obciążenie procesora klienta, zużycie pamięci klienta i inne.

Pakiet logrocket Redux middleware dodaje dodatkową warstwę wglądu do sesji użytkownika. LogRocket rejestruje wszystkie akcje i stany z Twoich sklepów Redux.

Zmodernizuj sposób debugowania aplikacji Reactowych-Rozpocznij monitorowanie za darmo.

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany.