株式会社スマレジの開発部でスマレジのサーバサイドを作っています

GASでTypeScriptを使う場合の注意点

こんばんは!株式会社スマレジ 、開発部のmasaです。

更新が空いてしまい申し訳ないです。。。ちょっと忙しい時期が続きましてなかなか更新できなかったです泣

さて、最近シリーズの方が進められていないですが、今回も別の話題です。

GASでガッツリしたツールを開発したいとき

スプシを導入している企業は増加している一方で、大体の場合、GASはシンプルな複写や計算などをさせるだけで込み入った機能などは諦めることが多いと思います。

その理由としてGASのベースがJavaScriptであるところにあります。 JSは手軽に使える一方で、JavaPHP,Pythonなどと異なり、MVCライクな開発をするのには少しクセがあります。 (無理ではないですが汗)

そこで、以前紹介したClasp + TypeScriptを使ったローカルでのGAS開発が採用されるのですが、それはそれでいくつか問題点があります。 以前のブログは↓。

masa2019.hatenablog.com

Clasp + TypeScriptを使用する際の問題点

export importが正常に動作しない

これは下記のブログで紹介されている現象です。

kenchan0130.github.io

平たく言えばJSのimport exportがGASにデプロイした時に動作しないことがあるという問題です。 原因は、下記の公式githubに記載されているのですが、GAS自体がECMAScriptコンパイラではなく、 GAS独自の解釈を行なっているようで、そこに問題がある(というかESとの互換性がない)ことにあります。 (これも上のブログの方が触れられています)

github.com

解決策: webpackを利用

回避手段は3つ提示されていますが、後の問題との関連で3番目の「webpackなどのバンドルツールを使用する」一択になります。

しかし、webpackでビルドしてしまうと、トランスパイルされたGASは個々の処理が関数として定義されない状態になります。

それを回避するために、doGet,doPostなどのHTTP用のメソッドをdeclare functionとして定義してあげる必要があります。

declare function doGet(e) {
...
}

また、production modeでwebpackを実行してしまうと、デフォルトではminifyされてしまいますので、定義した関数名とは異なる関数名として定義されてしまいます。

そのため、webpackを利用する際はdevelopment modeを利用しましょう。 eval()が冗長ではありますが、関数名が自分の決めたもののままになるため、スプシの拡張メニュー用のラッパーメソッドからの呼び出しが可能になります。

doGet,doPostとの共存

いわゆるWebサーバとしてのリクエストを捌く処理と、スプシ上のツールとしての役割を両立させたい場合に発生する問題です。 内部的にはevalで関数として評価されているので、呼び出しは可能ですが、menuに追加するなどは今のままではできません。

解決策: ラッパーメソッドをJSで用意する。

シンプルですがこれが一番確実です。 幸いなことに、doGetもdoPostもリクエストを引数に持つ関数なので、リクエスト引数をでっち上げてデータを渡すことも可能です。

例を示すと、

function task1() {
   let req = {};
   req.actionId = "task1";
   doGet(req);
}

というふうにdoGetをラップして、

declare function doGet(e) {

const actionId = e?.actionId;

switch(actionId) {
    case "task1":
      ...
      break;
   ...
}

というように、渡したリクエストに応じて処理を切り替えるなどが可能です。 こうすれば、task1を拡張メニューに紐づけることができ、TypeScript側のロジックを呼び出すことができます。

脱線が続いて申し訳ないですが、次回は上記の実装例をスマレジ の外部会員連携とプラットフォームAPIを組み合わせてご紹介します。