たゆたふ。

定まる所なく揺れ動き、いろいろやってみたメモ。など

GAS を Webpack + Babel でやってみた

久々に、Google Sheets の Add-on で欲しいものができたので作った。 良い機会なので、Webpack + Babel を使ってビルドする構成を試してみた。 また、Google Apps Script (GAS)周りでもいくつか変化があったので取り入れてみた。

その記録。

作ったもの

会社で開発に使った時間を資産管理の関係で申請する必要があるのだが、Redmine のチケットに時間を記録すれば OK となっている。 一方、私は Togglで日々の時間管理をしている。

チケット終了ごとに Redmine に登録したり、締め日に Toggl を見ながら手作業で Redmine に登録したりしてみたのだけど、どちらも面倒でやってられなかった。 やはり、普段の時間管理は Toggl だけにしたい。 ということで、Toggl から Redmine にデータ移行できるツールを作ることにした1

コマンドラインツールでも良かったのだけど、Redmine に登録する前にちょっと確認したり、調整したりできたほうが便利かと考えた。 となると Google Sheets に一旦書き出して、それを登録できるものがよかろう、それならば Add-on として実装するのが最も便利に使えそうだと考えた。

それで作ったのは toggl2rm 。 次の機能を備えている。

以下に、toggl2rmを作る過程でキーとなった部分や新たに調べたことを記述する。

Webpack + Babelの設定

ざっと、Toggl と RedmineAPI を叩く部分を GAS の Web エディタで検証がてら実装した後、gapps コマンド(node-google-apps-script)を使って、ローカルにソースを持ってきて、Webkit + Babel でビルドする設定した。

webpack.config.babel.jsは次の通り設定した。

import GasPlugin from 'gas-webpack-plugin';
import HtmlWebpackPlugin from 'html-webpack-plugin';
import path from 'path';

export default {
  context: path.resolve(__dirname, 'src'),
  entry: {
    code: './code',
    props: './props',
    utils: './utils',
  },
  output: {
    path: path.resolve(__dirname, 'dest'),
    filename: '[name].js',
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: 'babel-loader',
      },
      {
        test: /\.json$/,
        exclude: /node_modules/,
        use: {
          loader: 'file-loader',
          options: {
            name: './[name].[ext]',
          },
        },
      },
    ],
  },
  plugins: [
    new GasPlugin(),
    new HtmlWebpackPlugin({
      filename: 'sidebar.html',
      template: 'sidebar.html',
      inject: false,
    }),
    new HtmlWebpackPlugin({
      filename: 'setting_dialog.html',
      template: 'setting_dialog.html',
      inject: false,
    }),
  ],
};

.babelrcは次の通り。

{
  "presets": ["env", "gas"]
}

この設定では次のプラグインを利用している。

gas-webpack-pluginbabel-preset-gas で ES6 な JS をいい感じの GAS 向けコードにトランスパイルしてくれる。

html-webpack-plugin は結局 srcディレクトリからdestディレクトリに HTML ファイルをコピーするのにしか使っていない。 本当は HTML に含まれる CSS と JS を別ファイルで実装し、ビルドによって 1 つの HTML にまとめたかった。 html-webpack-pluginプラグインを更にインストールしていろいろ試したが、どうもうまくいかなかった。 最初からdestディレクトリに HTML だけ置いたり、Webpack 使わずコピーしても良かったのだけど、ソースとビルド成果物をはっきり分けたい+設定はwebpack.config.babel.jsに集約したいのでこうした。

また、JS を 1 つのファイルにビルドしてまとめても良かったのだけど、なんとなく大きな 1 ファイルを作りたくないなぁと思って、3 つに分けた。 しかし、1つにしたほうが、グローバルに晒したくない関数を隠せるので今後見直すかもしれない。

ESLint

ESLintも導入してみた。 ベースの設定は eslint-config-airbnb-baseを利用した。 これだけだと GAS 特有のオブジェクトの参照でエラーが出るので、それはeslint-plugin-googleappsscriptで解決した。

自分で実装したグローバルオブジェクトと console.error() 等のログ出力系(後述の Stackdriver Logging のため)を個別に許可設定した。

私は Atom エディタを使っているので、エディタの Linter が実装時にリアルタイムでチェックしてくれ、便利だった。

