GASをkotlinで開発する方法

ちょっと強引な方法ですが動いたのでメモ
動いたと言ってもhelloworldが出ただけなので、その先に落とし穴があるかもしれない...

intellijでkotlinjsのプロジェクトを作成し、コーディングする

build.gradle

kotlin.jsと作成するモジュールのjsが両方出力されるように設定します
下記は若干アレンジしてますが、やってることは公式ドキュメントと同様です

build.gradle

buildscript {
    ext.kotlin_version = '1.2.60'

    repositories {
        mavenCentral()
    }
    dependencies {
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    }
}

group 'com.naosim'
version '1.0-SNAPSHOT'

// 出力先設定
// バージョンごとに出力されるようにしてみた
// 通常は "${buildDir}/web" で良い
def webOutputDir = "${buildDir}/web/${version}"

// gasから呼ぶ時の名前、およびjsのファイル名 "${moduleName}.js"
def moduleName = "gaskotlin"

apply plugin: 'kotlin2js'

repositories {
    mavenCentral()
}

dependencies {
    compile "org.jetbrains.kotlin:kotlin-stdlib-js:$kotlin_version"
    testCompile "org.jetbrains.kotlin:kotlin-test-js:$kotlin_version"
}

task assembleWeb(type: Sync) {
    configurations.compile.each { File file ->
        from(zipTree(file.absolutePath), {
            includeEmptyDirs = false
            include { fileTreeElement ->
                def path = fileTreeElement.path
                path.endsWith(".js") && (path.startsWith("META-INF/resources/") ||
                        !path.startsWith("META-INF/"))
            }
        })
    }
    from compileKotlin2Js.destinationDir
    into webOutputDir

    dependsOn classes
}

compileKotlin2Js {
    kotlinOptions.outputFile = "${webOutputDir}/${moduleName}.js"
    kotlinOptions.sourceMap = false
}

Main.kt

次にメインのクラス
最終的にrunメソッドを呼び出してログ出力します
ログ出力用メソッドのLogger.log()はkotlin.jsに定義されていないのでexternalで定義してあげます

com.naosim.gaskotlin.Main.kt

package com.naosim.gaskotlin

external class Logger {
    companion object {
        fun log(text:String)
    }
}

fun run() {
    val message = "Hello JavaScript!"
    Logger.log(message)
}

ビルド

kotlin.jsも出力されるようにします

./gradlew clean assembleWeb compileKotlin2js
./gradlew compileKotlin2js

1発で生成する方法がわからなかった...誰か教えて...

以上で出力ディレクトリにkotlin.jsとgaskotlin.js(今回作ったモジュール)が生成されたはず

GASでコードを読み込む

先ほど生成したjsをGASで読み込みます
読み込むと言ってもコピペするだけだけど...

おまじない

GASの最初にこのおまじないを書きます

var ArrayBuffer = Int8Array = Int16Array = Uint16Array = Int32Array = Float32Array = Float64Array = function(){};

これがこの記事で最も大切なことです
kotlin.jsの中でこれらのクラスが使われてますがGASには存在しないクラスなので強引に捻り潰します
今後悪影響が出るとしたらココでしょうね...

kotlin.jsとgaskotlin.jsをコピペ

次に生成したコードをコピペします
kotlin.jsは3万行超えの巨大ファイルですがそんなこと気にせずコピペします

runメソッドの呼び出し

最後にgaskotlin.js内のrunメソッドを呼び出します
モジュール名 + パッケージ名 + メソッド名の順にドットで繋げて呼びます

function myFunction() {
  gaskotlin.com.naosim.gaskotlin.run();
}

コード全体

// おまじない
var ArrayBuffer = Int8Array = Int16Array = Uint16Array = Int32Array = Float32Array = Float64Array = function(){};

// kotlin.jsのコード 3万行超え

// gaskotlin.jsのコード 20行くらい

// 呼び出し
function myFunction() {
  gaskotlin.com.naosim.gaskotlin.run();
}

実行

最後にmyFunctionを実行してログ出力を確認

Hello JavaScript!

でたーーー!

まとめ

  • GASをkotlinで開発できる (気がする)
  • ただしGASで使われてないクラスを捻る必要がある