【GAS】GASでWebサービスを作る際に知っておくと便利なこと

## はじめに
この1年間GASを利用した業務改善やWebサービスを作ってきたのですが、いくつか気づいたこともあるのでまとめておきます。
特にWebサービスを作るとなった場合、参考書籍など内容がまとまっているものがほとんどないいので、何かの手助けになればよいかなと。

## V8を使わない
V8というのはV8ランタイムのことですが、利用するとアップロードファイルが壊れる、URLの不具合など結構不便な状況になるので、V8はオフにしましょう。
書籍ではV8をベースに作られているものが多いですが、個人的には謎のエラーとにらめっこする時間がもったいないのでオフを推奨します。

## HTMLを返す部分を別途作っておく
GASではdoGet(e)かdoPost(e)でWebサイト処理を行います。
その際、htmlを返すのはHtmlServiceを利用するのですが、結構使いまわすことになるのであらかじめ関数を作っておくと便利です。

```javascript:main.gs

function doGet(e){
  var option = {"error":""};
  option.title = "トップページ";
  //index.htmlを読み込み
  return createHtml("index",option.title,e.parameter,option);
}

//======================================================================================================
// getかpostをparamに渡してテンプレートを読み込んでhtmlOutputを返す
// return createHtml("index","トップページ",e.parameter,option);
//======================================================================================================
function createHtml(tmplFile,title,param,option){

  var htmlTmpl = HtmlService.createTemplateFromFile(tmplFile);
  htmlTmpl.param = param;
  htmlTmpl.option = option;

  var htmlOutput = htmlTmpl.evaluate().setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL);
  htmlOutput.addMetaTag('viewport', 'width=device-width, initial-scale=1');
  htmlOutput.setTitle(title);
  return htmlOutput;
}

```

doGetやdoPostでは、e.parameterというところにクエリ文字列やフォームの内容が含まれています。
また、doGet内で作った変数をhtmlに渡してやりたい場合、htmlTmplにセットしてあげることで呼び出せるようになるので、上記ではoptionという連想配列を渡すことで、読み込めるように設定しています。

その他テンプレートの詳細については下記を参考にしてください。テンプレートへの変数渡しについては、「Pushing variables to templates」に書かれています。
[HTML Service: Templated HTML](https://developers.google.com/apps-script/guides/html/templates#code.gs)


## html内での処理や出力方法
htmlファイルは別途作成しておきますが、変数の呼び出しは下記のように行います。
htmlファイル内にGASを書く場合、&lt;? と ?&gt; で囲んであげる必要があります。
```html:index.html
<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
  </head>
  <body>
    <?
    output._ = option.title;
    ?>
  </body>
</html>
```
変数の出力は
```
output._ = 変数
```
または
```
output.append(変数)
```
のどちらかで行うことができます。
とくに処理をせず変数だけ出力したい場合は、
```
<?=変数 ?> ←HTMLタグがエスケープされます
<?!=変数 ?>
```
という書き方も可能です。

## &lt;base target="_top"&gt;は削除しない
GASのWebサービスは多重のインラインフレーム内で処理されています。
&lt;base target="_top"&gt;がついているのは処理した際にフレーム内処理しないようにするためですので、うっかり削除しないようにしましょう。
削除すると動きません。

## 更新は「新しいデプロイ」ではなく「デプロイを管理」で行う
「新しいデプロイ」を行うとURLが新たに発行されます。URLをそのままにしてバージョンだけ新しくしたい場合は、「デプロイを管理」から新バージョンを選択することで行えます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/311544/2c912251-1e68-8727-aa74-48c4e4db1675.png)

## 画面レイアウトはBootstrapを使うと便利
GASでWebサービスを作る場合、レイアウトはBootstrapなどのフレームワークを利用するのがおすすめです。
FormやTableなどを使いたいケースの方が多いと思いますので、デザイン等々はフレームワークにまかせてしまうのが便利です。
外のURLからの呼び出しではなく内部に直接CSSやJSを入れ込みたい場合は、下記を参考にしてください。
[GASでWebページを作るときにHTMLとCSSを別ファイルに記述する方法](https://tonari-it.com/gas-web-html-css-scriptlet/)
bootstrap_js.htmlとbootstrap_css.htmlを作成し、中にJSとCSSをタグで囲んでペーストし、
```
<base target="_top">
<?!= HtmlService.createHtmlOutputFromFile('bootstrap_css').getContent(); ?>
...
<?!= HtmlService.createHtmlOutputFromFile('bootstrap_js').getContent(); ?>
</body>
```
というような形で呼び出します。
## リダイレクトはできない
POSTリクエストを受けた後、onLoadのタイミングでリロードさせないようにlocation.hrefでリダイレクトさせたいなどあると思いますが、これはもうどうにもなりません。去年の後半からどうやってもリダイレクトはできなくなりました。あきらめましょう。
(onClickイベント等の中ではtop.location.hrefは機能しますが、つまるところクリックなどの明示的なアクションを起点とする必要があります）
代わりに画面遷移しないように作るなどもありますが、個人的には面倒臭さの方が上回ったので、フォーム送信後にページをリロードしても不具合が起きないような作りにする方を選びました。

ページ遷移しない作りの場合、Bootstrapのモーダルダイアログなどを使うと便利です。
google.script.run.withSuccessHandlerで処理を実行し、エラーや結果をモーダルダイアログで表示させる形です。
モーダルダイアログを閉じるボタンをスクリプトのURLリンクにすることで、簡単にページをリロードさせることができます。

## おわりに
現時点で思いつくのはこんなところですが、また増えたらここに追加していこうと思います。
Googleフォームなど便利な機能もありつつ、もうちょっと細かい仕様にしたい場合は別途Webサービスを作る必要が出てくるかと思いますので、その時の参考にしてください。