両方の長所:同型JavaScriptを使用したSSR

サーバーサイドレンダリング、またはSSRは、フロントエンド開発コミュニティでよく耳にするフレーズです。

最も基本的なレベルでは、サーバー側のレンダリングはまさにそれが記述するものです。 あなたはウェブサイトに移動し、サーバーに要求を行い、HTMLをレンダリングし、ブラウザに完全にレンダリングされた結果を取得します。 かなり簡単です。 コミュニティがこれのための流行語をなぜ有するかあなた自身に尋ねるかもしれない。

JavaScriptとjQueryに大きく依存するリッチで動的なwebアプリケーションが登場する前は、基本的にすべてのwebアプリケーションがサーバーレンダリングされていました。 PHP、WordPress、さらには基本的なHTMLサイトもこの例です。

これらのサイトのいずれかのページにアクセスすると、すべてのHTMLデータとすべてが返されます。 リンクをクリックすると、ブラウザはサーバーに別の要求を行います。 応答に続いて、ブラウザが更新され、次のページがゼロからレンダリングされます。 このアプローチはうまく機能し、それは何年も持っています; ブラウザは、静的なHTMLをレンダリングする際に驚異的に高速です。 何が変わったのですか?

世紀の変わり目以来、JavaScriptの使用は、webページの対話性のためにあちこちに少し振りかけることから、web上で選択された誰もが認める言語になっています。 私たちは常により多くのロジックとJavaScriptをブラウザに出荷しています。

ReactやVueのようなシングルページフレームワークは、動的で複雑なデータ駆動型クライアントレンダリングwebアプリケーションのこの新しい時代を迎えました。 これらのSpaは、画面上にレンダリングする前に、サーバーからデータを含む完全にレンダリングされたコンテンツをフェッチしないため、サーバーレンダ

クライアント側でレンダリングされたアプリケーションは、JavaScriptを使用してブラウザでコンテンツをレンダーします。 サーバーからすべてのコンテンツを取得するのではなく、本文コンテンツのないベアボーンHTMLページを取得し、JavaScriptを使用してすべてのコンテンツを内部にレ

これの利点は、完全にサーバーレンダリングされたアプリケーションで発生する完全なページの更新を避けることです。 シングルページクライアントレンダリングアプリは、画面上のコンテンツを更新し、Apiからデータを取得し、ページを更新することなく目の前で更新します。 この特性は、現代のwebアプリケーションがそれらと対話するときにきびきびと”ネイティブ”に感じるものです。

クライアント側レンダリングのトレードオフ

クライアント側レンダリングされたSPAの世界では、すべての日差しと虹ではありません。 クライアント側でアプリケーションをレンダリングすることには、いくつかのトレードオフがあります。 主な2つの例はSEOと初期負荷パフォーマンスです。

SEO

クライアントレンダリングされたアプリは、JavaScriptが起動して残りをレンダリングする前に、コンテンツがほとんどない裸のHTMLページを返すため、検索エンジンクローラーがページのHTML構造を理解することは困難であり、これはサイトの検索ランキングに有害である。 Googleはこれを回避するために多くの優れた作業を行っていますが、SEOが特に重要な場合は、クライアント側のレンダリングを避けることをお勧めし

初期ロードパフォーマンス

クライアントレンダリングされたアプリでは、通常、最初にページを開いたときに次のことが発生します:

  • アプリは、アプリシェルや静的navbar
  • のようないくつかの基本的なHTMLをロードします。
  • あなたのコンテンツがレンダリングされます。

これの問題は、JavaScriptがネットワークから完全にロードされ、画面への要素のレンダリングが完了するまで、アプリケーションが何も表示されないということです。

一言で言えば、一般的にクライアント側のパフォーマンスの問題は、最先端のスマートフォン、強力なハイエンドのデスクトップマシン、または100ドルのロー

しかし、我々はサーバーを制御します。 ほとんどの場合、サーバーにより多くのCPUとメモリを提供し、ユーザーのパフォーマンスを向上させるために微調整することができます。

両方の世界のベスト

現代のフロントエンド技術でサーバー側のレンダリングを使用すると、両方の世界のベストを持つことができます。 これが一般的に機能する方法は、サーバーが最初のロード時に完全にレンダリングされたアプリケーションをレンダーして送り返すことです。 Hydrationと呼ばれる次のステップは、JavaScriptバンドルがダウンロードされて実行される場所です。 これは、イベントハンドラをアタッチし、クライアント側のルータのようなものを配線します。

