inuinu blog(開発用)

BOT @wagagun の開発ノウハウや、IT向け?の雑記ブログです。

素のJavascript(Vanilla)だけでフロントエンド開発(11:共通部分組込編)

このページでは、ReactやVueではなく、Vanillaと呼ばれる素のJavascriptのみで、フロントエンド開発が可能であるか?を解説します。今回は共通部分の組み込みを考えます。

今回は、前回…

inuinu-tech.hatenablog.jp

の続きになります。

いきなりここにたどり着いたのでしたら、お手すきの際で構いませんので、下記の記事からも読んでみていただければ幸いです。

inuinu-tech.hatenablog.jp

今回の課題のゴールは?

今回は、メニューなど、共通部分の組み込みを考えてみます。

なお、以下の記事の「Vanillaでのフロントエンド構築を阻む、手間や制限について」や「これらの手間や制限を乗り越えるには?」にも、同様の内容があります。
併せてご覧ください。

inuinu-tech.hatenablog.jp

フレームワークを利用した組み込みについて

フロントエンド、バックエンドに関わらず、フレームワークは概ね似たような振る舞いをします。

HTMLの基本的な構成(共通箇所のみ)およびディレクトリ構成

フレームワークを利用した際の、メインのHTMLは、主にこのような形でしょうか。

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
(metaタグやlinkやscriptなどの共通部分を記載していく)
</head>
<body>
(ヘッダー項目を記載していく)
(サイドメニュー項目を記載していく)
<div id="app">
(ここに各プログラムの内容がインポートされる!)
</div>
(フッター項目を記載していく)
</body>
</html>

フロントエンド、あるいはバックエンドのフレームワーク問わず、雛形になるようなHTMLを所定の場所に1つ用意し、

<div id="app">
</div>

あるいは、

<%= yield %>

といった形で記入し、ルーターのアドレスに対応する、各プログラムソース(erbなど)を用意することで、共通化が図られます。
つまり、真ん中の部分だけがURLを変更する都度、変わっていきます。

フレームワークを利用しない場合は?

ディレクトリ構成

フレームワークを使用しない場合(素のHTMLで構築する場合)は、ディレクトリ構成がそのまま、URLに反映します。

HTMLの基本的な構成

各プログラムのHTMLは概ねこのような形になります。

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
(metaタグやlinkやscriptなどの共通部分を記載していく)
(各共通部分のローディングもここで行う)
(各プログラム固有のJavascriptも記載する)
</head>
<body>
<div id="header_area">
(ヘッダー項目が置き換わる)
</div>
<div id="menu_area">
(サイドメニュー項目が置き換わる)
</div>

(ここに各プログラムの内容を記載していく)

<div id="footer_area">
(フッター項目が置き換わる)
</div>
</body>
</html>

fetch()あるいはSSIという選択肢

フレームワークを使用しない場合、フレームワークはプログラム固有の部分がインポートされますが、素のHTMLでは、それとは対象的に、共通部分をインポートします。

SSI(Server Side Include)を利用した場合と、fetch()を利用した場合での違いがあります。

SSI Javascript(fetch)
HEADタグ内の共通項目
BODY内のヘッダー項目 ○静的 ○静的あるいは動的
BODY内のメニュー項目 ○静的 ○静的あるいは動的
BODY内のフッター項目 ○静的 ○静的あるいは動的

ヘッダー・メニューやフッターはfetch()で取得して表示

現状、fetch()を使用すれば、BODYタグ内の共通箇所のHTMLのインクルードは可能です。
例えば、ヘッダーメニュー、両サイドに表示されるリンクや統計情報、フッターと呼ばれる箇所です。<

こちらのidのheader_area、menu_area、footer_areaのinnerHTMLに、別途fetch()で入手したHTMLをセットしてあげれば、共通箇所の表示は可能です。

etch()ではJSONではなくTEXT情報も取得できるから…なのですが、セキュリティの脆弱性を名目に塞がれないことを祈るのみです。

Javascriptのインクルードはできません。

もし、セキュリティの名目でHTMLテキストのインクルードを塞がれた場合は、JSONで取得し、JavascriptでHTMLを組み立てることになりそうです。

画面AとA'が似ているので、共通箇所をインクルードするのもfetch()?

上記を応用すれば可能ですが、わかりにくくなりそうですね…

HEADタグ内はfetch()できない

BODYタグ内のHTMLはインクルードできそうですが、HEADタグ内で、各画面に共通のMATAタグやLINKタグ、SCRIPTタグをインクルードしたい!というニーズには、そのままでは対応できません。
例えば、こういったものですね。

