diff --git a/build.gradle.kts b/build.gradle.kts index e5ae000b88b..71db9cc0259 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -503,10 +503,10 @@ tasks { ":kotlin-test:kotlin-test-js-ir:kotlin-test-js-ir-it".takeIf { !kotlinBuildProperties.isInJpsBuildIdeaSync }, ":kotlinx-metadata-jvm", ":tools:binary-compatibility-validator", + //":kotlin-stdlib-wasm", )).forEach { dependsOn("$it:check") } - dependsOn(":kotlin-stdlib-wasm:runWasmStdLibTestsWithD8") //Instead of :kotlin-stdlib-wasm:check } register("gradlePluginTest") { diff --git a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JSCompilerArguments.kt b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JSCompilerArguments.kt index 5fcddbc3bf7..bae81f0d29c 100644 --- a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JSCompilerArguments.kt +++ b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2JSCompilerArguments.kt @@ -249,13 +249,6 @@ class K2JSCompilerArguments : CommonCompilerArguments() { @Argument(value = "-Xwasm-debug-info", description = "Add debug info to WebAssembly compiled module") var wasmDebug: Boolean by FreezableVar(true) - @Argument( - value = "-Xwasm-launcher", - valueDescription = "esm|nodejs|d8", - description = "Picks flavor for the wasm launcher. Default is ESM." - ) - var wasmLauncher: String? by NullableStringFreezableVar("esm") - @Argument(value = "-Xwasm-kclass-fqn", description = "Enable support for FQ names in KClass") var wasmKClassFqn: Boolean by FreezableVar(false) diff --git a/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/K2JsIrCompiler.kt b/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/K2JsIrCompiler.kt index e6f4ea9b289..c018295def0 100644 --- a/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/K2JsIrCompiler.kt +++ b/compiler/cli/cli-js/src/org/jetbrains/kotlin/cli/js/K2JsIrCompiler.kt @@ -11,7 +11,6 @@ import com.intellij.openapi.util.text.StringUtil import org.jetbrains.kotlin.backend.common.CompilationException import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig import org.jetbrains.kotlin.backend.common.serialization.metadata.KlibMetadataVersion -import org.jetbrains.kotlin.backend.wasm.WasmLoaderKind import org.jetbrains.kotlin.backend.wasm.compileWasm import org.jetbrains.kotlin.backend.wasm.compileToLoweredIr import org.jetbrains.kotlin.backend.wasm.wasmPhases @@ -362,18 +361,9 @@ class K2JsIrCompiler : CLICompiler() { generateWat = true, ) - val launcherKind = when (arguments.wasmLauncher) { - "esm" -> WasmLoaderKind.BROWSER - "nodejs" -> WasmLoaderKind.NODE - "d8" -> WasmLoaderKind.D8 - "d8NodeCompatible" -> WasmLoaderKind.D8NodeCompatible - else -> throw IllegalArgumentException("Unrecognized flavor for the wasm launcher") - } - writeCompilationResult( result = res, dir = outputFile.parentFile, - loaderKind = launcherKind, fileNameBase = outputFile.nameWithoutExtension ) diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/compiler.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/compiler.kt index 33abb577bf3..386c7aa61f8 100644 --- a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/compiler.kt +++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/compiler.kt @@ -120,66 +120,49 @@ fun WasmCompiledModuleFragment.generateJs(): String { return runtime + jsCode } -enum class WasmLoaderKind { - D8, - D8NodeCompatible, - NODE, - BROWSER, -} - -fun generateJsWasmLoader(kind: WasmLoaderKind, wasmFilePath: String, externalJs: String): String { - val nodeExitOnD8 = - if (kind == WasmLoaderKind.D8NodeCompatible) "if ((typeof process !== 'undefined') && (typeof process.versions.node !== 'undefined')) process.exit(0)\n" - else "" - - val instantiation = when (kind) { - WasmLoaderKind.D8, WasmLoaderKind.D8NodeCompatible -> - """ - const wasmModule = new WebAssembly.Module(read('$wasmFilePath', 'binary')); - const wasmInstance = new WebAssembly.Instance(wasmModule, { js_code }); - """.trimIndent() - - WasmLoaderKind.NODE -> - """ - const fs = require('fs'); - var path = require('path'); - const wasmBuffer = fs.readFileSync(path.resolve(__dirname, './$wasmFilePath')); - const wasmModule = new WebAssembly.Module(wasmBuffer); - const wasmInstance = new WebAssembly.Instance(wasmModule, { js_code }); - """.trimIndent() - - WasmLoaderKind.BROWSER -> - """ - const { instance: wasmInstance } = await WebAssembly.instantiateStreaming(fetch("$wasmFilePath"), { js_code }); - """.trimIndent() +fun generateJsWasmLoader(wasmFilePath: String, externalJs: String): String = + externalJs + """ + + const isNodeJs = (typeof process !== 'undefined') && (process.release.name === 'node'); + const isD8 = !isNodeJs && (typeof d8 !== 'undefined'); + const isBrowser = !isNodeJs && !isD8 && (typeof window !== 'undefined'); + + if (!isNodeJs && !isD8 && !isBrowser) { + throw "Supported JS engine not detected"; } - - val init = - """ - - const wasmExports = wasmInstance.exports; - wasmExports.__init(); - wasmExports.startUnitTests?.(); - - """.trimIndent() - - val export = when (kind) { - WasmLoaderKind.D8, WasmLoaderKind.BROWSER -> - "export default wasmExports;\n" - - WasmLoaderKind.NODE -> - "module.exports = wasmExports;\n" - - WasmLoaderKind.D8NodeCompatible -> "" + + let wasmInstance; + let require; // Placed here to give access to it from externals (js_code) + if (isNodeJs) { + const module = await import('node:module'); + require = module.createRequire(import.meta.url); + const fs = require('fs'); + const path = require('path'); + const url = require('url'); + const __dirname = url.fileURLToPath(new URL('.', import.meta.url)); + const wasmBuffer = fs.readFileSync(path.resolve(__dirname, './$wasmFilePath')); + const wasmModule = new WebAssembly.Module(wasmBuffer); + wasmInstance = new WebAssembly.Instance(wasmModule, { js_code }); } - - return nodeExitOnD8 + externalJs + instantiation + init + export -} + + if (isD8) { + const wasmBuffer = read('$wasmFilePath', 'binary'); + const wasmModule = new WebAssembly.Module(wasmBuffer); + wasmInstance = new WebAssembly.Instance(wasmModule, { js_code }); + } + + if (isBrowser) { + wasmInstance = (await WebAssembly.instantiateStreaming(fetch('$wasmFilePath'), { js_code })).instance; + } + + const wasmExports = wasmInstance.exports; + wasmExports.__init(); + export default wasmExports; + """.trimIndent() fun writeCompilationResult( result: WasmCompilerResult, dir: File, - loaderKind: WasmLoaderKind, fileNameBase: String = "index", ) { dir.mkdirs() @@ -187,6 +170,7 @@ fun writeCompilationResult( File(dir, "$fileNameBase.wat").writeText(result.wat) } File(dir, "$fileNameBase.wasm").writeBytes(result.wasm) - val jsWithLoader = generateJsWasmLoader(loaderKind, "./$fileNameBase.wasm", result.js) - File(dir, "$fileNameBase.js").writeText(jsWithLoader) + + val jsWithLoader = generateJsWasmLoader("./$fileNameBase.wasm", result.js) + File(dir, "$fileNameBase.mjs").writeText(jsWithLoader) } diff --git a/compiler/testData/cli/js/jsExtraHelp.out b/compiler/testData/cli/js/jsExtraHelp.out index 9027bd8ca8c..8ce6a898960 100644 --- a/compiler/testData/cli/js/jsExtraHelp.out +++ b/compiler/testData/cli/js/jsExtraHelp.out @@ -45,7 +45,6 @@ where advanced options include: Turn on range checks for the array access functions -Xwasm-enable-asserts Turn on asserts -Xwasm-kclass-fqn Enable support for FQ names in KClass - -Xwasm-launcher=esm|nodejs|d8 Picks flavor for the wasm launcher. Default is ESM. -Xallow-kotlin-package Allow compiling code in package 'kotlin' and allow not requiring kotlin.stdlib in module-info -Xallow-result-return-type Allow compiling code when `kotlin.Result` is used as a return type -Xbuiltins-from-sources Compile builtIns from sources diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/testOld/BasicWasmBoxTest.kt b/js/js.tests/test/org/jetbrains/kotlin/js/testOld/BasicWasmBoxTest.kt index a9801f30bae..c0a442f49b2 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/testOld/BasicWasmBoxTest.kt +++ b/js/js.tests/test/org/jetbrains/kotlin/js/testOld/BasicWasmBoxTest.kt @@ -148,7 +148,7 @@ abstract class BasicWasmBoxTest( ) val testJsQuiet = """ - import exports from './index.js'; + import exports from './index.mjs'; let actualResult try { @@ -176,19 +176,19 @@ abstract class BasicWasmBoxTest( val path = dir.absolutePath println(" ------ $name WAT file://$path/index.wat") println(" ------ $name WASM file://$path/index.wasm") - println(" ------ $name JS file://$path/index.js") - println(" ------ $name Test file://$path/test.js") + println(" ------ $name JS file://$path/index.mjs") + println(" ------ $name Test file://$path/test.mjs") } - writeCompilationResult(res, dir, WasmLoaderKind.D8) - File(dir, "test.js").writeText(testJs) + writeCompilationResult(res, dir) + File(dir, "test.mjs").writeText(testJs) ExternalTool(System.getProperty("javascript.engine.path.V8")) .run( "--experimental-wasm-gc", "--experimental-wasm-eh", *jsFilesBefore.map { File(it).absolutePath }.toTypedArray(), "--module", - "./test.js", + "./test.mjs", *jsFilesAfter.map { File(it).absolutePath }.toTypedArray(), workingDirectory = dir ) @@ -200,14 +200,14 @@ abstract class BasicWasmBoxTest( if (debugMode >= DebugMode.SUPER_DEBUG) { fun writeBrowserTest(name: String, res: WasmCompilerResult) { val dir = File(outputDirBase, name) - writeCompilationResult(res, dir, WasmLoaderKind.BROWSER) - File(dir, "test.js").writeText(testJsVerbose) + writeCompilationResult(res, dir) + File(dir, "test.mjs").writeText(testJsVerbose) File(dir, "index.html").writeText( """ - + """.trimIndent() @@ -215,8 +215,8 @@ abstract class BasicWasmBoxTest( val path = dir.absolutePath println(" ------ $name WAT file://$path/index.wat") println(" ------ $name WASM file://$path/index.wasm") - println(" ------ $name JS file://$path/index.js") - println(" ------ $name TEST file://$path/test.js") + println(" ------ $name JS file://$path/index.mjs") + println(" ------ $name TEST file://$path/test.mjs") println(" ------ $name HTML file://$path/index.html") } diff --git a/libraries/stdlib/wasm/build.gradle.kts b/libraries/stdlib/wasm/build.gradle.kts index a99c7d93d0c..f0b5d088bdc 100644 --- a/libraries/stdlib/wasm/build.gradle.kts +++ b/libraries/stdlib/wasm/build.gradle.kts @@ -1,6 +1,5 @@ import org.jetbrains.kotlin.gradle.dsl.KotlinCompile import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrLink -import java.io.OutputStream plugins { `maven-publish` @@ -77,13 +76,7 @@ val commonTestSources by task { kotlin { wasm { - nodejs { - testTask { - useMocha { - timeout = "10s" - } - } - } + nodejs() } sourceSets { @@ -144,33 +137,7 @@ val compileTestKotlinWasm by tasks.existing(KotlinCompile::class) { } val compileTestDevelopmentExecutableKotlinWasm = tasks.named("compileTestDevelopmentExecutableKotlinWasm") { - (this as KotlinCompile<*>).kotlinOptions.freeCompilerArgs += listOf("-Xwasm-enable-array-range-checks", "-Xwasm-launcher=d8") -} - -val runWasmStdLibTestsWithD8 by tasks.registering(Exec::class) { - dependsOn(":js:js.tests:unzipV8") - dependsOn(compileTestDevelopmentExecutableKotlinWasm) - - val unzipV8Task = tasks.getByPath(":js:js.tests:unzipV8") - val d8Path = File(unzipV8Task.outputs.files.single(), "d8") - executable = d8Path.toString() - - val compiledFile = compileTestDevelopmentExecutableKotlinWasm - .get() - .kotlinOptions - .outputFile - ?.let { File(it) } - check(compiledFile != null) - - if (System.getenv("TEAMCITY_VERSION") == null) { - standardOutput = object : OutputStream() { - override fun write(b: Int) = Unit - } - errorOutput = standardOutput - } - - workingDir = compiledFile.parentFile - args = listOf("--experimental-wasm-gc", "--experimental-wasm-eh", "--module", compiledFile.name) + (this as KotlinCompile<*>).kotlinOptions.freeCompilerArgs += listOf("-Xwasm-enable-array-range-checks") } val runtimeElements by configurations.creating {} diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/KotlinJsPlatformTestRun.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/KotlinJsPlatformTestRun.kt index ff053e30b44..b0d5485e942 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/KotlinJsPlatformTestRun.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/KotlinJsPlatformTestRun.kt @@ -14,6 +14,7 @@ import org.jetbrains.kotlin.gradle.plugin.KotlinTargetTestRun import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsSubTargetContainerDsl import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsSubTargetDsl +import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinWasmSubTargetContainerDsl import org.jetbrains.kotlin.gradle.targets.js.testing.KotlinJsTest import org.jetbrains.kotlin.gradle.testing.KotlinReportAggregatingTestRun import org.jetbrains.kotlin.gradle.testing.KotlinTaskTestRun @@ -82,6 +83,7 @@ open class KotlinJsReportAggregatingTestRun( target.whenBrowserConfigured { doConfigureInChildren(this) } target.whenNodejsConfigured { doConfigureInChildren(this) } + (target as? KotlinWasmSubTargetContainerDsl)?.whenD8Configured { doConfigureInChildren(this) } } override fun filter(configureFilter: Closure<*>) = filter { target.project.configure(this, configureFilter) } diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinBrowserJsIr.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinBrowserJsIr.kt index aeda6d8405a..07b5275f939 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinBrowserJsIr.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinBrowserJsIr.kt @@ -63,9 +63,6 @@ open class KotlinBrowserJsIr @Inject constructor(target: KotlinJsIrTarget) : } } - override val additionalCompilerOption: String? - get() = "-Xwasm-launcher=esm".takeIf { target.platformType == KotlinPlatformType.wasm } - override fun commonWebpackConfig(body: KotlinWebpackConfig.() -> Unit) { webpackTaskConfigurations.add { webpackConfigApplier(body) diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinD8Ir.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinD8Ir.kt index 6d88bb140cb..11ea69c6c5b 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinD8Ir.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinD8Ir.kt @@ -5,7 +5,6 @@ package org.jetbrains.kotlin.gradle.targets.js.ir -import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType import org.jetbrains.kotlin.gradle.targets.js.d8.D8Exec import org.jetbrains.kotlin.gradle.targets.js.d8.D8RootPlugin import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinWasmD8Dsl @@ -34,7 +33,4 @@ open class KotlinD8Ir @Inject constructor(target: KotlinJsIrTarget) : override fun configureTestDependencies(test: KotlinJsTest) { test.dependsOn(d8.setupTaskProvider) } - - override val additionalCompilerOption: String? - get() = "-Xwasm-launcher=d8".takeIf { target.platformType == KotlinPlatformType.wasm } } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsBinaryContainer.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsBinaryContainer.kt index 900a0f24367..97b6bd6dec1 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsBinaryContainer.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsBinaryContainer.kt @@ -52,6 +52,10 @@ constructor( (this as KotlinJsIrSubTarget).produceExecutable() } + target.whenD8Configured { + (this as KotlinJsIrSubTarget).produceExecutable() + } + return compilation.binaries.executableIrInternal(compilation) } @@ -106,6 +110,10 @@ constructor( (this as KotlinJsIrSubTarget).produceLibrary() } + target.whenD8Configured { + (this as KotlinJsIrSubTarget).produceLibrary() + } + return createBinaries( compilation = compilation, jsBinaryType = KotlinJsBinaryType.LIBRARY, diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrSubTarget.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrSubTarget.kt index b1f21c3cd8d..0bdf2595116 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrSubTarget.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrSubTarget.kt @@ -102,17 +102,6 @@ abstract class KotlinJsIrSubTarget( } } - private fun addLinkOptions(compilation: KotlinJsIrCompilation) { - val additionalCompilerOption = additionalCompilerOption ?: return - compilation.binaries - .withType(JsIrBinary::class.java) - .all { - it.linkTask.configure { linkTask -> - linkTask.kotlinOptions.freeCompilerArgs += additionalCompilerOption - } - } - } - private fun configureTestsRun(testRun: KotlinJsPlatformTestRun, compilation: KotlinJsIrCompilation) { fun KotlinJsPlatformTestRun.subtargetTestTaskName(): String = disambiguateCamelCased( lowerCamelCaseName( @@ -121,8 +110,6 @@ abstract class KotlinJsIrSubTarget( ) ) - addLinkOptions(compilation) - val testJs = project.registerTask( testRun.subtargetTestTaskName(), listOf(compilation) @@ -177,7 +164,6 @@ abstract class KotlinJsIrSubTarget( protected abstract fun configureDefaultTestFramework(test: KotlinJsTest) protected abstract fun configureTestDependencies(test: KotlinJsTest) - protected abstract val additionalCompilerOption: String? private fun configureMain() { target.compilations.all { compilation -> diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinNodeJsIr.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinNodeJsIr.kt index 75a2791fd45..8f26ca2c6f8 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinNodeJsIr.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinNodeJsIr.kt @@ -43,7 +43,4 @@ open class KotlinNodeJsIr @Inject constructor(target: KotlinJsIrTarget) : test.testFramework = KotlinWasmNode(test) } } - - override val additionalCompilerOption: String? - get() = "-Xwasm-launcher=nodejs".takeIf { target.platformType == KotlinPlatformType.wasm } } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmProject.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmProject.kt index cf57b08860e..081c6f64a74 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmProject.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/NpmProject.kt @@ -8,6 +8,7 @@ package org.jetbrains.kotlin.gradle.targets.js.npm import org.gradle.api.Project import org.gradle.process.ExecSpec import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation +import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation import org.jetbrains.kotlin.gradle.plugin.mpp.disambiguateName import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsTargetDsl @@ -28,6 +29,8 @@ val KotlinJsCompilation.npmProject: NpmProject open class NpmProject(@Transient val compilation: KotlinJsCompilation) : Serializable { val compilationName = compilation.disambiguatedName + private val extension = if (compilation.platformType == KotlinPlatformType.wasm) ".mjs" else ".js" + val name: String by lazy { buildNpmProjectName() } @@ -65,7 +68,7 @@ open class NpmProject(@Transient val compilation: KotlinJsCompilation) : Seriali get() = dir.resolve(DIST_FOLDER) val main: String - get() = "$DIST_FOLDER/$name.js" + get() = "$DIST_FOLDER/$name$extension" val externalsDirRoot by lazy { project.buildDir.resolve("externals").resolve(name) diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/testing/KotlinWasmD8.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/testing/KotlinWasmD8.kt index 047097cbcd3..452c086491f 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/testing/KotlinWasmD8.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/testing/KotlinWasmD8.kt @@ -14,14 +14,19 @@ import org.jetbrains.kotlin.gradle.targets.js.RequiredKotlinJsDependency import org.jetbrains.kotlin.gradle.targets.js.d8.D8RootPlugin import org.jetbrains.kotlin.gradle.targets.js.internal.parseNodeJsStackTraceAsJvm import org.jetbrains.kotlin.gradle.targets.js.isTeamCity +import org.jetbrains.kotlin.gradle.targets.js.writeWasmUnitTestRunner import org.jetbrains.kotlin.gradle.utils.getValue internal class KotlinWasmD8(private val kotlinJsTest: KotlinJsTest) : KotlinJsTestFramework { override val settingsState: String = "KotlinWasmD8" + @Transient override val compilation: KotlinJsCompilation = kotlinJsTest.compilation + @Transient private val project: Project = compilation.target.project + private val d8 = D8RootPlugin.apply(project.rootProject) private val d8Executable by project.provider { d8.requireConfigured().executablePath } + private val isTeamCity by lazy { project.isTeamCity } init { kotlinJsTest.outputs.upToDateWhen { false } @@ -33,10 +38,10 @@ internal class KotlinWasmD8(private val kotlinJsTest: KotlinJsTest) : KotlinJsTe nodeJsArgs: MutableList, debug: Boolean ): TCServiceMessagesTestExecutionSpec { - val compiledFile = task.inputFileProperty.get().asFile + val testRunnerFile = writeWasmUnitTestRunner(task.inputFileProperty.get().asFile) forkOptions.executable = d8Executable.absolutePath - forkOptions.workingDir = compiledFile.parentFile + forkOptions.workingDir = testRunnerFile.parentFile val clientSettings = TCServiceMessagesClientSettings( task.name, @@ -44,7 +49,7 @@ internal class KotlinWasmD8(private val kotlinJsTest: KotlinJsTest) : KotlinJsTe prependSuiteName = true, stackTraceParser = ::parseNodeJsStackTraceAsJvm, ignoreOutOfRootNodes = true, - escapeTCMessagesInLog = project.isTeamCity + escapeTCMessagesInLog = isTeamCity ) val cliArgs = KotlinTestRunnerCliArgs( @@ -53,26 +58,20 @@ internal class KotlinWasmD8(private val kotlinJsTest: KotlinJsTest) : KotlinJsTe ) val args = mutableListOf( - "--module", - compiledFile.absolutePath, - "--experimental-wasm-typed-funcref", "--experimental-wasm-gc", "--experimental-wasm-eh", + testRunnerFile.absolutePath, ) args.add("--") args.addAll(cliArgs.toList()) - val dryRunArgs = mutableListOf() - dryRunArgs.addAll(args) - dryRunArgs.add("--dryRun") - return TCServiceMessagesTestExecutionSpec( forkOptions = forkOptions, args = args, checkExitCode = false, clientSettings = clientSettings, - dryRunArgs = dryRunArgs + dryRunArgs = args + "--dryRun" ) } diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/testing/KotlinWasmNode.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/testing/KotlinWasmNode.kt index 08c974ff580..4bd1038d483 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/testing/KotlinWasmNode.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/testing/KotlinWasmNode.kt @@ -5,7 +5,6 @@ package org.jetbrains.kotlin.gradle.targets.js.testing -import org.gradle.api.Project import org.gradle.process.ProcessForkOptions import org.jetbrains.kotlin.gradle.internal.testing.TCServiceMessagesClientSettings import org.jetbrains.kotlin.gradle.internal.testing.TCServiceMessagesTestExecutionSpec @@ -13,11 +12,13 @@ import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation import org.jetbrains.kotlin.gradle.targets.js.RequiredKotlinJsDependency import org.jetbrains.kotlin.gradle.targets.js.internal.parseNodeJsStackTraceAsJvm import org.jetbrains.kotlin.gradle.targets.js.isTeamCity +import org.jetbrains.kotlin.gradle.targets.js.writeWasmUnitTestRunner internal class KotlinWasmNode(private val kotlinJsTest: KotlinJsTest) : KotlinJsTestFramework { override val settingsState: String = "KotlinWasmNode" + @Transient override val compilation: KotlinJsCompilation = kotlinJsTest.compilation - private val project: Project = compilation.target.project + private val isTeamCity by lazy { compilation.target.project.isTeamCity } init { kotlinJsTest.outputs.upToDateWhen { false } @@ -29,7 +30,7 @@ internal class KotlinWasmNode(private val kotlinJsTest: KotlinJsTest) : KotlinJs nodeJsArgs: MutableList, debug: Boolean ): TCServiceMessagesTestExecutionSpec { - val compiledFile = task.inputFileProperty.get().asFile + val testRunnerFile = writeWasmUnitTestRunner(task.inputFileProperty.get().asFile) val clientSettings = TCServiceMessagesClientSettings( task.name, @@ -37,7 +38,7 @@ internal class KotlinWasmNode(private val kotlinJsTest: KotlinJsTest) : KotlinJs prependSuiteName = true, stackTraceParser = ::parseNodeJsStackTraceAsJvm, ignoreOutOfRootNodes = true, - escapeTCMessagesInLog = project.isTeamCity + escapeTCMessagesInLog = isTeamCity ) val cliArgs = KotlinTestRunnerCliArgs( @@ -47,22 +48,17 @@ internal class KotlinWasmNode(private val kotlinJsTest: KotlinJsTest) : KotlinJs val args = mutableListOf() with(args) { - add("--experimental-wasm-typed-funcref") add("--experimental-wasm-gc") add("--experimental-wasm-eh") - add(compiledFile.absolutePath) + add(testRunnerFile.absolutePath) addAll(cliArgs.toList()) } - val dryRunArgs = mutableListOf() - dryRunArgs.addAll(args) - dryRunArgs.add("--dryRun") - return TCServiceMessagesTestExecutionSpec( forkOptions = forkOptions, args = args, checkExitCode = false, clientSettings = clientSettings, - dryRunArgs = dryRunArgs + dryRunArgs = args + "--dryRun" ) } diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/testing/karma/KotlinKarma.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/testing/karma/KotlinKarma.kt index 0250a2eab2c..e108c476665 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/testing/karma/KotlinKarma.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/testing/karma/KotlinKarma.kt @@ -61,6 +61,7 @@ class KotlinKarma( private var configDirectory: File by property { defaultConfigDirectory } + private val isTeamCity by lazy { project.isTeamCity } override val requiredNpmDependencies: Set get() = requiredDependencies + webpackConfig.getRequiredDependencies(versions) @@ -380,7 +381,7 @@ class KotlinKarma( prependSuiteName = true, stackTraceParser = ::parseNodeJsStackTraceAsJvm, ignoreOutOfRootNodes = true, - escapeTCMessagesInLog = project.isTeamCity + escapeTCMessagesInLog = isTeamCity ) config.basePath = npmProject.nodeModulesDir.absolutePath diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/testing/mocha/KotlinMocha.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/testing/mocha/KotlinMocha.kt index 789e237a168..e6a11fd953a 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/testing/mocha/KotlinMocha.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/testing/mocha/KotlinMocha.kt @@ -28,6 +28,7 @@ class KotlinMocha(@Transient override val compilation: KotlinJsCompilation, priv private val project: Project = compilation.target.project private val npmProject = compilation.npmProject private val versions = NodeJsRootPlugin.apply(project.rootProject).versions + private val isTeamCity by lazy { project.isTeamCity } override val settingsState: String get() = "mocha" @@ -59,7 +60,7 @@ class KotlinMocha(@Transient override val compilation: KotlinJsCompilation, priv prependSuiteName = true, stackTraceParser = ::parseNodeJsStackTraceAsJvm, ignoreOutOfRootNodes = true, - escapeTCMessagesInLog = project.isTeamCity + escapeTCMessagesInLog = isTeamCity ) val cliArgs = KotlinTestRunnerCliArgs( diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/utils.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/utils.kt index d96c3628d31..456d8d46a78 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/utils.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/utils.kt @@ -68,3 +68,14 @@ val Project.isTeamCity: Boolean } else { project.hasProperty(TCServiceMessagesTestExecutor.TC_PROJECT_PROPERTY) } + +internal fun writeWasmUnitTestRunner(compiledFile: File): File { + val testRunnerFile = compiledFile.parentFile.resolve("runUnitTests.mjs") + testRunnerFile.writeText( + """ + import exports from '${compiledFile.absolutePath}'; + exports.startUnitTests?.(); + """.trimIndent() + ) + return testRunnerFile +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/Kotlin2JsCompileConfig.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/Kotlin2JsCompileConfig.kt index fb6093d4d91..86f145864f4 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/Kotlin2JsCompileConfig.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/Kotlin2JsCompileConfig.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.gradle.tasks.configuration +import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinCompilationData import org.jetbrains.kotlin.gradle.targets.js.ir.isProduceUnzippedKlib import org.jetbrains.kotlin.gradle.tasks.Kotlin2JsCompile @@ -27,8 +28,9 @@ internal open class BaseKotlin2JsCompileConfig( task.incrementalJsKlib = propertiesProvider.incrementalJsKlib ?: true task.outputFileProperty.value(task.project.provider { + val extensionName = if (compilation.platformType == KotlinPlatformType.wasm) ".mjs" else ".js" task.kotlinOptions.outputFile?.let(::File) - ?: task.destinationDirectory.locationOnly.get().asFile.resolve("${compilation.ownModuleName}.js") + ?: task.destinationDirectory.locationOnly.get().asFile.resolve("${compilation.ownModuleName}$extensionName") }).disallowChanges() task.optionalOutputFile.fileProvider(task.outputFileProperty.flatMap { outputFile ->