このアプローチでは、最初のロードでSSRのすべての利点を得ると、その時点からのすべての相互作用はクライアント側のJavaScriptによって処理されます。 これは、私たちが知っていると愛する動的な単一ページのwebアプリの経験に続いて、迅速な、SEOに優しい初期ロードを提供します。

このようなアプリケーションは、クライアントとサーバー上で同じJavaScriptが実行されるため、ユニバーサルアプリケーションと呼ばれます。 また、まったく同じことを意味する「同型」という言葉が使用されているのを聞くこともあります。

チュートリアル:SSRの実装

SSRにもトレードオフがないわけではありません。 より複雑な構成を導入するだけでなく、独自のサーバーをホストして管理する必要があるため、開発にオーバーヘッドが追加されます。 これらの問題は、Nextのような信じられないほどのフレームワークjsとRazzleは非常に人気があります:SSR構成部分を抽象化し、UIコードの作成に集中できます。

このチュートリアルでは、SSRフレームワークを使用しません。 何かがどのように機能するかを学ぶ最良の方法は、実際にそれを構築することですので、提供できる可能性のある最も簡単なSSR設定を作成する方法:

  • グローバルCDN
  • 完全に機能するバックエンドAPI
  • 管理するためのサーバーやインフラストラクチャはありません
  • シングルコマンドデプロイ

create-react-appで作成されたユニバーサルサーバレンダリングされたReactアプリケーションをAmazon Web Services(AWS)にデプロイします。 AWSの経験がある必要はありません。

私たちのツール

私たちのアプリケーションを構築するために、いくつかの異なるAWSサービスを利用しようとしています。

  • : 主にモバイルおよびウェブ開発用のAWSサービスを管理するための高レベルのフレームワーク
  • AWS Lambda:サーバーを管理せずにクラウドでコードを実行
  • AWS Cloudfront(CDN):世界中のコ)

アーキテクチャ図

私たちのLambda関数は、Reactアプリケーションのサーバーレンダリングを担当しています。 静的コンテンツを保存するためにS3を使用し、それを提供するためにCloudfront CDNを使用します。 AWS Amplifyはこれらのサービスを作成することを非常に簡単にするため、これらのサービスについて事前知識を持つ必要はありません。

私たちのアーキテクチャ図

アーキテクチャ図

アプリケーションの構築

まず、AWS Amplify CLIをインストールし、AWSアカウントをまだ持っていない場合は作成する必要があります。 この短いガイドに従うことでこれを行うことができます。

プロジェクト設定

Amplifyが設定されたので、Reactプロジェクトの設定を開始できます。 私たちは私たちを助けるために素晴らしいcreate-react-appを使用します。 あなたがNodeを持っていると仮定します。jsとnpmがインストールされていると、実行できます:

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

AWS Amplifyウィザードでデフォルトのオプションを選択します。

私たちのReactプロジェクトはAmplifyでブートストラップされ、SSR用の”サーバー”を追加する準備が整いました。 これを行うには、amplify add apiを実行していくつかの質問に答えます:

$ 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

これにより、AWSインフラストラクチャとバックエンドに必要な関連するテンプレート、ディレクトリ、およびコードが作成されます。

インフラストラクチャをデプロイする前に、サーバー側のレンダリング用に準備するためにReactアプリケーション内でいくつかの変更を加える必要があ src/App.js(Reactアプリケーションのメインアプリコンポーネント)を開き、次のように貼り付けます:

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

次に、Reactアプリケーションをサーバー側でレンダリングするスクリプトを作成する必要があります。 これは、react-dom/serverパッケージのrenderToString関数で行われます。 この関数は、<App />コンポーネントを取得し、サーバー側で文字列としてレンダリングし、完全にレンダリングされたHTMLとしてクライアントに返す準備ができ

次のコードでsrc/render.jsにファイルを作成します:

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

素晴らしい-私たちのクライアント側のReactアプリは、サーバー側でレンダリングする必要があるすべてのコードを持っています。 これは、Reactアプリケーションをレンダリングするサーバー側のエンドポイントをコード化する必要があることを意味します。

問題がありますが、サーバー側で実行するにはsrc/render関数と<App />コンポーネントコードが必要です。 サーバーはデフォルトでReactやESモジュールについては何も知りません。 このため、Babelを使用してReactアプリケーションからサーバー側にコードを移行します。

これを行うには、いくつかのBabel依存関係をプロジェクトにインストールしましょう。

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

次に、プロジェクトのルートに.babelrcを作成します。 このファイルは、Babelを設定し、使用するプラグイン/プリセットを指示するために使用されます。

