アプリ開発備忘録

PlayStationMobile、Android、UWPの開発備忘録

Kotlin/JSでpackage.jsonの出力をカスタマイズする。(MPP対応)

Kotlin/JSKotlin/JS としてセットアップするか、 Kotlin MultiPlatform Project(Kotlin MPP) としてセットアップするかの二種類があります。
ここでは全体としての Kotlin/JS と、Kotlin/MPP と対になっている Kotlin/JS の表記が混じっています。

基本構成

Kotlinファイルは src/jsMain/kotlin 以下に記述します。 build.gradle.kts でセットアップしました。 1.4-M1 を使用しましたが、 1.3.71 でも大丈夫でした。

Kotlin/MPP

plugins {
    id("org.jetbrains.kotlin.multiplatform") version ("1.4-M1")
}

group = "org.example"
version = "1.0-SNAPSHOT"

repositories {
    maven { url = uri("https://dl.bintray.com/kotlin/kotlin-eap") }
    mavenCentral()
}

kotlin {
    js()
    sourceSets {
        getByName("jsMain") {
            dependencies {
                implementation(kotlin("stdlib-js"))

                implementation(npm("firebase-admin", "^8.10.0"))
                implementation(npm("firebase-functions", "^3.6.1"))
            }
        }
    }
}

Kotlin/JS

plugins {
    id("org.jetbrains.kotlin.js") version ("1.4-M1")
}

group = "org.example"
version = "1.0-SNAPSHOT"

repositories {
    maven { url = uri("https://dl.bintray.com/kotlin/kotlin-eap") }
    mavenCentral()
}

dependencies {
    implementation("org.jetbrains.kotlin:kotlin-stdlib-js")

    implementation(npm("firebase-admin", "^8.10.0"))
    implementation(npm("firebase-functions", "^3.6.1"))
}

dependencies

package.jsondependencies は、gradleの dependencies に書けば大丈夫です。

implementation(npm("firebase-admin", "^8.10.0"))
implementation(npm("firebase-functions", "^3.6.1"))
  "dependencies": {
    "kotlin": "1.4.0-M1",
    "firebase-admin": "^8.10.0",
    "firebase-functions": "^3.6.1"
  },

devDependencies, peerDependencies, optionalDependencies, bundledDependencies, workspaces

packageJsonorg.jetbrains.kotlin.gradle.targets.js.npm.PackageJson を操作します。この PackageJsonGson でそのまま出力することで package.json が出力されます。

Kotlin/MPP

import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation.MAIN_COMPILATION_NAME
kotlin {
    js {
        nodejs {
            compilations.getByName(MAIN_COMPILATION_NAME) {
                packageJson {
                    devDependencies["eslint"] = "^5.12.0"
                }
            }
        }
    }
}

Kotlin/JS

import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation.MAIN_COMPILATION_NAME
kotlin {
    target {
        compilations {
            getByName(KotlinCompilation.MAIN_COMPILATION_NAME) {
                packageJson {
                    devDependencies["eslint"] = "^5.12.0"
                }
            }
        }
    }
}

その他のpackage.jsonの要素

PackageJsonGson でそのまま出力しているので、ここに定義されていなければ package.json の出力を変えることはできません。
なので以下のように新しく定義して、 package.json が出力された後に読み込んで出力し直します。

kotlin/JSは JsJar ですが、Kotlin/MPPは jsJar なので注意が必要です。

共通

import org.jetbrains.kotlin.gradle.targets.js.npm.PackageJson

val PROJECT_NAME = rootProject.name
kotlin {
    tasks.first { it.name.toUpperCase() == "JSJAR" }
        .doLast {
            customizePackageJson() 
        }
}

fun customizePackageJson() {
    val packageJsonFile = File("build/js/packages/$PROJECT_NAME/package.json")
    val packageJson = Gson().fromJson(packageJsonFile.readText(), PackageJson::class.java)

    val customPackageJson = CustomPackageJson(packageJson) {
        engines["node"] = "10"


        scripts["lint"] = ""
        scripts["serve"] = "firebase emulators:start --only functions"
        scripts["shell"] = "firebase functions:shell"
        scripts["start"] = "npm run shell"
        scripts["deploy"] = "firebase deploy --only functions"
        scripts["logs"] = "firebase functions:log"
    }

    packageJsonFile.writeText(
        com.google.gson.GsonBuilder()
            .setPrettyPrinting()
            .create()
            .toJson(customPackageJson)
    )
}

@Suppress("USELESS_ELVIS")
class CustomPackageJson(packageJson: PackageJson, block: CustomPackageJson.() -> Unit) {
    var private: Boolean? = packageJson.private

    var main: String? = packageJson.main

    var workspaces: Collection<String>? = packageJson.workspaces

    val devDependencies = packageJson.devDependencies
        get() = field ?: mutableMapOf()

    val dependencies = packageJson.dependencies
        get() = field ?: mutableMapOf()

    val peerDependencies = packageJson.peerDependencies
        get() = field ?: mutableMapOf()

    val optionalDependencies = packageJson.optionalDependencies
        get() = field ?: mutableMapOf()

    val bundledDependencies = packageJson.bundledDependencies
        get() = field ?: mutableListOf()

    val engines = mutableMapOf<String, String>()
        get() = field ?: mutableMapOf()

    val scripts = mutableMapOf<String, String>()
        get() = field ?: mutableMapOf()

    init {
        block(this)
    }
}

おわりに

Kotlin/JSに関する情報が全然ないのと、コードジャンプが使えなくてコードを追うのが大変でした。

それから、Kotlin/MPP では使用できるのに、 Kotlin/JS では java.nio が使えなかったりする違いがあってGradleスクリプトが書きにくいとかあるので Kotlin/MPP で書くことをおすすめします。