HomeWeb WorldJavaScriptCompile your Kotlin Projects to JavaScript Modules

Compile your Kotlin Projects to JavaScript Modules

Kotlin allows the developers to compile the Kotlin project to Javascript modules for popular module systems.

The list of available options are:

  1. Plain (Default) – The compilation is not done for any module system. You can access the module by its name in the global system.
  2. Asynchronous Module Definition (AMD), which is in particular used by require.js library.
  3. CommonJSĀ convention, widely used by node.js/npm (requireĀ function andĀ module.exportsĀ object)
  4. Unified Module Definitions (UMD), which is compatible with bothĀ AMDĀ andĀ CommonJS, and works as “plain” when neitherĀ AMDĀ norĀ CommonJSĀ is available at runtime.

Choosing the Target Module System

Choosing the target module system depends on your build environment:

From IntelliJ IDEA

Setup per module: Open File -> Project Structureā€¦, find your module in Modules and select “Kotlin” facet under it. Choose appropriate module system in “Module kind” field.

Setup for the whole project: Open File -> Settings, select “Build, Execution, Deployment” -> “Compiler” -> “Kotlin compiler”. Choose appropriate module system in “Module kind” field.

From Maven

To select module system when compiling via Maven, you should setĀ moduleKindĀ configuration property, i.e. yourĀ pom.xmlĀ should look like this:

<plugin>
    <artifactId>kotlin-maven-plugin</artifactId>
    <groupId>org.jetbrains.kotlin</groupId>
    <version>${kotlin.version}</version>
    <executions>
        <execution>
            <id>compile</id>
            <goals>
                <goal>js</goal>
            </goals>
        </execution>
    </executions>
    <!-- Insert these lines -->
    <configuration>
        <moduleKind>commonjs</moduleKind>
    </configuration>
    <!-- end of inserted text -->
</plugin>

Available values are:Ā plain,Ā amd,Ā commonjs,Ā umd.

From Gradle

To select module system when compiling via Gradle, you should setĀ moduleKindĀ property, i.e.

compileKotlin2Js.kotlinOptions.moduleKind = "commonjs"

Available values are similar to Maven.

@JsModuleĀ annotation

To tell Kotlin that anĀ externalĀ class, package, function or property is a JavaScript module, you can useĀ @JsModuleĀ annotation. Consider you have the following CommonJS module called “hello”:

module.exports.sayHello = function(name) { alert("Hello, " + name); }

 

You should declare it like this in Kotlin:

@JsModule("hello")
external fun sayHello(name: String)

ApplyingĀ @JsModuleĀ to packages

Some JavaScript libraries export packages (namespaces) instead of functions and classes. In terms of JavaScript it’s an object that has members thatĀ areĀ classes, functions and properties. Importing these packages as Kotlin objects often looks unnatural. The compiler allows to map imported JavaScript packages to Kotlin packages, using the following notation:

@file:JsModule("extModule")
package ext.jspackage.name

external fun foo()

external class C

where the corresponding JavaScript module is declared like this:

module.exports = {
    foo:  { /* some code here */ },
    C:  { /* some code here */ }
}

Important: files marked withĀ @file:JsModuleĀ annotation can’t declare non-external members. The example below produces compile-time error:

@file:JsModule("extModule")
package ext.jspackage.name

external fun foo()

fun bar() = "!" + foo() + "!" // error here

Importing deeper package hierarchies

In the previous example the JavaScript module exports a single package. However, some JavaScript libraries export multiple packages from within a module. This case is also supported by Kotlin, though you have to declare a newĀ .ktĀ file for each package you import.

For example, let’s make our example a bit more complicated:

module.exports = {
    mylib: {
        pkg1: {
            foo: function() { /* some code here */ },
            bar: function() { /* some code here */ }
        },
        pkg2: {
            baz: function() { /* some code here */ }
        }
    }
}

To import this module in Kotlin, you have to write two Kotlin source files:

@file:JsModule("extModule")
@file:JsQualifier("mylib.pkg1")
package extlib.pkg1

external fun foo()

external fun bar()

and

@file:JsModule("extModule")
@file:JsQualifier("mylib.pkg2")
package extlib.pkg2

external fun baz()

@JsNonModuleĀ annotation

When a declaration hasĀ @JsModule, you can’t use it from Kotlin code when you don’t compile it to a JavaScript module. Usually, developers distribute their libraries both as JavaScript modules and downloadableĀ .jsĀ files that you can copy to project’s static resources and include viaĀ HTML Script tag.

element. To tell Kotlin that it’s ok to use aĀ @JsModuleĀ declaration from non-module environment, you should putĀ @JsNonModuleĀ declaration. For example, given JavaScript code:

function topLevelSayHello(name) { alert("Hello, " + name); }
if (module && module.exports) {
    module.exports = topLevelSayHello;
}

can be described like this:

@JsModule("hello")
@JsNonModule
@JsName("topLevelSayHello")
external fun sayHello(name: String)

 

RELATED ARTICLES

Most Popular