{ "presets":}

最後に、package.jsonを更新して、ビルドステップの一部としてコードを変換しましょう。 これにより、ファイルがamplify/backend/function/amplifyssr/src/clientディレクトリに変換され、SSRのサーバーと同様にクライアント側で実行する必要があるすべてのユニバーサルJavaScriptが格納されます。

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

Lambdaでアプリをレンダリングする

ビルド構成は完了です! LambdaがSSRを実行するためには両方とも必要になるため、amplify/backend/function/amplifyssr/srcにジャンプしてreactreact-domをインストールしましょう。

yarn add react react-dom

ここで、Lambda上で実行されるExpressサーバーを設定します。 Lambda関数は、前のamplify add apiステップを完了し、RESTおよびExpressJSAPIを選択したときに自動生成されました。

AmplifyはすでにLambda上で実行するためのExpressサーバーを設定しているので、ここで行う必要があるのは、サーバーにエンドポイントを追加することだけです。 次のコードを含むようにamplify/backend/function/amplifyssr/src/app.jsファイルを更新します:

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

ExpressサーバーはSSR対応になり、Reactアプリケーションをデプロイできます。

ホスティングと最後の仕上げ

アプリの最初のレンダリングからサーバーレンダリングされたHTMLを受け取ったら、クライアント側のJavaScriptバンドルをフェッチしてそこから引き継ぎ、完全に対話型のSPAを提供します。

クライアント側のJavaScriptと静的ファイルをホストする場所が必要です。 AWSでは、これに一般的に使用されるサービスは、大規模なスケーラブルなクラウドオブジェクトストアであるS3(Simple Storage Service)です。

また、グローバルなキャッシュとパフォーマンスのためにCDNをその前に置くつもりです。 Amplifyを使用すると、プロジェクトのルートディレクトリからいくつかのコマンドを実行して、プロジェクトの両方のリソースを作成できます:

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

amplify publishコマンドを実行すると、Express server Lambda function、S3バケット、CDNなどのインフラストラクチャ全体をデプロイできるようになりました。

コンソール出力には、Amplifyによって作成されたテンプレートから関連するすべてのリソースが表示されます。 Cloudfront CDNの作成には時間がかかる場合がありますので、しばらくお待ちください。 リソースが作成されると、Cloudfront CDN URLがターミナルに表示されます。

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

最後に行う必要があるのは、アプリがサーバーによってレンダリングされた後、クライアント側のバンドルをどこからフェッチするかをReactに伝えるこ これは、PUBLIC_URL環境変数を使用してcreate-react-appで行われます。 React apppackage.jsonスクリプトを再度更新して、次のようにしましょう:

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

この更新された設定を使用して、アプリケーションを再構築してAWSにデプロイします。

amplify publish

完全にサーバー側でレンダリングされたReactアプリをAWS上で実行する必要があります!

アプリの実行

SSR APIのURLはamplify/backend/amplify-meta.jsonにあります。 JSONファイルでRootUrlを探すと、新しいサーバーレンダリングアプリケーションにアクセスできるURLが表示されます。 次のようになります:

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

ブラウザの<your-api-url>/ssrのAPI Gateway URLにアクセスすると、光沢のある新しいサーバーレンダリングされたReactアプリケーションが表示されます! 選択したブラウザのネットワークタブに飛び込み、リクエストを表示すると、/ssrへのリクエストには、ドキュメントの<body>内にレンダリングされたReactアプリケーシ

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

また、ここからレンダリングを引き継ぐクライアント側のJavaScriptをロードするために、ブラウザからCloudfront URLに要求が行われていることに気付くでしょう。

ここから行く場所

このチュートリアルは、インフラストラクチャ、Cdnなどの管理を心配することなく、できるだけ早くサーバー側のレンダリングを起動して実行することを目的としています。 サーバーレスアプローチを使用して、私たちは私たちのセットアップに行うことができますいくつかの素敵な機能強化があります。

Provisioned concurrency

AWS Lambdaが非常に低コストを維持できる一つの方法は、しばらくヒットされていないLambda関数が”アイドル状態になるということです。「これは本質的に、それらを再度実行すると、「コールドスタート」と呼ばれるものが発生することを意味します—ラムダが応答する前に発生する必要がある初期化の遅延。

この後、ラムダは一定期間再び”ウォーム”になり、次の長いアイドル期間まで後続の要求に迅速に応答します。 これにより、応答時間がわずかに信頼できなくなる可能性があります。

