1059 words
5 min

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

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

iframe#

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

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

HtmlService.XFrameOptionsMode.ALLOWALL を使用するとすべて許可になるため、iframeを自由に埋め込み表示することができるが クリックジャッキングも行えることになるため、自身でセキュリティー対策を行う必要あり。 詳しくは公式を参照。 Enum XFrameOptionsMode

ページ同士のリンク#

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

Code.js
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側でスクリプトを書いてあげる必要がある。 例えば、

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

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

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

Code.js
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>

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

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

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

GASでHTMLを公開するときに詰まった個所まとめ
https://storia-blog.pages.dev/blogs/gas_html
作者
Storia
公開日
2024-06-03