開発
【GAS】claspによるローカル開発時にファイルを分割する
Tamahashi
弊社では業務効率化のためにさまざまな場面でGASを開発しています。
筆者は当初ブラウザ上のエディタで開発していましたが、いくつか不満を抱えていました。
- コードの自動整形ができない
- 静的解析できない
- typescriptが使えない
- 慣れたエディタで開発したい
- 関数を外部ファイルから呼び出す際の仕組みに不満
上記の4つ目まではclaspと呼ばれるGASプロジェクトをローカルで開発できるツールを使用することで解決できますが、5つ目については具体的な解決法を示す記事が少ないように感じたので、こちらにまとめてみようと思います。
環境構築
4つ目までは多くの記事で取り上げられていますので、手順だけシンプルに示します。
claspをインストール
npm install -g @google/clasp
googleにログイン
clasp login
GASプロジェクトをクローン
clasp clone SCRIPT_ID
各種設定ファイルを作成
// package.json
{
"name": "GAS",
"version": "1.0.0",
"description": "GAS project",
"scripts": {
"lint": "npx eslint '*.{js,ts,json}'",
"format": "prettier --write './**/*.{js,ts,json}'"
},
"devDependencies": {
"@typescript-eslint/eslint-plugin": "^5.3.1",
"@typescript-eslint/parser": "^5.3.1",
"eslint": "^7.32.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-prettier": "^4.0.0",
"prettier": "^2.4.1"
},
"dependencies": {
"@google/clasp": "^2.4.1",
"@types/google-apps-script": "^1.0.41"
}
}
//.eslintrc.json
{
"root": true,
"env": {
"browser": true,
"es2021": true,
},
"extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended", "prettier"],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 12,
"sourceType": "module"
},
"plugins": ["@typescript-eslint"]
}
//.prettierrc.json
{
"trailingComma": "all",
"tabWidth": 2,
"semi": true,
"singleQuote": true,
"jsxSingleQuote": true,
"printWidth": 100
}
//tsconfig.json
{
"compilerOptions": {
"target": "ES2021",
"strict": true
}
}
パッケージをインストール
npm install
以上で環境構築は終了です。
ファイル分割する際の不満
main.gsからsub.gsのfunc1関数を呼び出す場合、GASでは以下のように記述します。
// main.gs
const main = () => {
func1()
};
// sub.gs
const func1 = () => {
Logger.log("func1 executed")
}
上記の通り、GASはimport/exportを使うことなく別ファイルの関数を直接呼び出すことができます。
しかしこの仕組みだと、コードが肥大化した際に、main.gs内の関数なのか、sub.gs内の関数なのか非常にわかりづらくなります。
この問題の回避策がこちらで示されています。
- exportsを使用
- namespaceを使用
- webpack, gulp, rollup.jsなどのサードパーティ製ツールを使用
以上の方法がある中で、今回はexportsを使用してみようと思います。
exportsでファイル分割してみる
以下のようにmodule.exports.プロパティ名 = 値 を記述することで、指定の関数を外部で使用できるようになります。
// sub.ts
export const func1 = () => {
Logger.log('func1 executed');
};
module.exports.func1 = func1;
関数は以下のようにして呼び出すことができます。
// main.ts
const main = () => {
const func1 = module.exports.func1;
func1();
};
しかし、この方法だとどのファイルで定義された関数なのかわからない問題が解決していません。また、関数一つ一つにexportsを使用するのも面倒です。
そこで今回はclassを使用することでこの問題を解決してみようと思います。
sub.tsを以下に書きかえます。
// sub.ts
export class Sub {
public func = () => {
Logger.log('func1 executed');
};
}
module.exports.Sub = Sub;
main.tsからSub classのインスタンスを生成し、関数を呼び出します。
// main.ts
const main = () => {
const Sub = module.exports.Sub;
const sub = new Sub();
sub.func1();
};
これで、どのファイルで定義された関数なのかも分かりやすくなったと思います。
まとめ
今回はGASにおける開発体験を向上するために、ローカルでの開発環境構築とファイル分割の方法を紹介しました。
実はclassを使う場合、import/exportでもclaspでgsファイルに変換後も正常に動作するみたいです(少々不安定なようで、正常に変換されないことがありますが…)。
GASの開発環境を考える際にこの記事が参考になれば幸いです。