概要
Google Apps Script でのwebアプリ(SPA)開発においては, 公式ドキュメントで複数のhtmlを統合して表示する方法が紹介されています。
しかし, この公式の方法を直接用いると, doGet()
で呼び出された html ファイル内でのみしか他のhtmlファイルを読み込むことはできず, そのため, 複数階層に html ファイルを分割するようなことはできません。
そこで, 本稿では, 公式の提示した実装に若干の変更を加えることで, 複数階層にわたる html ファイル分割を実現するための実装を提示します。
背景:公式の提唱手法とその限界
Google Apps Script においては, gs ファイルと html ファイルのみが許容されています。
しかし, 公式ドキュメントのHTML Service: Best Practicesの Separate HTML, CSS, and JavaScript の項目には, 以下のようなコード(抜粋)を用意することで, 疑似的に html, css, JSファイルを分けることができると紹介されています。
function doGet(request) {
return HtmlService.createTemplateFromFile('Page')
.evaluate();
}
function include(filename) {
return HtmlService.createHtmlOutputFromFile(filename)
.getContent();
}
<html>
<head>
<base target="_top">
<?!= include('Stylesheet'); ?>
</head>
<body>
<h1>Welcome</h1>
<p>Please enjoy this helpful script.</p>
<?!= include('JavaScript'); ?>
</body>
</html>
ここで, <?!= … ?>
はサーバサイドの式を呼び出す構文です。
code.gs
で定義されたinclude()
をそれぞれの場所で評価することで, Stylesheet.html
および JavaScript.html
を展開できるということです。
しかし, この実装では, たとえば JavaScript.html
内で再び <?!= include(...); ?>
を記述して(Page.html
から見れば)孫の呼び出しを行うことはできません。行うと, <?!= include(...); ?>
が文字列としてそのまま表示されます。
サイトの規模が多少大きくなってくると, これでは不便なことが出てきます。
本題
そこで, サーバサイドのinclude()
関数を以下のように書き換えます。
function include(filename) {
var template = HtmlService.createTemplateFromFile(filename);
var html = template.evaluate().getContent();
return html;
}
ファイルから直接 htmlOutput オブジェクト を得るのではなく, まず template オブジェクト を得て, その中身を評価(template.evaluate()
)してから htmlOutput を得るようにしています。
すると、呼び出し先のhtml
ファイルにおいて記述したinclude()
も評価されるようになり, 結果として再帰的にファイルを読み込めるようになります。
補足
循環的に include()
が呼ばれると無限ループになるので, それは防ぐようにしたほうがいいかもしれません。