LoginSignup
5
2

More than 3 years have passed since last update.

GAS の CLI ツール「clasp」で TypeScript を扱ってみた

Last updated at Posted at 2019-09-09

はじめに

いつか触ろうと思って触ってなかった clasp
https://qiita.com/HeRo/items/4e65dcc82783b2766c03
を参考にしながら触ってみた。

しかも @google/clasp v1.5.0 から TypeScript をサポートしていて、
トランスパイルも自動的にやってくれるとのこと。

但し、TS ファイルから自動的に GS ファイルに変換されたものを
clasp cloneclasp pull すると、変換後の結果が JS ファイルとしてダウンロードされるらしい。
ので、最初からトランスパイル後のファイルを clasp push したら良いのかな?と試してみた記録です。

前提

複数ファイルに分割していない場合は直接 push しても、
トランスパイル後のファイルを push しても変わりはなかったので、
複数ファイルを用意して試す。

push 対象の TS ファイル

src/code.ts
import { outputLog } from './hoge';

function myFunction() {
  outputLog();
}
src/hoge.ts
export function outputLog(): void {
  Logger.log('Hello World!');
}

:white_check_mark: TS ファイルを直接 clasp push した場合

初めに普通にそのまま push するパターン
.clasp.json の rootDir で push 対象ディレクトリを指定。

$ clasp push
└─ src/appsscript.json
└─ src/code.ts
└─ src/hoge.ts
Pushed 3 files.

変換された GS ファイル

code.gs
// Compiled using ts2gas 3.4.4 (TypeScript 3.6.2)
var exports = exports || {};
var module = module || { exports: exports };
//import { outputLog } from './hoge';
function myFunction() {
    outputLog();
}
//# sourceMappingURL=module.js.map

↑import 文が勝手にコメントアウトされてた。
ts2gas 3.4.4 っていうのを使ってるみたい?

hoge.gs
// Compiled using ts2gas 3.4.4 (TypeScript 3.6.2)
var exports = exports || {};
var module = module || { exports: exports };
function outputLog() {
    Logger.log('Hello World!');
}
exports.outputLog = outputLog;
//# sourceMappingURL=module.js.map

myFunction 実行結果

まぁ普通にいける

トランスパイルした JS ファイルを clasp push した場合

tsconfig.json で dist 以下にトランスパイルファイルを出力するようにした。
合わせて .clasp.json の rootDir は dist に変更した。

:x: module="es2015", target="es5"

