🕌

GASでHTMLを公開するときに詰まった個所まとめ

2024/06/03に公開

GASでHTMLを静的に公開したい時に詰まった個所まとめ
GASを使用してWebサイトの公開を行う方法とかは色々な箇所で既に説明されているので飛ばします。

iframe

ページ内に埋め込み系のコンテンツがある場合
GAS側ではX-Frame-OptionsSAMEORIGINが指定されるためSameOriginPolicyで埋め込みがブロックされる。
そのため、setXFrameOptionsModeを使ってポリシーの設定をする必要がある。
setXFrameOptionsModeHtmlService.XFrameOptionsMode.ALLOWALLを渡す事ですべて許可扱いになり埋め込みがブロックされなくなる。

Code.gs
function doGet() {
  return HtmlService.createHtmlOutputFromFile('index').setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL);
}

ページ同士のリンク

ページ同士のリンクは静的サイトと違いGASとして完結させる必要があるため
GAS側にスクリプトを書いて対応する必要がある。

Code.gs
function doGet(e) {
  let page = e.parameter.page;
  if (!page) {
    page = 'index';
  }
  return HtmlService.createTemplateFromFile(page).evaluate().setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL);
}

function getAppUrl() {
  return ScriptApp.getService().getUrl();
}
index.html 変更前
<a href="/index.html">ホーム</a>
index.html 変更後
<a href="<?= getAppUrl() ?>?page=index">ホーム</a>

HTMLファイルにはgetAppUrl関数として、GASのURLを返す関数を作成しておき
GAS側でHTMLを返す際にURLを埋め込んで返す。
また、doGet関数でリクエストパラメータを受け取れるようにし
指定されたファイルをHTMLとして返却する。

ページの埋め込み

ページが複数あって、HTML同士を共通化してある時
GAS側でスクリプトを書いてあげる必要がある。
例えば、

構成
project-root/
└── public/
    ├── pages/
    │   └── navbar.html
    └── index.html
index.html
:
<body>
  <nav id="navbar"></nav>
</body>
:

の時
静的サイトの時は、jQueryなり、javascriptでDOMのコピーをすれば対応できるが
GASの場合だと取得する対象のHTMLが静的ファイルとして配置されないため
ファイルの中身が取得できない。

そのため、ファイルの共通化をしたい場合は以下のGASを書いて対応させる必要あり。

Code.gs
function doGet(e) {
  let page = e.parameter.page;
  if (!page) {
    page = 'index';
  }
  return HtmlService.createTemplateFromFile(page).evaluate().setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL);
}

function include(filename) {
  return HtmlService.createTemplateFromFile(filename).evaluate().getContent();
}

HTML側には共通化HTMLを挿入したい箇所に以下の文を追加する。

index.html
<body>
  <nav id="navbar">
  <?!= include('navbar') ?> <!-- ←この行を追加 -->
 </nav>
</body>

ポイント

  • GASでHTMLの内容を返す時にevaluateを行ってからHTMLを返却しないとGASの埋め込みコード(*1)が評価されなくなる

*1 例えば<?= getAppUrl() ?>などの埋め込み部分のテンプレートに埋め込んでいるタグのこと

画像の埋め込み

画像ファイルを表示したい時、GASに画像ファイルをアップロードしても参照ができない。
そのため、Base64に変換して埋め込む必要がある。
Base64にするにはNodeで関数を記載するなり、gulpで埋め込むなりする方法がある。

GASの25MB制限

GASはすべてのファイル合わせて25MBの制限がある。
公式

もし、画像などを25MB以上ページに使用したい場合は
Base64での埋め込みではなくGoogleDriveに画像を保存し
HTML側から取得する必要あり。

Code.gs
function getImageAsBase64(fileName) {
  const fileId = getFileIdByName(fileName);
  var file = DriveApp.getFileById(fileId);
  var blob = file.getBlob();
  var contentType = blob.getContentType();
  var base64Data = Utilities.base64Encode(blob.getBytes());
  return 'data:' + contentType + ';base64,' + base64Data;
}

function getFileIdByName(fileName) {
  const folder = DriveApp.getFolderById("ここに画像フォルダのID");
  const files = folder.getFiles();
  let fileId = null;
  while (files.hasNext()) {
    const file = files.next();
    
    if (file.getName() === fileName) {
      fileId = file.getId();
      Logger.log("Found file: " + fileName + " with ID: " + fileId);
      break;
    }
  }
  
  if (fileId === null) {
    Logger.log("File not found: " + fileName);
  }
  return fileId;
}

画像を取得するスクリプトを追加

sample.html
<script>
function fetchImages() {
    const images = document.querySelectorAll('img[data-file-id]');
    images.forEach(function(img) {
      const fileId = img.getAttribute('data-file-id');
      google.script.run.withSuccessHandler(function(base64Image) {
        img.src = base64Image;
      }).getImageAsBase64(fileId);
    });
}
      
document.addEventListener('DOMContentLoaded', fetchImages);
</script>

画像ファイルを表示したい箇所に以下のように指定

sample.html
<img src data-file-id="画像ファイル名" />

上記でBase64として表示することができる。
もし、画像を誰でも共有にする場合は画像のURLを取得してimageタグのsrcに指定する方法もある。

Discussion