# 设置 Kotlin/JS 工程(Project) Kotlin JavaScript 工程(Project) 使用 Gradle 进行编译. 为了方便开发者管理 Kotlin JavaScript 工程, 我们提供了 `kotlin.multiplatform` Gradle 插件, 其中包括工程配置工具, 以及对 JavaScript 开发中常见业务进行自动化处理的帮助性任务. 这个插件会在后台使用 [npm](https://www.npmjs.com/) 或 [Yarn](https://yarnpkg.com/) 包管理器下载 npm 依赖项, 并使用 [webpack](https://webpack.js.org/) 将 Kotlin 工程编译为 JavaScript bundle . 依赖项管理和配置调整大部分可以直接在 Gradle 构建脚本文件中完成, 还可以通过选项覆盖自动生成的配置, 获得完全的控制能力. 你可以在 Gradle 工程的 `build.gradle(.kts)` 文件中手动的应用 `org.jetbrains.kotlin.multiplatform` 插件: Kotlin: ```KOTLIN plugins { kotlin("multiplatform") version "2.4.20" } ``` Groovy: ```GROOVY plugins { id 'org.jetbrains.kotlin.multiplatform' version '2.4.20' } ``` 通过 Kotlin Multiplatform Gradle 插件, 你可以在编译脚本的 `kotlin` 节中管理工程的各方面设置. ```GROOVY kotlin { // ... } ``` 在 `kotlin {}` 代码段中, 你可以管理以下方面: * [目标执行环境](#execution-environments): 浏览器, 或 Node.js * [支持 ES2015 功能](#support-for-es2015-features): 类, 模块, 和生成器 * [配置输出粒度](#configure-output-granularity) * [生成 TypeScript 声明文件](#generation-of-typescript-declaration-files-d-ts) * [工程的依赖项目管理](#dependencies): Maven 或 npm * [运行配置(configuration)](#run-task) * [测试配置(configuration)](#test-task) * 对于浏览器工程的 [打包(Bundling)](#webpack-bundling) 和 [CSS 支持](#css) * [目标目录](#distribution-target-directory) 和 [模块名称](#module-name) * [工程的 package.json 文件](#package-json-customization) ## 执行环境 Kotlin/JS 工程可以运行于两种不同的执行环境: * 浏览器环境, 用于浏览器内运行的客户端脚本 * [Node.js](https://nodejs.org/), 在浏览器之外运行 JavaScript 代码, 比如, 运行服务器端脚本. 要为 Kotlin/JS 工程定义目标运行环境, 需要添加 `js {}` 代码段, 其中包含 `browser {}` 或 `nodejs {}`: ```GROOVY kotlin { js { browser { } binaries.executable() } } ``` `binaries.executable()` 指令明确的指示 Kotlin 编译器输出可执行的 `.js` 文件. 省略 `binaries.executable()` 会导致编译器只生成 Kotlin-internal 库文件, 这些库文件可以被其他项目使用, 但不能独立运行. > **Tip:** > 与创建可执行文件相比, 这样通常会更快, 而且在处理你项目中的非叶(non-leaf)模块时, 这是一种可能的优化. Kotlin Multiplatform 插件会针对选定的运行环境, 自动配置它的编译任务. 包括下载并安装应用程序运行和测试所需要的环境和依赖项目, 因此开发者可以编译, 运行, 以及测试简单的工程, 而无需再添加更多配置. 对于编译目标为 Node.js 的项目, 还有一个选项可以使用本地已安装的 Node.js. 详情请参见 [使用已安装的 Node.js](#use-pre-installed-node-js). ## 支持 ES2015 功能 Kotlin 支持 ES2015 功能, 包括: * 模块: 简化你的代码库, 提高可维护性的. * 类: 可以结合 OOP 原则, 产生更清晰, 更直观的代码. * 用于编译 [挂起函数](composing-suspending-functions.html) 的生成器: 能够改善最终 bundle 的大小, 并帮助进行调试. * [内联 JavaScript 代码](js-interop.html#inline-javascript). 你可以向你的 `build.gradle(.kts)` 文件添加 `es2015` 编译目标, 一次性启用所有支持的 ES2015 功能: ```KOTLIN tasks.withType().configureEach { compilerOptions { target = "es2015" } } ``` [关于 ES2015 (ECMAScript 2015, ES6), 更多详情请参见官方文档](https://262.ecma-international.org/6.0/). ## 配置输出粒度 你可以选择让编译器在你的项目中如何输出 `.js` 文件: * 对每个模块输出 `.js` 文件. 默认情况下, JS 编译器的编译结果是对项目的每个模块输出单独的 `.js` 文件. * 对每个项目输出 `.js` 文件. 你也可以将整个项目编译为单个 `.js` 文件, 方法是向 `gradle.properties` 文件添加以下设置: ```PROPERTIES kotlin.js.ir.output.granularity=whole-program // 默认值是 'per-module' ``` * 对每个文件输出 `.js` 文件. 你也可以设置更加细粒度的输出, 为每个 Kotlin 文件生成 1 个 JavaScript 文件 (如果 Kotlin 文件包含导出的声明, 则会生成 2 个 JavaScript 文件). 启用这个模式的方法如下: 1. 将 [编译目标](#support-for-es2015-features) 设置为 `es2015`, 在你的项目中支持 ES2015 功能. 2. 将以下内容添加到 `gradle.properties` 文件: ```PROPERTIES kotlin.js.ir.output.granularity=per-file // 默认值是 'per-module' ``` ## 生成 TypeScript 声明文件 (`d.ts`) Kotlin/JS 编译器能够从你的 Kotlin 代码生成 TypeScript 定义. 在开发混合 App(Hybrid App)时, JavaScript 工具和 IDE 可以使用这些定义实现以下功能: * 提供代码自动完成 * 支持静态分析 * 简化在 JavaScript 和 TypeScript 项目中添加 Kotlin 代码的过程 生成 TypeScript 定义对于 [共用业务逻辑的使用场景](js-overview.html#use-cases-for-kotlin-js) 尤其有用. 编译器会收集所有标注了 [@JsExport](js-to-kotlin-interop.html#jsexport-annotation) 注解的顶级声明, 并自动在一个 `.d.ts` 文件中生成 TypeScript 定义. 要生成 TypeScript 定义, 请在你的 Gradle 构建文件中明确进行配置. 请在你的 `build.gradle.kts` 文件的 [js {} 代码段](#execution-environments) 中添加 `generateTypeScriptDefinitions()` 函数: ```KOTLIN kotlin { js { binaries.executable() browser { } generateTypeScriptDefinitions() } } ``` 这些声明位于 `build/js/packages//kotlin` 目录中, 与相应的未经 webpack 处理的 JavaScript 代码在一起. ## 依赖项目 与其他 Gradle 工程一样, Kotlin/JS 工程编译脚本的 `dependencies {}` 代码段内, 支持添加传统的 Gradle [依赖项目声明](https://docs.gradle.org/current/userguide/declaring_dependencies.html): Kotlin: ```KOTLIN dependencies { implementation("org.example.myproject", "1.1.0") } ``` Groovy: ```GROOVY dependencies { implementation 'org.example.myproject:1.1.0' } ``` Kotlin Multiplatform Gradle 插件也支持在编译脚本的 `kotlin {}` 代码段中添加特定源代码集合(source set)的依赖项目声明: Kotlin: ```KOTLIN kotlin { sourceSets { val jsMain by getting { dependencies { implementation("org.example.myproject:1.1.0") } } } } ``` Groovy: ```GROOVY kotlin { sourceSets { jsMain { dependencies { implementation 'org.example.myproject:1.1.0' } } } } ``` > **Note:** > 并不是 Kotlin 编程语言中所有可用的库在 JavaScript 平台都可用: 只有那些包含针对 Kotlin/JS 的 artifact 的库才能使用. 如果你添加的库依赖于 [来自 npm 的包](#npm-dependencies), Gradle 也会自动解析这些传递性依赖项. ### Kotlin 标准库 对 [标准库](https://kotlinlang.org/api/latest/jvm/stdlib/index.html) 的依赖项会自动添加. 标准库的版本与 Kotlin Multiplatform 插件的版本相同. 对于跨平台的测试, 可以使用 [kotlin.test](https://kotlinlang.org/api/latest/kotlin.test/) API. 当你创建跨平台项目时, 你可以在 `commonTest` 中使用一个依赖项, 对所有的源代码集添加测试依赖项: Kotlin: ```KOTLIN kotlin { sourceSets { commonTest.dependencies { implementation(kotlin("test")) // 会自动引入所有的平台依赖项 } } } ``` Groovy: ```GROOVY kotlin { sourceSets { commonTest { dependencies { implementation kotlin("test") // 会自动引入所有的平台依赖项 } } } } ``` ### npm 依赖项目 在 JavaScript 的世界中, 管理依赖项目的最常见方式是 [npm](https://www.npmjs.com/). 它提供了各种 JavaScript 模块(module) 的最大的公共仓库(repository). 通过 Kotlin Multiplatform Gradle 插件, 可以在 Gradle 编译脚本中声明 npm 依赖项目, 方法和声明其他依赖项目类似. 要声明一个 npm 依赖项目, 可以在一个依赖项目声明中使用 `npm()` 函数指定依赖项目的名称和版本. 也可以使用 [npm semver 语法](https://docs.npmjs.com/about-semantic-versioning), 指定一个或多个版本范围. Kotlin: ```KOTLIN dependencies { implementation(npm("react", "> 14.0.0 <=16.9.0")) } ``` Groovy: ```GROOVY dependencies { implementation npm('react', '> 14.0.0 <=16.9.0') } ``` 默认情况下, 插件会使用 [Yarn](https://yarnpkg.com/lang/en/) 包管理器的一个单独的实例, 来下载和安装 npm 依赖项. 不需要额外配置, 默认即可工作, 但你也可以 [根据需要对其进行调整](#yarn). 你也可以通过 [npm](https://www.npmjs.com/) 包管理器直接使用 npm 依赖项. 要使用 npm 作为你的包管理器, 请在你的 `gradle.properties` 文件中, 设置以下属性: ```PROPERTIES kotlin.js.yarn=false ``` 除了标准依赖项之外, 在 Gradle DSL 中使用还可以使用 3 种其他类型的依赖项. 关于什么情况下应该选择什么类型的依赖项, 请阅读 npm 提供的官方文档: * [devDependencies](https://docs.npmjs.com/files/package.json#devdependencies), 通过 `devNpm(...)` 使用, * [optionalDependencies](https://docs.npmjs.com/files/package.json#optionaldependencies) 通过 `optionalNpm(...)` 使用, 以及 * [peerDependencies](https://docs.npmjs.com/files/package.json#peerdependencies) 如果 `peerNpm(...)` 使用. 一个 npm 依赖项目安装完成之后, 你就可以如 [在 Kotlin 中调用 JavaScript](js-interop.html) 中介绍过的那样, 在你的代码中使用它的 API. ## run 任务 Kotlin Multiplatform Gradle 插件提供了一个 `jsBrowserDevelopmentRun` 任务, 它可以运行你的纯 Kotlin/JS 工程, 无需额外的配置. 对于在浏览器内运行 Kotlin/JS 工程的情况, 这个是 `browserDevelopmentRun` 任务的一个别名(在 Kotlin 跨平台项目也可以使用). 它使用 [webpack DevServer](https://webpack.js.org/configuration/dev-server/) 来提供你的 JavaScript artifact. 如果你想要自定义 DevServer 的配置, 例如, 改变端口号, 请使用 [webpack 配置文件](#webpack-bundling). 对于在 Node.js 平台运行 Kotlin/JS 项目的情况, 请使用 `jsNodeDevelopmentRun` 任务, 它是 `nodeRun` 任务的别名. 要运行一个工程, 请执行 Gradle 编译周期(lifecycle)中标准的 `jsBrowserDevelopmentRun` 任务, 或者运行它作为别名对应的真实的任务: ```BASH ./gradlew jsBrowserDevelopmentRun ``` 如果要在修改过源代码文件后自动对你的应用程序进行重新构建, 可以使用 Gradle 的 [连续构建(continuous build)](https://docs.gradle.org/current/userguide/command_line_interface.html#sec:continuous_build) 功能: ```BASH ./gradlew jsBrowserDevelopmentRun --continuous ``` 或者 ```BASH ./gradlew jsBrowserDevelopmentRun -t ``` 工程构建成功后, `webpack-dev-server` 会自动刷新浏览器页面. ## test 任务 Kotlin Multiplatform Gradle 插件会为工程自动设置测试环境. 对于浏览器工程, 它会下载并安装测试运行器 [Karma](https://karma-runner.github.io/), 以及相关的依赖项目; 对于 Node.js 项目, 会使用 [Mocha](https://mochajs.org/) 测试框架. 插件还提供了很多有用的测试功能, 比如: * 生成源代码文件映射(Source map) * 生成测试报告(Test report) * 在控制台输出测试运行结果 为了运行浏览器中的测试, 插件会默认使用 [Headless Chrome](https://chromium.googlesource.com/chromium/src/+/lkgr/headless/README.md). 你也可以选择其他浏览器来运行测试, 方法是在编译脚本的 `useKarma {}` 代码段中添加相应的设置: ```GROOVY kotlin { js { browser { testTask { useKarma { useIe() useSafari() useFirefox() useChrome() useChromeCanary() useChromeHeadless() usePhantomJS() useOpera() } } } binaries.executable() // ... } } ``` 或者你也可以在 `gradle.properties` 文件中添加测试的目标浏览器: ```PROPERTIES kotlin.js.browser.karma.browsers=firefox,safari ``` 通过这种方法, 你可以为所有的模块定义一组浏览器, 然后在某些模块的构建脚本中添加特定的浏览器. 请注意, Kotlin Multiplatform Gradle 插件不会为你自动安装这些浏览器, 而只是使用那些在它的运行环境中可用的浏览器. 比如说, 如果在一个持续集成服务器上运行 Kotlin/JS 测试, 请注意确保安装了你需要测试的浏览器. 如果想要跳过测试, 可以在 `testTask {}` 代码段中添加 `enabled = false` 设置. ```GROOVY kotlin { js { browser { testTask { enabled = false } } binaries.executable() // ... } } ``` 要运行测试, 请执行 Gradle 编译周期(lifecycle)中标准的 `check` 任务: ```BASH ./gradlew check ``` 如果要指定你的 Node.js 测试运行器使用的环境变量 (比如, 向你的测试代码传递外部信息, 或对包的解析进行微调), 可以在你的构建脚本的 `testTask {}` 代码段中使用 `environment()` 函数, 参数是键-值对: ```GROOVY kotlin { js { nodejs { testTask { environment("key", "value") } } } } ``` ## 配置 Karma Kotlin Multiplatform Gradle 插件会在构建时自动生成 Karma 配置文件, 其中包括你的 `build.gradle(.kts)` 文件中的 [kotlin.js.browser.testTask.useKarma {} 代码段](#test-task) 中的设置. 你可以在 `build/js/packages/projectName-test/karma.conf.js` 找到这个文件. 要调整 Karma 所使用的配置, 请将你的额外配置文件 放在你的项目根目录的 `karma.config.d` 目录之下. 在构建时, 这个目录下的所有 `.js` 配置文件都会被读取, 并自动合并到生成的 `karma.conf.js` 文件中. Karma 配置的详细功能请参见 Karma 的 [文档](https://karma-runner.github.io/5.0/config/configuration-file.html). ## webpack 打包(Bundling) 如果编译目标为浏览器环境, Kotlin Multiplatform Gradle 插件使用大家都熟悉的 [webpack](https://webpack.js.org/) 来打包模块. ### webpack 版本 Kotlin Multiplatform 插件使用 webpack 5. 如果你的项目通过 plugin 1.5.0 以前版本创建, 那么可以在你的项目的 `gradle.properties` 文件中添加以下设置, 临时切换回这些版本使用的 webpack 4: ```PROPERTIES kotlin.js.webpack.major.version=4 ``` ### webpack 任务 在 Gradle 编译脚本的 `kotlin.js.browser.webpackTask {}` 配置代码段中, 可以直接调整最常见的 webpack 配置: * `outputFileName` - webpack 的输出文件名称. 执行webpack 任务之后, 这个文件将生成在 `/build/dist/` 文件夹内. 默认值是工程名称. * `output.libraryTarget` - 用于 webpack 输出文件的模块系统. 详情请参见 [Kotlin/JS 工程可用的模块系统](js-modules.html). 默认值是 `umd`. ```GROOVY webpackTask { outputFileName = "mycustomfilename.js" output.libraryTarget = "commonjs2" } ``` 还可以在 `commonWebpackConfig {}` 代码段中配置 webpack 的共通设置, 用于打包(bundling), 运行, 以及测试任务. ### webpack 配置文件 Kotlin Multiplatform Gradle plugin 在构建时会自动生成一个标准的 webpack 配置文件. 位置是 `build/js/packages/projectName/webpack.config.js`. 如果还想对 webpack 配置进行进一步的调整, 请将你的额外的配置文件放在你的工程的 `webpack.config.d` 目录内. 编译你的工程时, 所有的 `.js` 配置文件都会被自动合并到 `build/js/packages/projectName/webpack.config.js` 文件内. 比如, 如果要添加一个新的 [webpack loader](https://webpack.js.org/loaders/), 请要把以下内容添加到 `webpack.config.d` 目录内的一个 `.js` 中: > **Note:** > 这种情况下, 配置对象是全局对象 `config`. 你需要在你的脚本中修改这个对象. ```GROOVY config.module.rules.push({ test: /\.extension$/, loader: 'loader-name' }); ``` 关于 webpack 的所有配置项目, 请参见它的 [文档](https://webpack.js.org/concepts/configuration/). ### 构建可执行文件 要通过 webpack 编译可执行的 JavaScript artifact, Kotlin Multiplatform Gradle 插件包含 Gradle 任务 `browserDevelopmentWebpack` 和 `browserProductionWebpack`. * `browserDevelopmentWebpack` 创建开发模式的 artifact, 文件尺寸会比较大, 但构建时间比较短. 因此, 在活跃开发阶段请使用 `browserDevelopmentWebpack` 任务. * `browserProductionWebpack` 会执行死代码消除, 生成 artifact 文件, 并对输出结果的 JavaScript 文件最小化, 构建时间更长, 但生成的可执行文件尺寸更小. 因此, 在构建你的项目用于生成目的时, 请使用 `browserProductionWebpack` 任务. 执行这两个任务可以分别得到开发模式和生产模式的 artifact 文件. 生成的文件会在 `build/dist` 目录下, 除非 [另有设置](#distribution-target-directory). ```BASH ./gradlew browserProductionWebpack ``` 注意, 只有在你的编译目标设置为生成可执行文件 (通过 `binaries.executable()`) 时, 这些任务才可用. ## CSS Kotlin Multiplatform Gradle 创建还支持 webpack 的 [CSS](https://webpack.js.org/loaders/css-loader/) 和 [style](https://webpack.js.org/loaders/style-loader/) 装载器. 虽然所有的选项都可以直接修改构建你的项目的 [webpack 配置文件](#webpack-bundling), 但最常用的方法是使用 `build.gradle(.kts)` 中直接可用的设定. 要在你的项目中打开 CSS 支持, 请在 Gradle 构建文件的 `commonWebpackConfig {}` 代码段中设置 `cssSupport.enabled` 选项. 通过 IDE 向导创建新工程时, 这个配置也会默认启用. Kotlin: ```KOTLIN browser { commonWebpackConfig { cssSupport { enabled.set(true) } } } ``` Groovy: ```GROOVY browser { commonWebpackConfig { cssSupport { it.enabled = true } } } ``` 或者, 也可以单独对 `webpackTask {}`, `runTask {}`, 和 `testTask {}` 添加 CSS 支持: Kotlin: ```KOTLIN browser { webpackTask { cssSupport { enabled.set(true) } } runTask { cssSupport { enabled.set(true) } } testTask { useKarma { // ... webpackConfig.cssSupport { enabled.set(true) } } } } ``` Groovy: ```GROOVY browser { webpackTask { cssSupport { it.enabled = true } } runTask { cssSupport { it.enabled = true } } testTask { useKarma { // ... webpackConfig.cssSupport { it.enabled = true } } } } ``` 对你的项目打开 CSS 支持, 有助于防止在未配置的项目中使用样式表时发生的常见错误, 比如 `Module parse failed: Unexpected character '@' (14:0)`. 可以使用 `cssSupport.mode` 来指定 CSS 应该如何处理. 可选的设定值如下: * `"inline"` (默认值): 样式添加到全局的 `