<script src="hoge.js"></script>
<link href="hoge.css" rel="stylesheet">

HEADタグって思いの外長いですよね。そういったものを各ページに書くと、(機能数によっては)メンテンスが大変になりそうです…

こちらはSSI以外に選択肢はなさそうです…

SSIの具体例

問題点は、どうしても、共通する構成をすべてのHTMLに書かないといけないところです。

SSI(Server Side Include)を利用する

Webサーバーを利用した解決策としてはSSI(Server Side Include)があります。

この伝統的な手法を利用して、HTMLのインクルードをすることが可能です。
こちらはHEADタグ内でも可能です。

SSIの具体例

SSIを利用したHTMLの構成例です。

<!--#include virtual="include/header.html" -->
(ここに各プログラムの内容を記載していく、プログラム固有のJavascriptも)
<!--#include virtual="include/footer.html" -->

●header.html

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
(metaタグやlinkやscriptなどの共通部分を記載していく)
</head>
<body>
<div id="header_area">
(ヘッダー項目)
</div>
<div id="menu_area">
(サイドメニュー項目)
</div>

●footer.html

<div id="footer_area">
(フッター項目)
</div>
</body>
</html>

ヘッダー、メニュー、フッター項目は直書きしてもいいですし、onload時にfetch()してもいいですし、自由にできると思います。

SSIの問題点

SSIインジェクションという脆弱性があるようです。
Webサーバー上で対策できない場合や、他のWebシステムと同居している場合は、選択肢に入れることが出来ないかもしれませんね。

SSI(Server Side Include)を利用しても解決できない箇所

ブラウザのキャッシュを無効化できない

ブラウザ上部にある「戻る」ボタンを押下した際に、ページを無効化したいですよね?<

以前はMATAタグで可能でしたが、現在はレスポンスヘッダーでの記述になります。
これを実現するには何らかの手間がかかると思います。

フロントエンドのHTMLは枠だけなので、キャッシュが残っても悪さはしないだろう…と思っても、ブラウザが勝手にデータを埋め込んでしまう現象に、かつて出くわしたことがあります。

キャッシュバスター(キャッシュバスティング)ができない

JavascriptCSSは、変更してもキャッシュに残りっぱなしで、変更が反映されない問題が発生します。

これを防ぐ手法として、キャッシュバスティングがよく使われますが、(.htmlが静的なファイルである以上)これに対応できません。
何らかの手間をかける必要があります。

SSIでは、もしかしたら、こういった手法でキャッシュバスティングができるかもしれませんが…
(試してはいません。)

参考:nginxでSSIを有効化する
qiita.com

<!--#config timefmt="%m%d%H%M%S" -->
<script src="js/vanilla-front-end.js?t=<!--#echo var="DATE_LOCAL" -->"></script>

SSIが利用できない場合は?

必ずと言っていいほど、APIでサーバーサイドのフレームワークを利用すると思います。

そちらで側の共通箇所をインクルードしたHTMLだけを作ってあげて、あとはHTML+Javascriptに任せるといった手段もあります。

こちらでしたら、ブラウザのキャッシュの無効化も、キャッシュバスティングも文句なくできます。

私は結果的に、こちらの手法で開発しました。

下記の記事にも書きましたが、DBをサーバーサイドフレームワークで構築するのであれば、(表に出ない=スタッフのみが利用する)管理画面はサーバーサイドフレームワークのみで作成し、Webデザイナーが関与する(不特定多数(BtoC)あるいは他社がアクセスする(BtoB))表向きの部分のみ、Vanillaで開発という流れでも良いかと思います。

inuinu-tech.hatenablog.jp

結果的にサーバーサイドで作った方が楽?

メニューのincludeをfetch()ではなく、サーバーサイドのincludeで行う方が楽かもしれませんが、そうやって、どんどんサーバーサイドに比重が重くなっていくと、結果的に、すべてサーバーサイドで作りましょう!ということになってしまいそうですね。

まあ、それはそれで、選択としては間違ってはないと思います。

こういったことは、トレンド(流行)もありますので、何が正解ということもありません。

Ajaxに関わる箇所のみVanilla(またはサーバーサイドフレームワークAjax機能)で開発し、残りはすべてサーバーサイドのフレームワークでも良い気もします。

最後に

とりあえず、Vanillaなフロントエンド開発のテクニックをひととおり紹介しました。

次回は、APIについての考察になります。
(主にバックエンドエンジニア向けですが、フロントエンドエンジニアも目を通しておくと良いでしょう。)

inuinu-tech.hatenablog.jp