“サーバーレス”であるにもかかわらず、Lambdaは軽量コンテナを使用して要求を処理します。 すべてのコンテナは、任意の時点で一つの要求のみを処理することができます。 アイドル期間後のコールドスタートの問題に加えて、多くの同時リクエストが同じLambda関数にヒットし、応答する前に複数の同時コンテナまたはワーカーがコールドスタートされる場合も同様です。

過去には、多くのエンジニアがラムダを暖かく保つために定期的にpingするスクリプトを書くことでこの問題を解決してきました。 これを解決するためのはるかに優れたAWSネイティブの方法があり、これはProvisioned Concurrencyとして知られています。

プロビジョニングされた並行性を使用すると、特定のLambda関数のウォームを維持するために、特定の数の専用コンテナを非常に簡単に要求できます。 これにより、高い負荷と散発的な負荷の時に、より一貫したSSR応答時間が得られます。

Lambda versions

関数用にいくつかのLambdaバージョンを作成し、それらの間でトラフィックを分割することができます。 これは、Lambda側で更新を行い、a/Bテストを小規模なユーザーで行うことができるため、SSRアプリケーションでは非常に強力です。

ラムダのいくつかのバージョンを公開し、指定した重みでそれらの間のトラフィックを分割することができます。 たとえば、一部のユーザーがエンゲージメントを測定するためにCTAバナーをサーバーレンダリングしますが、他のユーザーにはレンダリングしない場合があります。 これはLambdaバージョンで行うことができます。

フルスタックウェブアプリケーション

前に説明したように、AWS AmplifyはすでにREST APIとExpressサーバーを作成しています。 このExpressサーバーにはamplify/backend/function/amplifyssr/src/app.jsのコードとエンドポイントをいつでも追加できるため、データベースや認証などを備えたフルスタックwebアプリケーションにアプリを

aws Amplifyツールの素晴らしいスイートを利用して、これらのリソースを作成したり、AWSでホストされていない場合でも、独自のインフラストラクチャにプラグ AWS Lambdaバックエンドを他のExpressサーバーとして扱い、その上に構築することができます。

amplify publishを実行してデプロイメントパイプライン全体をすでにセットアップしているので、コードの記述に集中できます。 このチュートリアルの開始点は、ここから望むことを行うための完全な柔軟性を提供します。

結論

サーバー側のレンダリングは難しい必要はありません。 NextやRazzleのような完全に管理されたツールを使用することはできますが、これは驚くべきことですが、多くのチームにとって、既存のコードや要件を考えると、これはあまりにも大きなパラダイムシフトになる可能性があります。 シンプルでメンテナンスの少ないカスタムアプローチを使用すると、特に既にAWSまたはAmplifyをプロジェクトに使用している場合は、作業が楽になります。

SSRはあなたのwebアプリケーションに価値のトンを追加し、大いに必要なパフォーマンスやSEOのブーストを提供することができます。 私たちは、いくつかのコマンドやクリックでCdn、サーバーレスバックエンド、および完全にホストされたwebアプリケーションを作成できるツールを持っている

SSRが必要だと思わなくても、JavaScriptエコシステムでは非常に一般的で一般的なトピックです。 その利点とトレードオフの理解を持つことは、web開発分野に関与するほとんどの人に便利になります。

私はあなたが今日何かを学んだことを願っています—読んでくれてありがとう! 私に手を差し伸べるか、私はJavaScript、Python、AWS、自動化、およびノーコード開発についてツイートし、ブログTwitterで私に従うこと自由に感じます。

本番環境のReact appsへの完全な可視性

React applicationsのデバッグは、特に再現が困難な問題が発生した場合には困難になる可能性があります。 Reduxの状態の監視と追跡、JavaScriptエラーの自動表示、遅いネットワーク要求とコンポーネントのロード時間の追跡に興味がある場合は、LogRocketを試してください。 LogRocket Dashboard Free Trial Banner

LogRocketはwebアプリ用のDVRのようなもので、あなたのReactアプリで起こるすべてを文字通り記録します。 問題が発生した理由を推測するのではなく、問題が発生したときにアプリケーションがどのような状態であったかを集計して報告することがで また、LogRocketはアプリのパフォーマンスを監視し、クライアントのCPU負荷、クライアントのメモリ使用量などの指標を報告します。

LogRocket Reduxミドルウェアパッケージは、ユーザーセッションに追加の可視性レイヤーを追加します。 LogRocketは、Reduxストアからのすべてのアクションと状態をログに記録します。

あなたのReactアプリをデバッグする方法を近代化—無料で監視を開始します。

コメントを残す

メールアドレスが公開されることはありません。