はじめに
SSR(Server-Side Rendering)は新しい概念ではなく、フロントエンドとバックエンドの層別化以前の長い期間、サーバーサイドレンダリングが主流でした(JSP、PHP)。サーバー側で完全な HTML ページを生成します
(フロントエンドレンダリングモードの探求 から引用)
つまり、SSR から CSR への大変革を経て、今や再び CSR から出発して SSR の可能性を探求しています……まるで巡り巡って起点に戻ったようです。この間に何が起こったのでしょうか?今の SSR と当時の JSP、PHP にはどのような違いがあるのでしょうか?
一.SSR が大行其道
フォーラム、ブログ、チャットルームがまだ活発だった時代に戻ると、業界のベストプラクティスは JSP、PHP、ASP/ASP.NET に基づくダイナミックウェブサイトでした
PHP を例にすると:
<?php if ( count( $_POST ) ): ?>
<?php include WTG_INCPATH . '/wechat_item_template.php' ?>
<div style="...">
<div id="wechat-post" class="wechat-post" style="...">
<div class="item" id="item-list">
<?php
$order = 1;
foreach ( $_POST['posts'] as $wechat_item_id ) {
echo generate_item_list( $wechat_item_id, $order );
$order++;
}
?>
</div>
<?php
$order = 1;
foreach ( $_POST['posts'] as $wechat_item_id ) {
echo generate_item_html( $wechat_item_id, $order );
$order++;
}
?>
<fieldset style="...">
<section style="...">
<p style="...">如果心中仍有疑问,请查看原文并留下评论噢。(<span style="font-size:0.8em; font-weight:600">特别要紧的问题,可以直接微信联系 ayqywx</span>)</p>
</section>
</fieldset>
</div>
<script>
function refineStyle () {
var post = document.getElementById('wechat-post');
// ul ol li
var uls = post.getElementsByTagName('ul');
for (var i = uls.length - 1; i >= 0; i--) {
uls[i].style.cssText = 'padding: 0; margin-left: 1.8em; margin-bottom: 1em; margin-top: -1em; list-style-type: disc;';
uls[i].removeAttribute('class');
};
}
document.addEventListener('DOMContentLoaded', function() {
refineStyle();
});
</script>
</div>
<?php endif ?>
(ayqy/wechat_subscribers から引用。微信公衆平台図文消息自動生成 に使用する WordPress プラグイン)
この時期、ウェブページの内容は完全にサーバー側でレンダリングされ、クライアント(ブラウザ)が受信するのはサービスデータが融合された HTML と、少量のインライン(フォーム)インタラクションロジックとスタイルルールでした。早期の大量なダイナミックウェブサイトを支えていたのは、この純粋な SSR モードでした
しかし、技術実践の深化に伴い、このモードは徐々にいくつかの問題を露呈しました:
-
性能が悪い:すべてのリクエストが来るたびにデータロジックとビューロジックを再度実行し、HTML を動的に生成する必要がある。その中で很大一部分の内容は同じであるにもかかわらず
-
マシンコストが高い:Tomcat/Apache などのアプリケーションサーバーの並行処理能力は [nginx](/articles/nginx-https 反向代理/) などの Web サーバーに遠く及ばない。そのため、より多くのマシンをデプロイする必要がある
-
開発/維持が困難:フロントエンドとバックエンドのコードが混在しており、人員協力が問題となり、修正維持には非常に慎重である必要がある(タグ構造が破壊されやすい)
これらの問題に直面し、2 つの思路が徐々に明確になってきました。動静分離と前後端層別化です。前者は性能とマシンコストの問題を解決し、後者は開発/維持の問題を解決します
二.動静分離
Web サーバーの静的リソース処理優勢を十分に活用し、同時にアプリケーションサーバーの負担を軽減するために、リソースを 2 つの類別に分けます:
-
静的リソース:画像、CSS、JS などの公用で、具体的なユーザーと無関係なリソース
-
動的リソース:アプリケーションロジック、データ操作など具体的なユーザーと密接に関連するリソース
2 つのリソースを分开してデプロイし、静的リソースを Web サーバーまたは CDN にデプロイし、アプリケーションサーバーには動的リソースのみをデプロイします。このようにすれば、静的リソースの响应が更快くなり(ブラウザキャッシュ、CDN 加速)、アプリケーションサーバーの圧力が小さくなり、皆が喜びます
しかし、ビューロジックが抜けていました。HTML は静的リソースと動的リソースのどちらに算定されるのでしょうか?
前後端層別化はこの問題に答えるためのものです
三.前後端層別化
ビューロジックの特殊な点は:
-
データと密接に関連
-
サーバー側とクライアント側の両方でビューロジックを承载可能
つまり、HTML ビュー構造の作成と維持作業は、サーバー側で完成することも、クライアント側で完成することもでき、どちらもサービスデータに依存します。しかし、サーバー側と比較して、クライアント側環境にはいくつかの優勢があります:
-
刷新(ページを再リクエスト)なしでビューを更新可能
-
無料の計算リソース
したがって、ビューロジックはクライアント側に划分されました(つまり CSR)。データインターフェースを境界として、前後端の 2 層に分かれます:
-
バックエンド:データおよびデータ操作サポートを提供
-
フロントエンド:データの提示とインタラクション機能を担当
自此、前後端は各々その職を尽くし、フロントエンドはユーザー体験の向上に尽力し、バックエンドは業務領域に専念し、並行イテレーションを行い、(インターフェース変化を涉及しない場合)互いに影響しません
四.CSR が如日中天
前後端層別化の後、CSR の黄金時代に入り、機能プラグイン、UI ライブラリ、フレームワーク、コンポーネントなどの多种類のコード复用方案を探索し出し、最終的に繁栄したコンポーネント生態を形成しました
コンポーネント化の開発方式の下で、純粋な CSR モードが日益盛行しました:
<!DOCTYPE html>
<html>
<head>
<title>My Awesome Web App</title>
<meta charset="utf-8">
</head>
<body>
<div id="app"></div>
<script src="bundle.js"></script>
</body>
</html>
このモードでは、ほぼすべてのページ内容がクライアント側で動的にレンダリングされます。ビュー作成、データリクエスト、データとテンプレートの融合、インタラクション機能を含むすべての作業を、1 セットのデータ駆動型コンポーネントレンダリングメカニズムに全権管理させ、コンポーネント以下の DOM 構造維持などの作業に注目する必要がなくなり、効果的にフロントエンドの生産効率を向上させました。しかし、いくつかの問題も随之而来しました:
-
コンポーネントツリーの初回レンダリング完了前に、ページ上には loading を含めたいかなる内容も表示できない
-
データリクエストは所属コンポーネントがレンダリングを開始してからでないと送信できない
これらの問題の根源は、現在のコンポーネントレンダリングフローは同期ブロッキングであることで、首屏性能に挑戦を提起しました:
-
低端設備では JS 実行効率が低く、白屏時間が長い
-
弱網環境ではデータ返回が遅く、loading 時間が長い
CSR はユーザー設備の計算リソースを利用しましたが、同時にその性能、ネットワーク環境などの不可控要因の制約も受けました。そこで、大家は再び目光を SSR に聚集させました
五.SSR が東山再起
SSR モードでは、首屏内容はサーバー側で生成され、クライアントは响应 HTML を受信した後、コンポーネントツリーのレンダリング完了を待つことなく直接内容を呈現できます
核心的思想はどちらもサーバー側でページレンダリング作業を完成することですが、今の SSR は先前と大きく異なります。体现在:
-
出発点:更快、より安定して首屏内容を呈現するため
-
成熟度:フロントエンドの成熟したコンポーネント体系、モジュール生態の上に建立され、Node.js に基づく同構方案がベストプラクティスとなった
-
独立性:仍然として前後端層別化を維持し、業務領域のアプリケーションサービスと強耦合しない
つまり、今の SSR はフロントエンド層の問題を解決するためにあり、CSR と結合して内容ロード体験を最適化するもので、CSR の多年の積淀の上での拡張であり、既存のフロントエンド技術生態と良好な相容性を維持しています。一方、当時の SSR は更多的是機能を実現し、温飽問題を解決するためでした
再看当時の SSR が直面したいくつかの問題:
-
性能が悪い:すべてのリクエストが来るたびにデータロジックとビューロジックを再度実行し、HTML を動的に生成する必要がある。その中で很大一部分の内容は同じであるにもかかわらず
-
マシンコストが高い:Tomcat/Apache などのアプリケーションサーバーの並行処理能力は [nginx](/articles/nginx-https 反向代理/) などの Web サーバーに遠く及ばない。そのため、より多くのマシンをデプロイする必要がある
-
開発/維持が困難:フロントエンドとバックエンドのコードが混在しており、人員協力が問題となり、修正維持には非常に慎重である必要がある(タグ構造が破壊されやすい)
SSR を導入した後、これらの問題が巻土重来しました。しかし、これらの年の技術発展はこれらの問題を解決するための新しい思路を提供しました:
-
リアルタイムレンダリングの性能問題:動静分離の思路仍然として適用可能。例えば Static Generation
-
サーバーリソースコスト問題:クラウド計算の発展はマシンコストを大幅に低減する見込み。例えば Node FaaS
-
SSR 部分と CSR 部分の開発/維持問題:同構は開発/維持難題の解決に新しい思路を提供しました(以前の思路は前後端層別化でしたが、今回は分けられません)。同一のコードを維持し、異なる実行環境で実行して異なる形式の目標産物を出力します
その中で、Static Generation(SSG、Static Site Generation とも呼ぶ)はコンパイル時に静的 HTML を生成し(CDN にデプロイ可能)、リアルタイムレンダリングの性能开销を回避します:
Static Generation (Recommended): The HTML is generated at build time and will be reused on each request.
しかし、すべてのページがコンパイル時に静的生成できるわけではありません。実行可能な実践方案は SSR と Static Generation を結合することで、内容が個別化データに依存する、または頻繁に更新されるページのみ SSR を行い、其余のシーンではすべて Static Generation を行います:
You should ask yourself: "Can I pre-render this page ahead of a user's request?" If the answer is yes, then you should choose Static Generation.
至此、沈寂多年の SSR は再び新しい活力を焕発しました
コメントはまだありません