改进翻译

JavaScript 模块

You can compile your Kotlin projects to JavaScript modules for various popular module systems. We currently support the following configurations for JavaScript modules:

面向浏览器

If you're targeting the browser and want to use a different module system than UMD, you can specify the desired module type in the webpackTask configuration block. For example, to switch to CommonJS, use:


kotlin {
    js {
        browser {
            webpackTask {
                output.libraryTarget = "commonjs2"
            }
        }
        binaries.executable()
    }
}

Webpack provides two different "flavors" of CommonJS, commonjs and commonjs2, which affect the way your declarations are made available. While in most cases, you probably want commonjs2, which adds the module.exports syntax to the generated library, you can also opt for the "pure" commonjs option, which implements the CommonJS specification exactly. To learn more about the difference between commonjs and commonjs2, check here.

创建 JavaScript 库与 Node.js 文件

If you are creating a library that will be consumed from JavaScript or a Node.js file, and want to use a different module system, the instructions are slightly different.

选择目标模块系统

To select module kind, set the moduleKind compiler option in the Gradle build script.

compileKotlinJs.kotlinOptions.moduleKind = "commonjs"

tasks.named<KotlinJsCompile>("compileKotlinJs").configure {
    kotlinOptions.moduleKind = "commonjs"
}

Available values are: umd (default), commonjs, amd, plain.

This is different from adjusting webpackTask.output.libraryTarget. The library target changes the output generated by webpack (after your code has already been compiled). kotlinOptions.moduleKind changes the output generated by the Kotlin compiler.

In the Kotlin Gradle DSL, there is also a shortcut for setting the CommonJS module kind:

kotlin {
    js {
         useCommonJs()
         // . . .
    }
}

@JsModule 注解

要告诉 Kotlin 一个 external 类、 包、 函数或者属性是一个 JavaScript 模块,你可以使用 @JsModule 注解。考虑你有以下 CommonJS 模块叫“hello”:

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

你应该在 Kotlin 中这样声明:

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

@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: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 注解

当一个声明标有 @JsModule、当你并不把它编译到一个 JavaScript 模块时,你不能在 Kotlin 代码中使用它。 通常,开发人员将他们的库既作为 JavaScript 模块也作为可下载的 .js 文件分发, 可以将这些文件复制到项目的静态资源,并通过 <script> 标签包含。 如需告诉 Kotlin,可以在非模块环境中使用一个 @JsModule 声明,请添加 @JsNonModule 注解。例如以下 JavaScript 代码:

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

在 Kotlin 中可以这样描述:

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

Module system used by the Kotlin Standard Library

Kotlin 以 Kotlin/JS 标准库作为单个文件分发,该文件本身被编译为 UMD 模块,因此你可以使用上述任何模块系统。While for most use cases of Kotlin/JS, it is recommended to use a Gradle dependency on kotlin-stdlib-js, 也在 NPM 上作为 kotlin 包提供。