4

I'm currentyl creating a kotlin mutliplatform project for jvm and js. My build.gradle.kts looks like this:

plugins {
    id ("org.jetbrains.kotlin.multiplatform")
}

repositories {
    mavenCentral()
}

kotlin {
    jvm() {
        compilations["main"].kotlinOptions{
            jvmTarget = "1.8"
        }
    }
    js() {
        compilations["main"].kotlinOptions{
            outputFile = "${buildDir}/nodejs/common.js"
            moduleKind = "commonjs"
            sourceMap = true
            verbose = true
        }
    }

    sourceSets {
        val commonMain by getting {
            dependencies {
                implementation (kotlin("stdlib"))
                implementation (kotlin("stdlib-common"))
            }
        }
        val commonTest by getting {
            dependencies {
                implementation (kotlin("test-common"))
                implementation (kotlin("test-annotations-common"))
            }
        }
        jvm().compilations["main"].defaultSourceSet  {
            dependencies {
                implementation (kotlin("stdlib-jdk8"))
            }
        }
        jvm().compilations["test"].defaultSourceSet  {
            dependencies {
                implementation (kotlin("test"))
                implementation (kotlin("test-junit"))
            }
        }
        js().compilations["main"].defaultSourceSet {
            dependencies {
                implementation (kotlin("stdlib-js"))
            }

        }
        js().compilations["test"].defaultSourceSet  {
            dependencies {
                implementation (kotlin("test-js"))
            }
        }
    }
}

When I build the project a common.js is created which content looks like this:

(function (_, Kotlin) {
    'use strict';
    var Kind_CLASS = Kotlin.Kind.CLASS;
    var ArrayList_init = Kotlin.kotlin.collections.ArrayList_init_287e2$;
    var emptyList = Kotlin.kotlin.collections.emptyList_287e2$;
    var NotImplementedError_init = Kotlin.kotlin.NotImplementedError;
    function commonSharedCode(platform) {
        return 'Common: Hi! ' + platform.greetingMethod + '(' + platform.name + ') AND NOW IN BEAUTIFUL ' + platform.beautifulPlatform();
    }
    function Platform(greetingMethod, name) {
        this.greetingMethod = greetingMethod;
        this.name = name;
    }
    Platform.prototype.beautifulPlatform = function () {
        return '***' + this.name + '***';
    };
    // ... //
    return _;
}(module.exports, require('kotlin')));

Now I created a simple javascript file outside the project and tried to use the created code (like you see in the tutorials - they create an app that uses the mutliplatform project as a dependency). This seems not to be possible because no function etc. are exported by the created code. I hoped to be able to do things like

const common = require('common');

function myTest () {
    console.log(common.Platform('Hello', 'World'));
}

Do you have an idea on how to build the project to be able to do these things?

Florian
  • 51
  • 2

1 Answers1

2

Have you tried actually running the above code? If yes, what happens? There's some ambiguity in this question, so it's hard to pinpoint what's the actual problem.

Anyway, let me share what I managed to do in a quick and dirty way. Perhaps this proof of concept will unblock you.

  1. I created such Kotlin file in my Kotlin/JS project:
class TestLibraryClass {
    @JsName("appendNumberToString")
    fun appendNumberToString(string: String, number: Int) =
        "Appending: $string - $number"

    fun functionWithoutJsNameAnnotation(someStr: String)
            = someStr
}
  1. I built the project, and got the result JS file in build/distributions/project-name.js.

  2. I opened any webpage in a web browser that has a JS console, and pasted the code of project-name.js file like this - this is an equivalent of your attempt with require:

importedKotlinLib = ...pasted the code here...
[hit enter]
  1. I created an instance of TestLibraryClass:
testLibraryClassInstance = new importedKotlinLib.TestLibraryClass()
  1. I was able to call both functions, the first one with the custom given name to avoid name mangling, and the second one was present with mangled name:

JS console dump

I learned about name mangling (and how to work around it) here. Please note that the class name TestLibraryClass isn't mangled. I tested that top-level functions' names get mangled.


Regarding the big picture - if it's officially supported to prepare JS libraries written in Kotlin - I don't have full clarity here. I'll be happy to update this answer once I find out. I'm also looking at incorporating Kotlin/JS in my company's projects.

PiotrK
  • 1,502
  • 1
  • 15
  • 33