$ clasp push
| Pushing files...Push failed. Errors:
{ Error: Syntax error: Missing ; before statement. line: 1 file: code
    at Gaxios.request (/Volumes/sdcard/Bin/.nodenv/versions/10.15.1/lib/node_modules/@google/clasp/node_modules/gaxios/build/src/gaxios.js:70:23)
    at process._tickCallback (internal/process/next_tick.js:68:7)
  response:
   { config:
      { url:
         'https://script.googleapis.com/v1/projects/xxxxxxxxxx/content',
        method: 'PUT',
        paramsSerializer: [Function],
        data: [Object],
        headers: [Object],
        params: [Object: null prototype] {},
        validateStatus: [Function],
        retry: true,
        body:
         '{"scriptId":"xxxxxxxxxx","files":[{"name":"appsscript","type":"JSON","source":"{\\n  \\"timeZone\\": \\"Asia/Tokyo\\",\\n  \\"dependencies\\": {\\n  },\\n  \\"exceptionLogging\\": \\"STACKDRIVER\\"\\n}"},{"name":"code","type":"SERVER_JS","source":"import { outputLog } from \'./hoge\';\\nfunction myFunction() {\\n    outputLog();\\n}\\n//# sourceMappingURL=code.js.map"},{"name":"hoge","type":"SERVER_JS","source":"export function outputLog() {\\n    Logger.log(\'Hello World!\');\\n}\\n//PropertiesService.getScriptProperties().getProperty(\'HOGE\')\\n//# sourceMappingURL=hoge.js.map"}]}',
        responseType: 'json',
        retryConfig: [Object] },
     data: { error: [Object] },
     headers:
      { 'alt-svc': 'quic=":443"; ma=2592000; v="46,43,39"',
        'cache-control': 'private',
        connection: 'close',
        'content-encoding': 'gzip',
        'content-type': 'application/json; charset=UTF-8',
        date: 'Mon, 09 Sep 2019 04:43:21 GMT',
        server: 'ESF',
        'transfer-encoding': 'chunked',
        vary: 'Origin, X-Origin, Referer',
        'x-content-type-options': 'nosniff',
        'x-frame-options': 'SAMEORIGIN',
        'x-xss-protection': '0' },
     status: 400,
     statusText: 'Bad Request' },
  config:
   { url:
      'https://script.googleapis.com/v1/projects/xxxxxxxxxx/content',
     method: 'PUT',
     paramsSerializer: [Function],
     data:
      { scriptId: 'xxxxxxxxxx',
        files: [Array] },
     headers:
      { 'Accept-Encoding': 'gzip',
        'User-Agent': 'google-api-nodejs-client/2.0.4 (gzip)',
        Authorization:
         'Bearer ya29.Glx-B1azGu5jyQ_tkABZ9n6mmnDuPnn5uZLM44sOwDMXfAt3mC7Bem5Dmi9joKJ3lmvg7vNy87f37h0muiiccVOdO1Uv-n4YQLqLasp5r03_EzZZAlQ1_AHCt_70bg',
        'Content-Type': 'application/json',
        Accept: 'application/json' },
     params: [Object: null prototype] {},
     validateStatus: [Function],
     retry: true,
     body:
      '{"scriptId":"xxxxxxxxxx","files":[{"name":"appsscript","type":"JSON","source":"{\\n  \\"timeZone\\": \\"Asia/Tokyo\\",\\n  \\"dependencies\\": {\\n  },\\n  \\"exceptionLogging\\": \\"STACKDRIVER\\"\\n}"},{"name":"code","type":"SERVER_JS","source":"import { outputLog } from \'./hoge\';\\nfunction myFunction() {\\n    outputLog();\\n}\\n//# sourceMappingURL=code.js.map"},{"name":"hoge","type":"SERVER_JS","source":"export function outputLog() {\\n    Logger.log(\'Hello World!\');\\n}\\n//PropertiesService.getScriptProperties().getProperty(\'HOGE\')\\n//# sourceMappingURL=hoge.js.map"}]}',
     responseType: 'json',
     retryConfig:
      { currentRetryAttempt: 0,
        retry: 3,
        retryDelay: 100,
        httpMethodsToRetry: [Array],
        noResponseRetries: 2,
        statusCodesToRetry: [Array] } },
  code: 400,
  errors:
   [ { message:
        'Syntax error: Missing ; before statement. line: 1 file: code',
       domain: 'global',
       reason: 'badRequest' } ] }
└─ dist/appsscript.json
└─ dist/code.js
└─ dist/hoge.js

↑なんかエラー出た。

push しようとしたトランスパイル結果

dist/code.js
import { outputLog } from './hoge';
function myFunction() {
    outputLog();
}
//# sourceMappingURL=code.js.map
dist/hoge.js
export function outputLog() {
    Logger.log('Hello World!');
}
//# sourceMappingURL=hoge.js.map

↑普通に import/export なやつ。


:x: module="commonjs", target="es5"

$ clasp push
└─ dist/appsscript.json
└─ dist/code.js
└─ dist/hoge.js
Pushed 3 files.

↑clasp push できた

トランスパイル結果を push して変換された GS ファイル

code.gs
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var hoge_1 = require("./hoge");
function myFunction() {
    hoge_1.outputLog();
}
//# sourceMappingURL=code.js.map
hoge.gs
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
function outputLog() {
    Logger.log('Hello World!');
}
exports.outputLog = outputLog;
//# sourceMappingURL=hoge.js.map

↑requre 系なやつ。
ちなみに dist 以下に出力された dist/code.jsdist/hoge.js と中身は同じ。
ファイル名だけ .gs に変換されている模様

myFunction 実行結果

実行ができなかった!

まとめ

import を使わない場合はトランスパイル後の JS ファイルを push しても問題はない。
でも clasp に任せて TS ファイルを直接 push したほうが良さそう。

push した TS ファイルは GS ファイルに変換されているので、
次回 clasp clone , clasp pull 等をすると変換後の GS ファイルがダウンロードされてしまう。
TS ファイルは別途、Git 等で管理したほうが良さそう。

5
2
0

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
5
2