Kotlin JavaScript模塊

Kotlin 允許你將 Kotlin 項目編譯爲熱門模塊系統的 JavaScript 模塊。以下是
可用選項的列表:

  1. 無模塊(Plain)。不爲任何模塊系統編譯。像往常一樣,你可以在全局作用域中以其名稱訪問模塊。
    默認使用此選項。
  2. 異步模塊定義(AMD,Asynchronous Module Definition),它尤其爲
    require.js 庫所使用。
  3. CommonJS 約定,廣泛用於 node.js/npm
    (require 函數和 module.exports 對象)
  4. 統一模塊定義(UMD,Unified Module Definitions),它與 AMDCommonJS 兼容,
    並且當在運行時 AMDCommonJS 都不可用時,作爲「plain」使用。

選擇目標模塊系統

選擇目標模塊系統的方式取決於你的構建環境:

在 IntelliJ IDEA 中

設置每個模塊:
打開「File → Project Structure…」,在「Modules」中找到你的模塊並選擇其下的「Kotlin」facet。在
「Module kind」字段中選擇合適的模塊系統。

爲整個項目設置:
打開「File → Settings」,選擇「Build, Execution, Deployment」→「Compiler」→「Kotlin compiler」。 在
「Module kind」字段中選擇合適的模塊系統。

在 Maven 中

要選擇通過 Maven 編譯時的模塊系統,你應該設置 moduleKind 配置屬性,即你的
pom.xml 應該看起來像這樣:

<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>
    <!-- 插入這些行 -->
    <configuration>
        <moduleKind>commonjs</moduleKind>
    </configuration>
    <!-- 插入文本結束 -->
</plugin>

可用值包括:plainamdcommonjsumd

在 Gradle 中

要選擇通過 Gradle 編譯時的模塊系統,你應該設置 moduleKind 屬性,即

compileKotlin2Js.kotlinOptions.moduleKind = "commonjs"

可用的值類似於 Maven。

[@JsModule](https://github.com/JsModule "@JsModule") 註解

要告訴 Kotlin 一個 external 類、 包、 函數或者屬性是一個 JavaScript 模塊,你可以使用 [@JsModule](https://github.com/JsModule "@JsModule")
註解。考慮你有以下 CommonJS 模塊叫「hello」:

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

你應該在 Kotlin 中這樣聲明:

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

[@JsModule](https://github.com/JsModule "@JsModule") 應用到包

一些 JavaScript 庫導出包(命名空間)而不是函數和類。
從 JavaScript 角度講 它是一個具有一些成員的對象,這些成員類、函數和屬性。
將這些包作爲 Kotlin 對象導入通常看起來不自然。
編譯器允許使用以下助記符將導入的 JavaScript 包映射到 Kotlin 包:

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

external fun foo()

external class C

其中相應的 JavaScript 模塊的聲明如下:

module.exports = {
    foo:  { /* 此處一些代碼 */ },
    C:  { /* 此處一些代碼 */ }
}

重要提示:標有 [@file](https://github.com/file "@file"):JsModule 註解的文件無法聲明非外部成員。
下面的示例會產生編譯期錯誤:

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

external fun foo()

fun bar() = "!" + foo() + "!" // 此處報錯

導入更深的包層次結構

在前文示例中,JavaScript 模塊導出單個包。
但是,一些 JavaScript 庫會從模塊中導出多個包。
Kotlin 也支持這種場景,儘管你必須爲每個導入的包聲明一個新的 .kt 文件。

例如,讓我們的示例更復雜一些:

module.exports = {
    mylib: {
        pkg1: {
            foo: function() { /* 此處一些代碼 */ },
            bar: function() { /* 此處一些代碼 */ }
        },
        pkg2: {
            baz: function() { /* 此處一些代碼 */ }
        }
    }
}

要在 Kotlin 中導入該模塊,你必須編寫兩個 Kotlin 源文件:

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

external fun foo()

external fun bar()

以及

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

external fun baz()

[@JsNonModule](https://github.com/JsNonModule "@JsNonModule") 註解

當一個聲明具有 [@JsModule](https://github.com/JsModule "@JsModule")、當你並不把它編譯到一個 JavaScript 模塊時,你不能在 Kotlin 代碼中使用它。
通常,開發人員將他們的庫既作爲 JavaScript 模塊也作爲可下載的.js 文件分發,你可以將這些文件複製到
項目的靜態資源,並通過 <script> 元素包含。 要告訴 Kotlin,可以
在非模塊環境中使用一個 [@JsModule](https://github.com/JsModule "@JsModule") 聲明,你應該放置 [@JsNonModule](https://github.com/JsNonModule "@JsNonModule") 聲明。例如,
給定 JavaScript 代碼:

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

可以這樣描述:

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

備註

Kotlin 以 kotlin.js 標準庫作爲單個文件分發,該文件本身被編譯爲 UMD 模塊,因此
你可以使用上述任何模塊系統。也可以在 NPM 上使用 kotlin