【GAS】 Windows 10でclaspを使う【Emacsが使いたかっただけ】(2020-01-16追記あり）

*目標：* Windows 10でclaspを使い、WSLのEmacsでCode.jsを編集する
*やったこと：* claspのインストール、既存プロジェクトのクローン、Emacsでの編集、プッシュ、デプロイ

# 前置き
浮世の義理でGASを使っていたが、エディターがEmacsでないのではかどらなくなってきた。
claspというのを使えば、ローカル環境でEmacsが使えると分かっていた。
問題があって、手元のマシンがWindowsで、EmacsはWSLで使っていた。
現状、ぼくのWSLでChromeは動かせていない。
claspを使うとき、ログインするのにChromeを使わないといけないので、それができなくて困っていた。
そこで、こう考えた。
claspのcreate、clone、push、pullなんかの作業はWindowsのcmd.exeで行い、ファイルの編集だけEmacsで行えばいいのではないか。
ということで、Windowsにclaspを入れた記録である。
特に新しい情報はないが、この環境で情報をまとめたものはなかったと思うので自分用メモ。

# 前提条件
- Google IDを持っている
- Chromeをインストールし、上記のIDを持っている
- Web上のGASで開発している

# インストール
以下のページを参考にした。

claspのインストールについて：
https://qiita.com/rf_p/items/7492375ddd684ba734f8

Node.js/npmのインストールについて
https://qiita.com/taiponrock/items/9001ae194571feb63a5e

inquirerのインストールについて（いらないかもしれんけど・・・）
https://www.moongift.jp/2013/07/20130716-3/

- https://nodejs.org/en/ を開く
- Download for Windows (x64) が開く
- 12.14.0 LTSをダウンロード（執筆時点）
- デフォルトでインストール
- cmd.exeを起動
- `node --version` (v12.14.0)
- `npm --version` (6.13.4)（執筆時点）
- `npm init --y`
- `npm i @google/clasp -g` (WSLでpermissionのことを言われたらsudo）
- 警告が出た「npm WARN inquirer-autocomplete-prompt\@1.0.1 requires a peer of inquirer@^5.0.0 || ^6.0.0 but none is installed. You must install peer dependencies yourself.」
- `npm install inquirer`
- 7.0.1がインストールされた（執筆時点）

(追記:2022-10-27)
久しぶりにやってみたら、`fsevents`がないと怒られた。単純にインストールしようとすると、OSが違うと言われる。
以下の記事でしのいだ。
https://stackoverflow.com/questions/48898312/npm-error-unsupported-platform-for-fsevents-when-deploying-to-azure

- `npm i -f fsevents`

(追記終わり)

(追記:2021-01-12)
ここでこれが必要だと思う。

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

これがないと同じディレクトリにnode-modulesが出来ない。
あとUbuntuでやるときは「npm i」系はsudoしないとかも。
(追記終わり)

- `clasp login`
- Chromeが起動し、ログインが求められたのでログイン
- 「Authorization successful.」、「Default credentials saved to: ~\.clasprc.json (C:\Users\cf\.clasprc.json).」と言われた。

# クローン

以下のページを参考にした。
https://qiita.com/HeRo/items/4e65dcc82783b2766c03

すでにGASのプロジェクトを持っているので、それをクローンしてくる。

- Webでスクリプトエディタを開く
- ファイル＝＞プロジェクトのプロパティ
- プロジェクトのプロパティコマンドが開く
- スクリプトIDをコピーする
- ブラウザを閉じる

- cmd.exe
- 作業フォルダを作ってそこに移動
- clasp clone <<スクリプトID（コピーしたのをペースト）>>
- Code.jsなどがクローンされる
- WSLからは/mnt/c/...でアクセスできる（Cドライブ限定！これはカンタンに解決できないようだ）

まだプッシュもプルもしてませんが、それはおいおい報告します。。

# 追記
前提として、cloneを行ったディレクトリで作業している。

# pushするファイルの拡張子を指定 (追記 2019-12-30
参考：
https://qiita.com/HeRo/items/4e65dcc82783b2766c03#%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%97%E3%83%88%E3%81%AEpush

ただpushすると全ファイルがプッシュされてしまうので、*.jsとappsscript.jsonだけプッシュされるように、ワーキングディレクトリに.claspignoreというファイルを以下のように作った。

```.claspignore
**/**
!*.js
!appsscript.json
```

#プッシュ (追記 2019-12-30

cmd.exeで以下のようにプッシュした。
（ローカルになくてリモートにある既存のファイルはすべて消えるので注意

```
C:\Users\cf\GDrive\clasp>clasp push
└─ Code.js
└─ appsscript.json
Pushed 2 files.
```

スクリプトに文法エラーがあるとここで表示される。

また、あまりにもエラーがひどいと

```
Push failed. Errors:
```

とだけ言われるケースがあった。
（Code.gsを直すだけでpush）ができた）

#Emacsとpush failed（2020-01-16追記）

```
Push failed. Errors:
```

とだけ言われるケースで、以下のようなものがあってハマった。

Emacsを使って編集していて、未保存の編集がある場合（Emacsのバッファバーに**というダーティサインが出ている場合）、編集中のファイルを「foo.js」とすると、「#foo.js」というファイルと「.#foo.js」というJUNCTION（なにそれ？）が出来る。

これらもjsという拡張子で終わっているので、pushしようとすると、たぶんJUNCTIONの方がJavaScriptとしてはメチャクチャなので、claspはびっくりして「Push failed. Errors:」とだけ言い残してプッシュをあきらめるのではないか。

これらのファイルをDOS窓で消してやってもpushは成功するが、Emacsの編集を終わらせて保存してやった方がむろん正道だ。

なお、Emacsは保存後も「foo.js~」のようなバックアップファイルが残るが、こちらは拡張子にチルダがついているのでpushの対象外になるから問題にはならない。
# 導入（デプロイ） (追記 2019-12-30

現在開発中のアプリケーションは、フォームに付属したスクリプトとしてフォームから実行する他に、Web上の「公開＝＞Webアプリケーションとして導入」メニューを使って、Webアプリケーションとして公開している。

参考：
https://tonari-it.com/gas-url-doget-parameter/

Web上のスクリプトエディタを使ってコードを更新した場合は、そのたびに「公開＝＞Webアプリケーションとして導入」を行って、Project version: に New を指定してやらなければ Web アプリが新しくならない。

これをclaspで行うには以下のように行う。
まず、```clasp deployments```で現在のデプロイメント一覧を取得する。

```
C:\Users\cf\GDrive\clasp>clasp deployments
2 Deployments.
- AxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxU @HEAD
- AyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyI @14 - web app meta-version
```

「@HEAD」がファイル＝＞プロジェクトのプロパティ」で得られるスクリプトID、
「@14 - web app meta-version」が「公開＝＞アプリケーションとして導入」で得られるスクリプトIDのようだ。
14は現在のバージョン番号。

Webアプリケーションの方をデプロイするには、上で得られたスクリプトIDを--deploymentIdに指定して以下のように行う。

```
C:\Users\cf\SBX_GDrive\clasp>clasp deploy --deploymentId AyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyI
Created version 15.
- AyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyI @15.
```
バージョン番号が自動的に1上がり、Webアプリケーションとしての導入が自動的に再度行われる。

（```clasp redeploy```と書いてあるブログは古いので注意。redeployは廃止され、エラーが表示される）

バージョンの一覧の表示はversionsコマンド、
バージョンアップと説明の付与はversionコマンドで行う。
（末尾のsの有無だけが違うのに注意）
上で```clasp deploy```を行うと「- web app meta-version」というコメントが取れてしまったが、これはversionコマンドで付与できる説明と同じもののようだ。

まとめると、コードを更新すると
- ```clasp push```
- ```clasp deploy --deplomentID```
の2つのコマンドを実行すればプッシュ＆デプロイが行われる。
# バッチファイルの活用（追記 2020-01-16
```clasp push``` や ```clasp deploy --deploymentId=xxxxxxxxxxxxxxxxxxxxxxxxxx``` などのコマンドは、バッチファイルに入れてパスを通している。何百回も起動するからだ。
# クライアントサイドJavaScriptの効率のいい書き方（追記 2020-01-16
GASでWebアプリとしてデプロイし、URLへのアクセスによって実行されるのはdoGet()関数で、サーバーサイドで実行される。
参考： https://tonari-it.com/gas-web-doget-html-output/

一方、フォーム入力による必須入力チェックや、ある項目を選択したら別の項目を有効化／無効化する処理は、クライアントサイドのJavaScriptを使って行う。
参考：https://tonari-it.com/gas-web-app-javascript/ および https://tonari-it.com/gas-button-event-javascript/

余談だが、この「いつも隣にITのお仕事」というサイトは、大変参考にさせてもらっている。足を向けて寝られない。
ところで、上の２個めに紹介したクライアントサイドのJavaScriptを使う記事では、JavaScriptはjs.htmlというファイルに括りだし、HTMLテンプレートから強制スクリプトレットタグ ```<?!=...>``` をいうのを使って行うと書いている。（強制スクリプトレットタグについては以下に詳しい: https://tonari-it.com/gas-html-css/）

```index.html（一部）
    <?!= HtmlService.createHtmlOutputFromFile('js').getContent(); ?>
```

ここで```'js'``` というのは ```js.html``` というファイルの基底ファイル名だ。
この中には、以下のような形式でJavaScript関数を書くことが上記サイトでは例示されている。

```js.html（一部）
<script>
function foo() {
  /* JavaScriptのコード */
}
</script>
```

GASのHtmlService.createHtmlOutputFromFileメソッドでは ```*.html``` というファイルしか読み込んでくれないので、ワークアラウンドとしてそのようにしている。

しかし、これだと、```js.html```をclasp経由でEmacs（やVSCodeなどのコードを認識するエディター）で、htmlと思い込んでしまうので、JavaScriptとしてのインデントやキーワードの色付けが行われず、カッコの対応などが分からないので、大変苦労する。

そこで、以下のようなワークアラウンドを取った。わざわざ紹介するようなものではないが。。
まず、index.html側に```<script>```タグを書く。

```index.html（一部）
    <script>    
    <?!= HtmlService.createHtmlOutputFromFile('js').getContent(); ?>
    </script>    
```

次に、JavaScript側は```<script>```タグを書かず、拡張子を```js```にする。

```js.js（一部）
function foo() {
  /* JavaScriptのコード */
}
```

次に、```clasp push```するバッチファイルを以下のように書く。

```push.bat
call ren js.js js.html
call clasp push
call ren js.html js.js
```

要は開発するときは拡張子を```.js```にし、pushする直前で```.html```に変えて、pushした直後に```.js```に戻す。
```call```を使っているのは```cmd.exe```の機能で、前のコマンドの終了を待って次の実行を行いたいからだ。
参考： https://jj-blues.com/cms/wantto-callbatinbat/

ちょっとしたことだけど、これでだいぶ快調だ。
```.css```も同様に出来るだろう。

むろんこれは、claspを使ってEmacsで編集をしたいという特殊な事情をくぐり抜けるバッドハックであって、「いつも隣にITを」さんの記事内容としては普通にWeb経由の開発を考えているので現状のままでいいと思う。
# プル (追記 2020-01-02

ある程度開発が進んだところで、Web側でファイルを追加／変更し、その結果をローカルに持ってきたいときはpullを行う。

```
C:\Users\cf\GDrive\clasp>clasp pull
```

# WSLとの関係

WSLからWindowsのclaspコマンドを使うには、cmd.exeに/cオプションでclaspコマンドを渡す。
プッシュであれば

```
$ cmd.exe /c clasp push
```

とすれば良い。

本来は、Emacsでauto-shell-commmand ( https://qiita.com/ongaeshi/items/0e45e4bfa5a813c1b9e4 ) やfirestarter ( http://emacs.rubikitch.com/firestarter/ ) を使って、ファイルを編集保存したら自動でプッシュ、デプロイというのがやりたいのだが、この設定がうまくいかない（反応が帰ってこなくなる）。
これが現状の課題。

＊

これだけ苦労して設定した甲斐があったかという話だが、あくまで体感だが、20倍ぐらい楽になった。
やはりEmacsで編集できることと、コマンド２発（実際にはバックスクロールするので↑↑↑Enter、↓Enterと８回キーを押すだけ）で作業が終わるのがうれしい。
おすすめ。

（この項おわり）