上記を設定したのものはこんな感じ。

extends: airbnb-base

plugins:
  - googleappsscript

env:
  googleappsscript/googleappsscript: true

globals:
  Props: false
  Utils: false

rules:
  no-console: ["error", { allow: ["info", "warn", "error"] }]

clasp

最初は gapps コマンド(node-google-apps-script)を使っていた。 しかし、複数の GAS のプロジェクトがある場合、個別に Google Drive API の認証が必要なのにその認証情報の管理は~/.gapps 1 ファイルで行われ、切り替えるのが不便だった。

汎用的な不満だと思うので認証情報ファイルをコマンド実行時に指定する方法があるのではと、リポジトリを久々に見るとディスコンしていた。 代わりに Google 謹製の google/claspを使えと書かれていた。

clasp を調べてみて gapps と比べ以下が優れていると思ったので乗り換えた。

  • GAS プロジェクト毎の認証設定が不要(1 回のログインですべての GAS プロジェクトの管理が可能)
  • GAS スクリプトの作成も可能(gapps は先に GAS スクリプトを作っておく必要がある)
  • ドキュメントに紐づくスクリプトの管理も可能(gapps では不可)
  • Google 謹製という安心感

使い方はこちらを参照 => GAS のGoogle謹製CLIツール clasp - Qiita

Stackdriver Logging

確か以前は console.log() は GAS では使えなかったと思うのだが、今は使える。 GAS はサーバサイドで実行されるスクリプトなので、ブラウザの Dev Tool には何も出力されない。 どこに出力されるかというと、Stackdriver という Google Cloud 上のログサービスに出力される。

どうやら、去年の夏頃こうなったようだ3。 以前から GAS にちゃんとしたロギングがほしいと思っていた。 Logger.log() では最後の実行分しか見られないので、どうしても必要な場合にはスプレッドシートに書いたりしたものだ。 しかし、これからは Stackdriver Logging が使える。 DEBUG、INFO、WARN、ERROR という一般的なログレベルを設定して出力できるのも嬉しい。

Stackdriver は無料のサービスではないが、毎月無料枠があり、個人ユースではそれで足りるのではないかと思う。 今回はエラーログの記録に利用している。

ざっと調べてみた結果はこちら => GAS でStackdriver Loggingを使う - Qiita

最後に

久々に GAS での開発をやってみて、自分なりのモダンな開発構成を確立できたと思う。 gas-webpack-plugin が Webpack4 に対応できていないのかどうもうまくトランスパイルできなかったので、実は今回は Webpack3 を使っている。 そのうち対応されればアップデートしようと思う。

しばらく見ないうちに GAS を取り巻く環境も色々変わっていた。 以前は自分にだけ自作 Add-on をインストールする方法があったのだが、それがなくっている。代わりにテスト設定を作成してそこから起動すれば動かせる様に変更されようだ。少々めんどくさくなった。 その一方で、謹製 CLI ツールが用意されたり、ログ周りが強化されていた。
更に、GAS 専用のマネジメントコンソールもできた。Google Drive では他のドキュメントとごちゃまぜの管理だけど、こちらだとドキュメントに埋め込まれた GAS も含め、すべての GAS のみを管理できる。 まだ、あまり調べていないが、バージョン管理と公開周りも開発版と公開版を別々に動かせるようにするためにちょっと変わったようだ。 このあたりの変更は Chrome アプリのプラットフォームとして GAS を使っていくためであろうか?

何れにせよ、以前より開発しやすくなったと思う。 便利なサーバレス環境なので今後も活用していこうと思う。


  1. 個人的には全員で Toggl に移行したほうが効率的なのではと思うものの、今、回っている仕組みを私の我儘トリガーで変更するほどでもないし、Toggl も有料プランが必要になりそうで費用もいくらか発生してしまうので個人的に解決する道を選択した。

  2. CSV でダウンロードする機能を Toggl は提供している。しかし有料プランの機能。同等のデータは API を使えば取得でき、それを利用している。無料で有料機能相当を提供していることに気を使ってライセンスは CC-BY-NC-4.0 としている。

  3. G Suite Developers Blog: Stackdriver Logging for Google Apps Script is now available