Google Apps Scriptの開発をローカルで行うためにWebpackによる自作テンプレート作成をしてみる
今回はWebpackを使った自作テンプレート作成をやったことない人向けのチュートリアルになります。
ちゃんと調べて真面目な記事のつもりですが、Webpack歴1週間くらいの人間が書いているので間違ってそうなところは編集リクエストお願いします。。。
想定している記事の読者層
GoogleAppsScriptはとても便利なスクリプトの実行環境なので、Qiitaの記事でも人気で本日付けで1713の記事が公開されていますね。
とても便利なのでWebからさくっと作成して、そのまま放置している人も多いと思います。またプロダクトとして公開していたり、社内BotでSlack通知させていたりと、結構がっつり使っているのにGit管理されていないであったり、社内の誰からもレビュー受けていない状態になっていませんか?
であるので以下のような考えを持つかたはこの記事が参考になるかと思います。
- ウェブ上でGASを書いたことがある人 && プロダクトで使っている
- GitHub/GitLabでコードを管理したい、レビューしてもらいたい
- どうせならnpmモジュール使ったりES6とかTypescriptで書きたい(GASはES5までの構文のみ)
また自分はVue-cliとかでなんかいい感じにWebpackとかBabelがコンパイルしてくれるのでしっかり自分で定義とかしたことなかったので、そのあたりをテンプレート作成を通して学んでいきたいと思います。
なので、以下のような人が読むと、Webpac筋のレベルがあがるのではないでしょうか。
- Vue.js/Reactとか使っているときにWebpackを使っているはずだけど、設定したことない
- babel?トランスパイル??なにそれ食べれるの。
参考にさせてもらった記事
Google Apps Script のモダンな開発環境を求めて
こちらの記事は2018年末におけるGAS開発のいろんなものを丁寧にまとめてくださっているので、3往復くらい読ませていただきました。
Google Apps Script をローカル環境で快適に開発するためのテンプレートを作りました - Qiita
今回作ろうと思ったテンプレートの一番参考になった記事です。
2018/03/28 - gas-clasp-starter という Google Apps Script を ローカル環境で開発するためのテンプレートを作りました。 2018年に登場した、google/clasp をベースに webpack, TypeScript, TSLint, Prettier, Jest を利用したテンプレートになっています。
開発
グローバルに必要なパッケージ
今回コードはyarnのサンプルなのでnpmでやるかたは適宜読み替えてください。
$ node -v
v12.4.0
$ npm -v
6.9.0
$ yarn -v
1.16.0
$ clasp -v
2.1.0
webpack-cliと、claspはGoogleが提供しているGAS用のSDK的なものなのでインストールとログインしておく。
npm i @webpack-cli/init -g
npm i @google/clasp -g
clasp login
Webpack設定
mkdir qiita-gas-template
cd qiita-gas-template/
yarn add gas-webpack-plugin webpack webpack-cli @webpack-cli/init --dev
npx webpack-cli init
# A name parameter is required to create a storage
npx
は ./node_modules/webpack-cli/bin/cli.js
的なパスをわざわざ叩かなくても npx webpack-cli
だけで実行できる魔法のスクリプトです。気になるかたは調べてみて。
nameエラー出るので package.json
に "name": "qiita-gas-template"
を追加修正します。
{
"name": "qiita-gas-template",
"devDependencies": {
もう一度 webpack-cli
で初期化します。
npx webpack-cli init
ℹ INFO For more information and a detailed description of each question, have a look at: https://github.com/webpack/webpack-cli/blob/master/INIT.md
ℹ INFO Alternatively, run "webpack(-cli) --help" for usage info
? Will your application have multiple bundles? No
? Which will be your application entry point? src/index
? In which folder do you want to store your generated bundles? dist
? Will you use one of the below JS solutions? ES6
? Will you use one of the below CSS solutions? No
conflict package.json
? Overwrite package.json? overwrite
選択肢は適当に必要なものを選んでください。Typescript使いたい人はここでES6じゃなくてTS
があるはず。
initのときいろいろハマったので、ハマった人はこのあたり読むといいかも
https://github.com/webpack/webpack-cli/blob/master/INIT.md
次に package.json
を確認して、実行コマンドを確かめます。
"scripts": {
"build": "webpack",
"start": "webpack-dev-server"
yarn build
でコンパイルしてくれそうですね。
$ yarn build
# index.html
# main.xxxx.js
? In which folder do you want to store your generated bundles? dist
先程 dist
というディレクトリをコンパイル先に指定したので確認してみます。
$ tree -L 2 dist
dist
├── index.html
└── main.55d8ca80f289d8387835.js
index.js
が作られてほしかったのに違う感じになったので一旦削除する。
rm -fr dist/
index.jsが作られないのでwebpackの設定を確認する。
// html系のプラグインはいらないので
// 代わりに最初にyarnで追加したGAS用のwebpackプラグインを入れる
const HtmlWebpackPlugin = require('html-webpack-plugin'); // 削除
plugins: [new webpack.ProgressPlugin(), new HtmlWebpackPlugin()], // HtmlWebpackPluginだけ削除
// それぞれの行を以下の用に書き換える
const GasWebpackPlugin = require('gas-webpack-plugin'); // 追加
plugins: [new webpack.ProgressPlugin(), new GasWebpackPlugin()], // GasWebpackPluginを追加。
output: {
filename: 'index.js', // ここをindex.jsに書き換える
path: path.resolve(__dirname, 'dist')
},
最終的には以下のような感じになっていると思う。
const path = require('path');
const webpack = require('webpack');
const GasWebpackPlugin = require('gas-webpack-plugin');
module.exports = {
mode: 'development',
entry: './src/index.js',
output: {
filename: 'index.js',
path: path.resolve(__dirname, 'dist')
},
plugins: [new webpack.ProgressPlugin(), new GasWebpackPlugin()],
コンパイルが成功するか確認する。
$ yarn build
$ tree -L 2 dist
dist
└── index.js
dist/index.js
が作られてそうです!
// dist/index.jsじゃないよ! src/index.jsだよ!
global.doGet = () => {
return HtmlService.createHtmlOutput("<h1>Getのサンプル</h1>");
}
と書き換える。
yarn build
コンパイルすると
// (いろいろ長いのでこのあたりまで省略)
eval("global.doGet = function () {\n return HtmlService.createHtmlOutput(\"<h1>Getのサンプル</h1>\");\n};\n\n//# sourceURL=webpack:///./src/index.js?");
() => {}
が function(){}
に変換されているので問題なさそうですが、全部evalの中で見にくいですね。
entry: './src/index.js',
devtool: false, // ここの行を追加する
ちょっと今回は以上の設定を追加してみます。
yarn build
webpackのその他の記述がたくさんあるので、必要なところだけ見ると
// (略)
/* WEBPACK VAR INJECTION */(function(global) {global.doGet = function () {
return HtmlService.createHtmlOutput("<h1>Getのサンプル</h1>");
};
// (略)
いい感じにコンパイルされてそうですね。
GoogleAppsScriptの設定
次にGASアプリ作成する。standaloneを選ぶ。
clasp create --rootDir dist
# loginから求められるかも。
# appsscript.jsonが作成される
# https://script.google.com/d/xxxxxx/edit という文字列が出力される
# こちらの画面からコードが編集できるようになる
間違えて --rootDir dist
をつけ忘れたらclaspからpushするときにルートディレクトリをすべてpushしようとするので修正が必要です。 .clasp.json
にrootのオプション {"rootDir": "dist","scriptId": "xxx"}
を追記して、 appsscript.json
を dist/
以下に配置しなおします。
$ clasp push
> no such file or directory, open 'dist/appsscript.json'
dist/appsscript.json
がないって怒れれたので移動させる。
mv appsscript.json dist/appsscript.json
clasp push
clasp push
二回目以降は ? Manifest file has been updated. Do you want to push and overwrite? Yes
って聞かれるので上書きしたげる。
https://script.google.com/home ここから確認するか
https://script.google.com/d/<.clasp.jsonのscriptIdをここにいれる>
どっちかから確認してみましょう
アップロードされていたらOK◎
公開>ウェブアプリケーションとして導入>導入
で 表示される https://script.google.com/macros/s/xx_それっぽいコード_xx/exec
にアクセスすると。
と表示されてたらOKです!!!
テンプレート化する
rm .clasp.json
rm -rf dist/
rm -rf node_modules/
gitignoreを追加しとく
vim .gitignore
/node_modules
/test/js
/test/browsertest/js
/test/fixtures/temp-cache-fixture
/benchmark/js
/benchmark/fixtures
/examples/**/dist
/coverage
/dist
.DS_Store
*.log
.idea
.vscode
.eslintcache
package-lock.json
# 参考 https://github.com/webpack/webpack/blob/master/.gitignore
# distも保存しないほうがいいと思うので追加
テンプレートを含む gas-dev
みたいなルートディレクトリに qiita-gas-template
をいれて、それをコピーして使い回せば完成です。
$ tree -L 1
.
├── gas-dir
└── qiita-gas-template
以降はこのディレクトリをコピペしてそのディレクトリで以下のコマンドを実行して、GASを作りまくる感じです。
cp -r qiita-gas-template gas-dir
cd gas-dir
yarn
clasp create --rootDir dist
yarn build
clasp push
// https://script.google.com/home
以上、テンプレート作成でした。
あとはGitHub/GitLabのプライベートレポジトリとかでレビューしてもらったりいろいろやってみてください。
$ clasp pull (git)-[master]
Could not find script.
Did you provide the correct scriptId?
Are you logged in to the correct account with the script?
共同編集者(GASに権限のないアカウント)がpullしようとするとエラーがでるので、GAS画面上から共有して編集権限を与えてあげてください。
(Git管理を至上として、 clasp pull
は禁止にしたほうがいいと思いますが)
yarn
して yarn deploy
をすれば、別の人も開発に加われると思います。
もっといいテンプレートを使う
Google Apps Script をローカル環境で快適に開発するためのテンプレートを作りました - Qiita
最初の方に紹介したテンプレートのほうが出来がいいのでこちらを使うことを推奨します。
いまWebpack周りを解説したので多分コード読めるようになっていると思います。
具体的にはTypescriptを導入しているんですよね。
"devDependencies": {
"@types/google-apps-script": "0.0.53",
"@types/jest": "24.0.13",
なので Logger.lo
とかまで打つと、VSCodeとかだとタイプヒンティングでGAS上で開発するときに必要なGASのAPIが表示されたり、かなりローカルの開発効率があがります。
今回私が作ったテンプレートでも、以下のような感じでごにょっとpackegeとか追加してあげると、タイプヒンティング自体は動くようになるので、(たぶん、、)ちょっとやってみるといいかもしれません。howdy39さんのコードとか読んでみるといいかも。。。(力つきた。)
yarn add --dev typescript @types/google-apps-script ts-loader
touch tsconfig.json
mv src/index.js src/index.ts
最後に
今回はGASをローカルで開発する方法とGit管理しようぜって話と、テンプレート作ってみようぜ!って話をすべて込めてみました。最後まで読んでいただきありがとうございました!
.