とってもやさしいフロントエンド入門
はじめに
この記事は、フロントエンド初心者の方や、HTML / CSS / JS を学んだものの次に何を学べば良いのか分からない方に向けて、フロントエンドの基本的な用語や概念を解説した記事です。
といっても、全てをカバーするのは大変だと思ったので、私自身がフロントエンドの業務を行う上で知っておきたかったことをいくつかピックアップして書きました。今回は、ECMAScript・Babel・モジュール・DOM・SPA について解説していきます。
ECMAScript
以下の動画で、100秒で ECMAScript について解説しています!
手っ取り早く理解したい人はこちらを見てください。
この章では ECMAScript について深く知るために、まず JavaScript の歴史について解説します。
JavaScriptの歴史
JavaScript は、1995 年に Netscape Communications 社でプログラマーとして働いていた Brendan Eich(ブレンダン・アイク) 氏によって開発されました。
1995年にネットスケープ・コミュニケーションズ(Netscape Communications)社(当時)のブランダン・アイク(Brendan Eich)氏によって開発され、当時最も人気の高いWebブラウザだった「Netscape Navigator 2.0」に初めて実装された。
1990 年代前半、JavaScript が誕生する前の Web ページは、主にテキストや画像が表示されるだけの、いわゆる静的なページがほとんどでした。Web ページが「動かない」のは当たり前で、ユーザーが行うインタラクティブな操作は、リンクをクリックする程度に限られていました。ただし、当時 Web ページに「動き」を付ける手段がまったく無かったわけではありません。
例えば、1993 年に登場した「CGI」と呼ばれる技術を使えば、チャットや掲示板、アクセスカウンターなどのような Web コンテンツを(サーバーサイドのちから[1]を借りて)動的に生成することができましたし、「Javaアプレット」と呼ばれる技術を使えば、Java で作ったプログラムを Web ページの中に埋め込むこともできました。しかし、これらの技術はいずれも処理が重くなりがちだった上に、使える人が高度な技術を持ったプログラマーたちに限られていたため、あまり一般的に普及することはありませんでした。
そこで、当時 Netscape Communications 社に所属していた Brendan Eich 氏は、Java よりも軽量で、かつ素人のプログラマーでも手軽に扱えるような言語を作るべく、JavaScript の開発をはじめました。Brendan Eich 氏は、1995 年の 5 月に JavaScript のプロトタイプ版を作成し、その翌年に自社のブラウザである Netscape Navigator のバージョン 2.0 に搭載する形で JavaScript をリリースしました。
1995 年の時点で、Netscape Navigator のブラウザシェアは圧倒的でした。しかし、当然それを面白く思わない企業もいました。ライバル社の Microsoft です。Microsoft 社は、JavaScript が生まれる数ヶ月前に「Internet Explorer」というブラウザをリリースしたばかりで、Netscape Navigator のシェア率にできるだけ早く追いつく必要がありました。
Microsoft 社は、Netscape Communications 社が開発した JavaScript を自社のブラウザである Internet Explorer に組み込むことで、より多くのユーザーを獲得しようとしました。しかし、Netscape Communications 社は自分たちの優位性を保つために、JavaScript のライセンス供与を認めませんでした。そこで困った Microsoft 社は、JavaScript によく似た「JScript」という言語を独自に作り出したのです。
最初のうちは、JScript と JavaScript は、それなりに互換性を持っていました。しかし、両社の争いが激化していくと、お互いが独自の機能を詰め込むようになり、次第に互換性の無さが目立つようになりました。その結果、書いたコードが Netscape Navigator では動くけれど Internet Explorer では動かない、なんてことが頻繁に起こるようになりました。
そこで、この問題を解決するために登場したのが「Ecma International」です。Ecma International は、情報や通信技術の分野の規格を策定する国際的な標準化団体で、当時乱立していた JavaScript の実装を一つにまとめるために動き出しました。
Ecma International は、「JavaScript」と「JScript」の共通する部分を抜き出し、それをベースに標準的な仕様を策定しました。こうして作り出された新しい仕様は「ECMAScript」と呼ばれ、各ブラウザベンダーはこの ECMAScript に沿って JavaScript を実装することが基本方針となりました。
ECMAScriptの仕様策定プロセス
前述のとおり、JavaScript の仕様は「Ecma International」と呼ばれる団体によって策定されています。この Ecma International の中には、実はさまざまな専門委員会が存在しており、ECMAScript を策定する委員会は「TC39(Technical Committee 39)」という名称で呼ばれています。
TC39 のメンバーは、Microsoft、Mozilla、Google、Apple などのブラウザを開発している企業や、Facebook、Adobe、PayPal、Salesforce などの ECMAScript に関心のある企業たちによって構成されています。これらの企業たちは、毎年 1 回のリリースに向けて 2 ヶ月ごとにミーティングを行い、新しい機能や仕様の変更について議論・決定します。
では、実際にどのような流れで仕様改訂が行われるのかを見ていきましょう。
ステージ | ステージ名 | 説明 |
---|---|---|
0 | Strawman | アイデアの段階 |
1 | Proposal | 機能提案・検討が進めている段階 |
2 | Draft | 暫定的な仕様が作成された段階 |
3 | Candidate | 仕様がほぼ完成していて、ブラウザが実験的に実装している段階 |
4 | Finished | 仕様策定が完了した段階 |
まず、新しいアイデアが提案されると、ステージ0の「Strawman」と呼ばれる段階に入ります。ステージ0のアイデアが価値のある提案として見なされ、大まかな形で問題点や解決策を説明できるようになると、ステージ1の「Proposal」と呼ばれる段階に進みます。そして、提案がある程度まとまって仕様の草案として認められると、ステージ2の「Draft」と呼ばれる段階に上がります。さらに細かいところまで練り上げられて、仕様がほぼ完成した状態になると、ステージ3の「Candidate」の段階になります。最後に、2つ以上のブラウザがその機能を実装していて、ECMAScript の編集者に承認されると、ステージ4の「Finished」と呼ばれる段階になります。
ステージ4に上がった提案は、毎年 6 月のタイミングで ECMAScript の新しいバージョンとしてリリースされます。リリースする際は、ECMAScript 20XX
(ES20XX)というように、バージョン名に西暦を付けるのがルールとなっています。また、先ほど述べたとおり、ステージ4に上がるためには『2つ以上のブラウザがその機能を実装している』ことが必要です。そのため、一部のブラウザでは正式な ECMAScript になる前に、その機能を先取りして実装していたりします。もしこれらの機能を試しに使用してみたい場合は、次の章で解説する JavaScript コンパイラーの『Babel』を使うことをおすすめします。
参考文献
- JavaScript Primer - ECMAScript
- uhyohyo.net - JavaScript初級者から中級者になろう
- サバイバルTypeScript - ECMAScript
- ToyFish.Net - スクリプト言語「JScript」
- atmarkit - いまさら聞けないJavaScript入門
- atmarkit - ECMAScriptの最新情報を得るには
Babel
以下の動画で、100秒でトランスパイラについて解説しています!
手っ取り早く理解したい人はこちらを見てください。
「Babel」は、主に ECMAScript 2015+ コードを、古いブラウザまたは環境で実行できる下位互換バージョンの JavaScript に変換するために使用される JavaScript コンパイラーです。
Babel is a toolchain that is mainly used to convert ECMAScript 2015+ code into a backwards compatible version of JavaScript in current and older browsers or environments.
Babelの登場背景
前章の『ECMAScript』で述べたとおり、ECMAScript の新しいバージョンは毎年リリースされています。新しい機能が ECMAScript に追加されると、(一部の)エンジニアはそれらの機能をすぐにでも利用したいと考えるかもしれません。しかし、新しい ECMAScript の仕様がリリースされたからといって、その内容がすぐにブラウザに反映されるとは限りません。全てのブラウザに完全に実装されるまでには時間がかかる場合があります。
例えば、ES6(ES2015)では、let、const、アロー関数、クラス、Promise、モジュールなど、多くの新しい機能が追加されました。これらの機能は、これまでの JavaScript の弱点を補うような魅力的なものばかりでしたが、古いブラウザ(とくに Internet Explorer)ではなかなか実装されず、ES5 から ES6 に移行できないという課題が発生していました。
I learnt of this new version of JavaScript called ES6 that was in the process of being drafted. “Woah”, I thought. (…) How could I use this? No browser supported it and it was going to be years before I could reliably use it.
(訳)ES6というJavaScriptの新バージョンが策定されつつあることを知りました。「これはすごい」と思いました。 (…) これはどうやって使うんだ?どのブラウザもサポートしていないし、確実に使えるようになるまでには何年もかかりそうだった。
そこで、この課題を解決するために登場したのが「Babel」です。Babel は、ざっくり簡単に言うと、新しい ECMAScript 構文を古い ECMAScript の構文に変換するツールです。例えば、次の画像のように、const
とアロー関数を使用して書いたコードを、var
と 通常の関数式を使用して書いたコードに変換することができます。
Babel はもともと「6to5」という名前で呼ばれ、ES6 のコードを ES5 に変換するために開発されました。しかし、現在では ES6 に限らず、最新の ECMAScript の構文や、ブラウザが解釈できない JSX などの構文もサポートされています。このように Babel を利用することで、私たちエンジニアは古いブラウザに対応しつつも、ブラウザに実装されていない JavaScript の新しい構文を自由に使うことができます。
参考文献
モジュール / CommonJS / モジュールバンドラー / ESM
以下の動画で、100秒でモジュールバンドラーについて解説しています!
手っ取り早く理解したい人はこちらを見てください。
「モジュール」とは、ある特定の機能を実現するためのプログラムの塊のことを指します。
モジュールとは、ハードウェアやソフトウェアにおける、ひとまとまりの機能・要素のことである。ソフトウェアにおいては、ある機能を実現するプログラムの塊を指す場合に用いる。
モジュールとは
通常、Web アプリケーションの規模が大きくなると、JavaScript のコードも肥大化します。1 つのファイルに全てのコードを詰め込むと、コードの見通しが悪くなったり、保守性や再利用性が低下してしまう恐れがあります。
そのため、Web アプリケーションを開発する際は、プログラムを機能ごとなどの適切な単位に分割するのが一般的です。この分割された 1 つ 1 つのプログラムの塊のことを「モジュール」と呼びます。
多くのプログラミング言語には、モジュールを扱うための仕組みや構文があらかじめ用意されています。例えば、Python という言語には import/export 構文があり、これを使用することでモジュールを読み込んだり、逆に公開したりすることができます。しかし JavaScript においては、つい最近まで言語レベルのモジュール構文は存在しませんでした。Pyhon のような import/export 構文が JavaScript の標準でサポートされるようになったのは、2015 年(ES2015)からの話です。
通常、モジュールはクラスや便利な関数のライブラリを含みます。長い間、JavaScript には言語レベルのモジュール構文は存在しませんでした。
では、それまでは一体どうやって JavaScript でモジュール構文無しで開発を行っていたのでしょうか?この疑問を解決するために、この章では JavaScript のモジュールの歴史について詳しく見ていきたいと思います。
モジュールの歴史
JavaScriptの誕生
そもそも JavaScript は、1995 年に Web ページにちょっとしたインタラクティブな機能を追加するために誕生しました。
JavaScript のプログラムはとても小さいものから始まりました。初期の用途は、必要に応じてウェブページにちょっとした対話的な機能を追加する独立したスクリプト処理がほとんどであったため、大きなスクリプトは通常必要ありませんでした。
『JavaScript の歴史』の章でも解説しましたが、1990 年代前半の Web は、テキストや画像などが表示されるだけの、いわゆる静的なページがほとんどでした。動きのある Web ページは皆無ではありませんでしたが、実装するには CGI や Javaアプレットのような、難しいプログラミングの知識が必要でした。しかし、それでは実装できる人たちが一部のプログラマーたちに限られてしまうため、より手軽で習得しやすいプログラミング言語が必要とされました。そこで開発されたのが JavaScript です。
当時の JavaScript は、大きなプログラムを書くというよりも、どちらかというと Web サイトにちょっとした動きや効果を与えるために開発されました。先述したとおり、JavaScript は「手軽で習得しやすい」ことを重視して作り出された言語なので、本格的な Web アプリケーションで利用されることは想定されていませんでした。そのため、他のプログラミング言語が当たり前のように持っている「モジュールシステム(コードから別のファイルを読み込む仕組み)」も JavaScript には用意されていなかったのです。
しかし、時代が進むにつれて、JavaScript を使った Web の開発がメインになってくると、当然、モジュールシステムの欠如で困る場面が増えてきました。そこで、困った当時のプログラマーたちは、以下のように HTML ファイルの中に複数の <script>
タグを埋め込むことで、他の JavaScript ファイルの読み込みを実現していました。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<title>Title</title>
</head>
<body>
<h1>Hello world!</h1>
<!-- ここに script タグを列挙 -->
<script src="foo.js"></script>
<script src="bar.js"></script>
<script src="main.js"></script>
</body>
</html>
ただし、この方法には 依存関係を自分で解決しなければならない という問題がありました。
例えば、次の図で示されているように、foo.js と bar.js に定義された関数を main.js で使用している場合、上記の HTML のように、<script>
タグで js ファイルを読み込む順番は、必ず「foo.js と bar.js の後ろに main.js が来る」順番にしなければなりません。なぜなら、main.js を先に読み込むと、foo
と bar
関数が未定義でエラーになってしまうからです。
今回の説明の例では、<script>
タグを使ったファイルの読み込みは 3 つしかないので、この問題はそれほど深刻には見えないかもしれません。しかし、読み込むファイルが数十や数百と増えてくると、どのファイルがどのファイルに依存していて、どの順番で <script>
タグを配置する必要があるのか、すべて自分で管理しなければならないのは、かなり大変な作業になります。
CommonJSの登場
そこで、この問題を解決するために 2009 年に登場したのが「CommonJS」というプロジェクトです。
CommonJS はもともと、「JavaScript 最高!サーバーサイドでも JavaScript を使いたい!」という人たちが、Mozilla のエンジニアだった Kevin Dangoor 氏のもとに集まって出来たプロジェクトです。当初は、サーバーサイドの仕様 "だけ" を定める目的で「ServerJS」という名前が付けられましたが、後にサーバーサイドよりも広い範囲で仕様を定めることを目標に「CommonJS」という名前に改称されました。
といっても、この CommonJS というプロジェクトで作られたものは、あくまでも JavaScript の仕様に過ぎません。この仕様に沿って実装されたのが、「Node.js」と呼ばれるサーバーサイド JavaScript の実行環境です。
CommonJS の大部分はモジュールに関する仕様だったので、Node.js を利用すれば、他の言語と同じように JavaScript でモジュールの読み込み / 公開ができるようになりました。例えば、Node.js でモジュールを読み込みたい場合は、次のように require
を使用します。
const fooFunc = require("./foo.js")
fooFunc()
そしてモジュールをエクスポートしたい場合は、module.exports
(または exports)を使用します。
module.exports = function fooFunc() {
console.log("Hello World from foo!");
}
繰り返しになりますが、これは Node.js 上でモジュールを扱うための仕組みです。Node.js では完璧に上手くいくのですが、この仕組みを使ってブラウザでも同じように動かそうとすると、「require is not defined」というエラーがコンソールに表示されてしまいます。
しかし、当時は Node.js で作られた便利な npm のパッケージが世の中にたくさん公開されていたので、それらをブラウザ上でも利用したいと考える人が大勢いました。そこで誕生したのが「Browserify」というモジュールバンドラーです。
モジュールバンドラーの登場
「Browserify」とは、2011 年に substack 氏によって作られたモジュールバンドラーです。
「モジュールバンドラー」とは、名前の通り、モジュールをひとまとめにするツールのことを指します。
モジュールバンドラーとは、JavaScriptのモジュール依存関係を解決し、複数のモジュールを1つのJavaScriptファイルに結合するツールのことです。 モジュールバンドラーは起点となるモジュールが依存するモジュールを次々にたどり、適切な順序になるように結合(バンドル)します。
前述のとおり、CommonJS の登場によって、サーバーサイドの JavaScript ではモジュールを快適に扱うことができるようになりました。問題は、ブラウザ上では CommonJS 形式のモジュールがサポートされていないので、実行時に「require is not defined」というエラーが出てしまうことです。
それならば、ブラウザ上で require
を使わなくても済むように、あらかじめ複数の JavaScript ファイルを結合(バンドル)し、ブラウザが解釈可能な 1 枚の JavaScript ファイルを作っておこう、という発想が生まれました。これが「モジュールバンドラー」というツールの考え方です。
例えば、上記の左側の図には、main.js
・foo.js
・bar.js
という 3 つのファイルが存在します。モジュールバンドラーの役割は、各ファイルの中で require
が使われている部分を芋づる式に探し出して、ファイル同士を適切な順序で結合し、最終的に 1 枚の JavaScript ファイルを作り出すことです。このとき作り出されたファイル(図でいう bundle.js)の中には、require
は含まれません。
生成された JavaScript ファイルは、以下のように HTML 内で利用することができます。
<!-- bundle.js はモジュールバンドラーが出力した JavaScript ファイル-->
<script src="bundle.js"></script>
そうすることで、たとえ CommonJS 形式で記述されたプログラムであっても、ブラウザ上で自由に実行できるようになります。
ESMの登場
さて、モジュールバンドラーが登場したことによって、Node.js だけではなくブラウザ上でも CommonJS 形式のモジュールが利用できるようになりました。これでようやく、ブラウザの世界にも "モジュールシステム" がもたらされたのです。
しかし、CommonJS というのは元々 Kevin Dangoor 氏らが中心となって作り出した独自の JavaScript の仕様です。なので当然、当時のプログラマーたちの間では『標準的なモジュールシステムを使いたい』というニーズがありました。
そこで登場したのが「ECMAScript Modules」です。ECMAScript Modules は、2015 年の ES2015(ES6)のときに策定されたモジュールシステムで、略して「ES Modules」や「ESM」などと呼ばれます。(この記事では、以降 ESM と呼びます。)
この ESM の登場によって、ブラウザではモジュールの読み込み / 公開の記法が、より直感的に書けるようになりました。皆さんお馴染みの import / export 構文です。実際に、以下のファイルをブラウザに読み込ませてみましょう。「Hello World from foo!」という文字がコンソールに表示されるはずです。[2]
<html lang="ja">
<body>
<!-- ESMを利用するときは、 type="module" を必ず付ける必要がある-->
<script type="module">
import { fooFunc } from './foo.js'
fooFunc()
</script>
</body>
</html>
function fooFunc() {
console.log("Hello World from foo!");
}
export { fooFunc };
他にも、ESM を使うと良いことが色々あります。具体的には次のとおりです。
-
デフォルトで Strict モードが ON になる
Strict モードとは、JavaScript の古くて安全ではない構文の書き方を制限するためのモードのことです。通常、ファイルの先頭に"use strict";
と書くことで、そのファイル全体を Strict モードにすることができますが、ESM ではこの Strict モードが自動的に有効になります。 -
トップレベルで
await
が使用できるようになる
通常のスクリプトでは、await
式はasync
関数の中でないと使用できませんが、ESM の場合は、トップレベル(つまりasync
関数の外)でも利用可能になります。これによって、ちょっとしたコードを試したい時などに、async
関数をわざわざ用意する必要がなくなります。 -
静的解析が可能になる
ESM では、ファイルを静的に解析したあと、非同期で並行にモジュールを読み込んで実行します。もしシンタックスエラーなど(import するファイルのパスを間違えてたとか)があった場合は、実行前にエラーを出してくれるので、早めにエラーを検知することができます。
ところで、ESM が登場したのなら、モジュールバンドラーはもう要らなくなるのでは?と思いますよね。(私はそう思いました。)いいえ、そんなことはありません。モジュールバンドラーはまだまだ色んな現場で活躍しています。
では、なぜモジュールバンドラーは今でも必要とされているのでしょうか。最後にその理由をお話して、この章を終わりにしようと思います。
モジュールバンドラーが必要な理由
モジュールバンドラーが今でも使われている理由の一つに、Web アプリケーションのパフォーマンス低下を防ぐことが挙げられます。
例えば、モジュールバンドラーを使わずに ESM をネイティブ実行させた場合、次の図のように、ファイル読み込みのための往復が多数発生してしまいます。
一般的には、以下の引用にもあるとおり、クライアントとサーバー間のやりとりは 2 往復で済ませるのが理想的です。しかし、モジュールバンドラーを使わない場合、プロジェクトの規模によっては往復回数が数百や数千にも及ぶ可能性があります。
ウェブサイトのパフォーマンス最適化においては、2往復で全て済ませるのが基本的な原則です。具体的には、最初の1往復でHTML文書が帰ってきて、それにURLが載っているJavaScriptファイルを2往復目で取得します
これを避けるために、あらかじめ多数の細かいファイルを 1 つのファイルにバンドルしておきます。サーバーから取得するファイルが 1 つだけであれば、通信にかかる時間も節約できるため、パフォーマンス(表示速度)を落とさずに済みます。
ただし、何も考えずにとりあえずファイルを一つにバンドルしてしまうと、逆にバンドルサイズが大きすぎて初回読み込みに時間がかかってしまう可能性もあるので、注意が必要です。
参考文献
- JS モジュール三國志(from りあクト!)
- uhyohyo.net - JavaScript初級者から中級者になろう
- 歴史から見るTypeScriptにおけるwebpackとBabelの必要性
- Web Development History
- ZDNet - 誕生から25年を迎えたJavaScript--業界に多大な影響力を持つプログラミング言語に
- Modern JavaScript Explained For Dinosaurs - Peter Jang
- なぜJavaScriptには2つもモジュールシステムが混在しているのですか?(ES ModulesとCommonJS)
- webpackとBabelの基本を理解する(1) ―webpack編―
- サイボウズエンジニアのブログ
DOM
以下の動画で、100秒でDOMについて解説しています!
手っ取り早く理解したい人はこちらを見てください。
DOMとは
「DOM」とは、Document Object Model の略で、HTML や XML などの文書を JavaScript のようなスクリプト言語から取り扱うためのプログラミング API です。
The Document Object Model (DOM) is a programming API for HTML and XML documents. It defines the logical structure of documents and the way a document is accessed and manipulated.
(訳)Document Object Model (DOM) は、HTML および XML 文書のためのプログラミング API です。ドキュメントの論理構造と、ドキュメントへのアクセスや操作の方法を定義しています。
通常、ユーザーが Web サイトにアクセスすると、ブラウザはサーバーに対してリソース(ファイル)を要求します。要求を受けたサーバーは、HTML ファイルを最初に返します。
ブラウザは HTML ファイルを受け取っても、それをそのまま解釈することはできません。そのため、ブラウザは受け取った HTML ファイルを解析したら、メモリー上でツリー状のデータ構造に変換します。このとき作られる木構造のデータのことを「DOMツリー」と呼びます。
DOMツリーの中では、HTML のあらゆる部分が「ノード」という単位で区切られます。例えば、 HTML のタグ、テキスト、属性などはすべてノードです。ノードにはいくつかの種類があって、先ほど登場した DOMツリーの図をノードの種類ごとに色分けすると、次のようになります。
DOMツリーの構造は、Web ページに表示されているコンテンツと密接に結びついています。そのため、DOMツリーのノードを更新すると、それに応じて Web ページの表示も自動的に変化します。JavaScript を使用すると、DOMツリーから任意のノードを取り出して、編集・削除・追加などの操作をすることができます。このように、実際の Web ページに表示されているコンテンツを動的に変更するために、DOMツリーのノードを操作する作業のことを「DOM操作」と呼びます。
参考文献
- これ1冊でゼロから学べる Webプログラミング超入門 ーHTML,CSS,JavaScript,PHPをまるごとマスター
- techpit - Webサイトはどうやって表示される?
- atmarkit - 正しいHTMLとドキュメントツリーを理解しよう
SPA
「SPA」とは、Single Page Application の略で、単一の HTML ページを読み込んで、ユーザーのアプリケーション操作に合わせてページを動的に更新する Web アプリケーションのことです。
Single Page Application は、単一の HTML ページを読み込んで、ユーザーのアプリケーション操作に合わせてページを動的に更新する Web アプリケーションです。
SPAとは
従来の Web アプリケーション(Multi Page Application)では、ユーザーが何らかの操作を行ってクライアント側からリクエストが送信されると、サーバー側はそのたびにその操作に応じて適切な Web ページの情報(HTML / CSS / JavaScript など)を送信していました。
そして、クライアント側はサーバー側から Web ページの情報を受け取ると、それをもとに Web ページの内容を毎回まるごと書き換えていました。このため、ユーザーは通信のたびに Web ページが完全に切り替わるのを待ってから、次の操作を行わなければなりませんでした。
そこで、この問題を解決するために登場したのが「SPA(Single Page Application)」です。SPA は、名前のとおり単一の Web ページで構成される Web アプリケーションのことで、「CSR(Client Side Rendering)」と呼ばれるクライアント側でのレンダリング技術を使って、Web ページのコンテンツの一部を動的に書き換えます。
具体的な CSR の流れは、次のようになります。
- 初回のリクエストを送信
- サーバー側は Web ページの情報(HTML / CSS / JavaScript など)をレスポンス
- クライアント側で HTML を描画
- API サーバーに必要なデータをリクエスト
- クライアント側に必要なデータをレスポンス
- JavaScript の DOM操作 で差分を更新
上記の ①〜③ までは、従来の Web アプリケーションと同じです。初回アクセス時のみ、HTML / CSS / JavaScript などの情報を読み込みます。そして JavaScript の読み込みが完了したら、④〜⑥ の部分が実行されます。その後は、ユーザーからの操作に応じて ④〜⑥ の部分が再び繰り返されます。
もし、ヘッダーやフッターなどの全ページ共通のパーツがある場合、CSR では、これらのパーツは書き換えられずにそのまま保持されます。そしてページ遷移の際は、それ以外のパーツを変更していきます。そうすることで、ユーザーはページ遷移のたびに Web ページ全体の再読み込みを待つこと無く、より快適にアプリケーションを操作することができるようになります。
CSRの問題点
しかし、CSR には問題点もあります。それは、初回のページの表示速度が遅いという点です。
というのも、CSR では初回リクエスト時に、まず HTML ファイルをダウンロードするのですが、 この HTML の中身はほとんど "空っぽ" のようなものなので、初期表示では何も表示されません。
<html>
<head>
<meta charset="utf-8" />
<title>Title</title>
<script defer="defer" src="/static/js/main.0215976b.js"></script>
</head>
<body>
<div id="root"></div>
</body>
</html>
例えば、上記の HTML で考えてみましょう。通常、HTML の <body>
タグの中には、ユーザーに表示させたい Web ページの内容を記載するのですが、上記のコードの中には、<div id="root"></div>
という空の div タグ が 1 つ含まれているだけで、他には何もありません。つまり、<body>
タグの中身はほとんど "空っぽ" の状態だと言えます。
CSR では、JavaScript がロード・実行されるまでの間は、この <body>
タグに書かれた内容がユーザーの画面上に表示されます。<body>
タグの中身が空っぽだと、初期表示で表示される内容も真っ白になるため、ユーザーに少なからずストレスを与える可能性があります。
そのため、この問題を避けるべく「SSR」と呼ばれるレンダリング技術が登場しました。次の章では、この SSR について詳しく解説していきたいと思います。
SSRとは
前章の『CSRの問題点』でも解説したとおり、CSR には初回のページ表示に時間がかかるという問題があります。この問題を解決するために登場したのが「SSR(Server Side Rendering)」です。
サーバーサイドレンダリング(SSR)はウェブページのレンダリングをブラウザの代わりにサーバー上で行う、画面の表示において有用なアプリケーションの機能です。サーバーサイドは完全にレンダリングされたページをクライアントに送信します。
SSR では、初回アクセス時のみサーバー側で JavaScript の実行と HTML 生成を行い、それ以降のアクセスでは、クライアント側でページの差分更新を行います。
具体的には、次のような流れになります。
- 初回のリクエストを送信
- サーバー側で JavaScript を実行
- API サーバーに初期データをリクエスト
- 初期データをレスポンス
- サーバー側で HTML を生成
- レンダリング済みの HTML / CSS / JavaScript などをレスポンス
- クライアント側で JavaScript を実行
- 差分の更新のために必要なデータをリクエスト
- クライアント側にデータをレスポンス
- JavaScript の DOM操作 で差分を更新
②〜⑤ のとおり、SSR では初回アクセス時に、サーバー側で JavaScript を実行し、その結果から HTML ファイルを動的に生成します。そして ⑥ の部分で、完成された状態の HTML ファイルをクライアント側に渡します。ただし、このときの HTML はあくまでも "見た目" だけしかないので、Web ページをインタラクティブにさせるためには、⑦ で 必要最小限の JavaScript コードを実行する必要があります。⑦ が完了して Web ページが完全に表示されたら、あとは CSR の挙動と同じです。ユーザーからの操作(画面遷移)に応じて、⑦〜⑩ の部分が繰り返されます。
SSR では、ファーストビューが表示されても、JavaScript が実行されない限り、インタラクティブな画面にはなりません。そのため、実際にユーザーが操作できるまでの時間は、CSR と比べると大して変わらないかもしれません。しかし、Web ページが表示されるまでの単純な待ち時間は CSR よりもかなり短くなります。そのため、SSR では CSR よりもユーザーのストレスをより軽減することができます。
参考文献
- Real World HTTP 第2版 ―歴史とコードに学ぶインターネットとウェブ技術
- Server Side Renderingについて知るべきこと。Server Side Renderingとは何か? それによって何が改善されるのか? - Publickey
- SSG と SSR で理解する Next.js のページレンダリング
- atmarkit - SPA(シングルページアプリ)
- atmarkit - ゼロから学ぶ! Single Page Applicationの特徴と主なフレームワーク5選 - ITmedia
- SPA, SSR, SSGって結局なんなんだっけ?
- 7839 - Client Side Rendering(SPA)・SSR・SSG を整理してみた
さいごに
過去にこんな記事も投稿しています。興味ある方は是非見ていってください。
-
より厳密にいうと、CGI とは、Common Gateway Interface の略で、Web サーバがブラウザからの要求に応じて外部のプログラムを実行して、その処理結果をブラウザに送信する仕組みのことです。詳しくはこちらを参照 ↩︎
-
ローカルから(
file://
という URL を使って)HTML ファイルを読み込もうとすると、セキュリティ上の理由で CORS エラーが発生します。なので、コードを実行する際は、サーバー経由で行う必要があります。簡単にサーバー経由で実行できるおすすめの方法は、VSCode の Live Server を使うことです。インストール後、右下に表示される「Go Live」というボタンをクリックすると、ブラウザで localhost:5500 が開かれます。 ↩︎
Discussion
コメントから失礼致します!
すごく有意義な記事をご拝見させていただいてありがとうございます!
なんだこの素晴らしい記事は・・・。
フロントエンド入門者の私に刺さる記事でした。
ありがとうございます。