JavaScript 模块
You can compile your Kotlin projects to JavaScript modules for various popular module systems. We currently support the following configurations for JavaScript modules:
- 统一模块定义(UMD,Unified Module Definitions),它与 AMD 和 CommonJS 兼容。UMD modules are also able to be executed without being imported or when no module system is present. This is the default option for the
browser
andnodejs
targets. - 异步模块定义(AMD,Asynchronous Module Definition),它尤其为 RequireJS 库所使用。
- CommonJS,广泛用于 Node.js/npm
(
require
函数和module.exports
对象) - 无模块(Plain)。不为任何模块系统编译。可以在全局作用域中以其名称访问模块。
面向浏览器
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
包提供。