LoginSignup
19

More than 1 year has passed since last update.

[Clasp] Google Apps Script で npm install した package を利用する

Last updated at Posted at 2021-12-10

この記事は Google Apps Script Advent Calendar 2021 の 11 日目の記事です

はじめに

GAS に頼るのは最後の手段にしたいというのが個人的な考えですが、
google/claspにより TypeScript で記述できるようになったことで
自分の中で GAS に対するハードルがだいぶ下がりました。(TypeScriptの書き味が一番好きです)

今回はそんな clasp を使って、npm install した package を利用する方法を記載してみます。

前提

  • Node.js および npm を利用できること(本記事では npm を使いますが、yarn に置き換えられる方はそれでも大丈夫かと思います)
  • google/clasp がインストール済であること

注意点

  • 最後に GAS 上でプロジェクトを開くとわかりますが、1 つの JavaScript ファイルに bundle されるため、目当ての関数を探すのが面倒にはなります。
  • また、GAS 上コードを直接編集することはほぼできない感じになります。
  • clasp push する前には必ず、 npm run build (rollup 実行)が必要です。
  • 後から気づいたのですが、ドキュメントからのリンクのこちらにも完成形があります。本記事はそれを 0 からやっていく手順です。

手順

clasp プロジェクトのセットアップ

この辺りは初歩的なところなので読み飛ばしても OK です。また、clasp のスタート手順については、README を読むと情報が正確です。

# (未だの場合のみ) clasp の認証を通しておく
clasp login

# 適当にプロジェクトディレクトリを作成してnpm init
cd projectdir
npm init

# GASのプロジェクト構成を作成
clasp create --type standalone

TypeScript 化

これは本題とは少し関係がないところですが、TypeScript で書きたいのでドキュメントに従ってセットアップします。

次のコマンドで形定義を install して

npm i -D @types/google-apps-script

直下に tsconfig.json を作成すれば OK です。
tsconfig.json は clasp のドキュメントによると、変更するなという項目もあるので注意。
一例を載せておきます。

tsconfig.json
{
  "compilerOptions": {
    "target": "ES2019",
    "module": "None",
    "moduleResolution": "node",
    "esModuleInterop": true,
    "strict": true,
    "lib": ["esnext"],
    "experimentalDecorators": true
  },
  "include": ["src"]
}

スクリプトを記述

ここから本筋の、npm install した package を利用したコードを書いていきます。
とりあえず moment を使ってみるので install してコードを作成します。

moment を install して

npm i moment

src ディレクトリに index.ts を記述

src/index.ts
import moment from "moment";

const main = () => {
  const now = moment();
  Logger.log(now.format());
};

この時点で、 clasp push コマンドを打つと GAS をアップロードできますが、 clasp open で GAS プロジェクトを開いて実行しても、エラーになるはずです。GAS 上でも動かせる JavaScript ファイルになるよう、bundler を設定します。

module bundler (rollup.js) を設定

ローカルで書いたソースコードから、GAS 上でも実行できるファイルを生成するために rollup.js を使います。

ちょっと難しそうですが、clasp のドキュメントに書いてあることをやるだけです。

まず、rollup.js を install します。

npm i -D rollup

次に、rollup の config ファイル rollup.config.js を作成します。一旦ドキュメントからコピペするだけです。

rollup.config.js
import { babel } from "@rollup/plugin-babel";
import { nodeResolve } from "@rollup/plugin-node-resolve";

const extensions = [".ts", ".js"];

const preventThreeShakingPlugin = () => {
    return {
      name: 'no-threeshaking',
      resolveId(id, importer) {
        if (!importer) {
            // let's not theeshake entry points, as we're not exporting anything in Apps Script files
          return {id, moduleSideEffects: "no-treeshake" }
        }
        return null;
      }
    }
  }

export default {
  input: "./src/index.ts",
  output: {
    dir: "build",
    format: "esm",
  },
  plugins: [
    preventThreeShakingPlugin(),
    nodeResolve({
      extensions,
    }),
    babel({ extensions, babelHelpers: "runtime" }),
  ],
};

あわせて、babel の config ファイルを作成します。

babel.config.js
module.exports = {
  presets: [
    [
      // ES features necessary for user's Node version
      require("@babel/preset-env").default,
      {
        targets: {
          node: "current",
        },
      },
    ],
    [require("@babel/preset-typescript").default],
  ],
   plugins: ["@babel/plugin-transform-runtime"]
};

`plugins` はドキュメントの例にはありませんが、必要なので追加しておきます。

この状態で rollup を実行すると色々とエラーが出ることがわかるので対応します。(実行前にエラーがわかるようになりたい人生だった)

# 必要な依存関係を解決する (上記のjs内で使ってるplugin等々)
npm i -D @rollup/plugin-babel @rollup/plugin-node-resolve @babel/preset-env @babel/preset-typescript @babel/plugin-transform-runtime

babel.config.js に必要な plugin がないよと怒られるので編集追加します。

babel.config.js

+  plugins: ["@babel/plugin-transform-runtime"],

あと少しです。rollup.config.js に一部追加します。

node_modules 以下の package.json から main ファイルを解決してくれるのですが、 jsnext:main という様式で書かれている package があり、それに対応するための追記です。(jsnext:main 以外は ドキュメント記載のデフォルト値を入れてます。)

rollup.config.js
     nodeResolve({
       extensions,
+      mainFields: ["jsnext:main", "module", "main"],
     }),

ここまでできたら、package.json に build 用のコマンドを追加して実行してみましょう。

package.json
   "scripts": {
+    "build": "rollup -c"
   },
npm run build

成功すると created build みたいな出力になるはずです。

clasp のデプロイ

ここまできたらあと少しです。
bundle された js ファイル以外がアップロードされないように、.claspignoreを作成します。

.claspignore
# ignore all files…
**/**

# except the extensions…
!appsscript.json
# and our transpiled code
!build/*.js

# ignore even valid files if in…
.git/**
node_modules/**

そして以下のコマンドを実行するとアップロードできます。

# スクリプトのアップロード
clasp push

clasp open などで GAS プロジェクトを開き、 main 関数を実行すると、npm install した moment を使ったコードが実行できることが確認できるかと思います。
お疲れ様でした!

終わりに

今回のソースコード完成形はこちらにあります。 (https://github.com/suzukenz/sandbox/tree/master/advent-gas-2021)

記事にすると結構長くなりましたが、一度わかれば構築はすぐで、便利な package を使えたり
import / export が使えたりとメリットが多いので、自分は GAS を作るときはしばらくこれでやってみるつもりです。
また、clasp を使ってローカルに開発環境を作ることで、eslint などの便利なツールの恩恵も受けられます。その辺もいつか触れられたらと思います。

最後まで読んでいただきありがとうございました。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
19