1
+ import org.jetbrains.kotlin.gradle.targets.js.dsl.ExperimentalWasmDsl
1
2
import org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpackConfig
2
3
3
4
plugins {
4
- kotlin(" multiplatform" )
5
- if (System .getProperty(" application.useJs" ) == " true" ) {
6
- id(" org.jetbrains.compose" ) version " 1.5.11"
7
- } else {
8
- id(" org.jetbrains.compose" ) version " 1.5.10-dev-wasm02"
9
- }
5
+ alias(libs.plugins.org.jetbrains.kotlin.multiplatform)
6
+ alias(libs.plugins.org.jetbrains.compose)
10
7
}
11
8
12
9
buildscript {
13
10
dependencies {
14
- classpath(" org.jetbrains.kotlinx: atomicfu- gradle- plugin:_ " )
11
+ classpath(libs. org.jetbrains.kotlinx. atomicfu. gradle. plugin)
15
12
}
16
13
}
17
14
@@ -24,42 +21,53 @@ val useJs = System.getProperty("application.useJs") == "true"
24
21
val optimizeAggressively = System .getProperty(" application.optimize" ) == " true"
25
22
26
23
kotlin {
27
- jvmToolchain(11 )
24
+ val jdkVersion = project.property(" local.jdk.version" ).toString().toInt()
25
+
26
+ jvmToolchain(jdkVersion)
27
+
28
+ jvm {
29
+ compilations.configureEach {
30
+ kotlinOptions.freeCompilerArgs + = listOf (" -Xjdk-release=$jdkVersion " )
31
+ }
32
+ }
28
33
29
34
jvm {
30
35
withJava()
31
36
}
32
37
33
- if (useJs) {
34
- js {
35
- moduleName = " app"
36
- binaries.executable()
37
- browser {
38
- useCommonJs()
39
- commonWebpackConfig {
40
- outputFileName = " $moduleName .js"
41
- }
38
+ js {
39
+ moduleName = " app"
40
+ binaries.executable()
41
+ browser {
42
+ useCommonJs()
43
+ commonWebpackConfig {
44
+ outputFileName = " $moduleName .js"
42
45
}
43
46
}
44
- } else {
45
- wasmJs {
46
- moduleName = " app"
47
- binaries.executable()
48
- browser {
49
- commonWebpackConfig {
50
- outputFileName = " $moduleName .js"
51
- devServer = (devServer ? : KotlinWebpackConfig .DevServer ()).copy(
47
+ }
48
+
49
+ @OptIn(ExperimentalWasmDsl ::class )
50
+ wasmJs {
51
+ moduleName = " app"
52
+ binaries.executable()
53
+ browser {
54
+ commonWebpackConfig {
55
+ outputFileName = " $moduleName .js"
56
+ devServer =
57
+ (devServer ? : KotlinWebpackConfig .DevServer ()).copy(
52
58
port = 8081 ,
53
- static = (devServer?.static ? : mutableListOf ()).apply {
54
- // Serve sources to debug inside browser
55
- add(project.rootDir.path)
56
- }
59
+ static =
60
+ (devServer?.static ? : mutableListOf ()).apply {
61
+ // Serve sources to debug inside browser
62
+ add(project.rootDir.path)
63
+ }
57
64
)
58
- }
59
65
}
66
+ }
60
67
61
- applyBinaryen {
62
- binaryenArgs = mutableListOf (
68
+ applyBinaryen {
69
+ binaryenArgs =
70
+ mutableListOf (
63
71
" --enable-nontrapping-float-to-int" ,
64
72
" --enable-gc" ,
65
73
" --enable-reference-types" ,
@@ -70,7 +78,8 @@ kotlin {
70
78
" --fast-math"
71
79
)
72
80
73
- binaryenArgs + = if (optimizeAggressively) {
81
+ binaryenArgs + =
82
+ if (optimizeAggressively) {
74
83
listOf (
75
84
" --closed-world" ,
76
85
// "--metrics",
@@ -87,26 +96,24 @@ kotlin {
87
96
" -c" // Run passes while binary size decreases
88
97
)
89
98
}
90
- }
91
99
}
92
100
}
93
101
94
102
sourceSets {
95
103
all {
96
104
languageSettings {
97
- languageVersion = " 2.0"
98
105
progressiveMode = true
99
106
optIn(" kotlin.RequiresOptIn" )
100
107
}
101
108
}
102
109
103
110
val commonMain by getting {
104
111
dependencies {
105
- implementation(compose.runtime )
112
+ implementation(compose.ui )
106
113
implementation(compose.foundation)
107
114
implementation(compose.material)
108
- implementation(" org.jetbrains.kotlinx: atomicfu:_ " )
109
- implementation(KotlinX .datetime)
115
+ implementation(libs. org.jetbrains.kotlinx. atomicfu)
116
+ implementation(libs.org.jetbrains.kotlinx.kotlinx .datetime)
110
117
}
111
118
}
112
119
@@ -116,193 +123,41 @@ kotlin {
116
123
}
117
124
}
118
125
119
- if (useJs) {
120
- val jsMain by getting {
121
- dependencies {
122
- implementation(compose.web.core)
123
- }
126
+ val jsMain by getting {
127
+ dependencies {
128
+ @Suppress(" DEPRECATION" )
129
+ implementation(compose.web.core) // Required for Compose Web/Canvas on JS
124
130
}
125
131
}
126
132
}
127
133
}
128
134
129
135
compose {
130
- desktop.application.mainClass = " MainKt"
131
- experimental {
132
- web.application {}
136
+ providers.gradleProperty(" local.compose.kotlinCompilerPlugin" ).orNull?.let { composeKotlinCompilerPlugin ->
137
+ kotlinCompilerPlugin.set(composeKotlinCompilerPlugin)
138
+ val kotlinVersion = " ${libs.plugins.org.jetbrains.kotlin.multiplatform.get().version} "
139
+ kotlinCompilerPluginArgs.add(" suppressKotlinVersionCompatibilityCheck=$kotlinVersion " )
133
140
}
134
- if (! useJs) {
135
- kotlinCompilerPlugin.set(" 1.5.4" )
136
- }
137
- }
141
+ // kotlinCompilerPluginArgs.add("reportsDestination=${layout.buildDirectory.file("reports")}")
138
142
139
- if (! useJs) {
140
- rootProject.tasks {
141
- val hackNodeModuleImports by registering(Copy ::class ) {
142
- group = " kotlin browser"
143
- mustRunAfter(" kotlinNpmInstall" )
144
- from(buildDir.path + " /js/node_modules/@js-joda" )
145
- into(buildDir.path + " /js/packages/app/kotlin/@js-joda" )
146
- }
147
- for (dependent in listOf (" wasmJsBrowserProductionRun" , " wasmJsBrowserDevelopmentRun" )) {
148
- named(dependent) {
149
- dependsOn(hackNodeModuleImports)
150
- }
151
- }
152
- }
153
- }
154
-
155
- val yarnExecutablePath: String by lazy {
156
- with (rootProject.extensions.getByType< org.jetbrains.kotlin.gradle.targets.js.yarn.YarnRootExtension > ()) {
157
- requireConfigured().executable.substringBeforeLast(" .js" )
158
- }
159
- }
143
+ desktop.application.mainClass = " MainKt"
160
144
161
- val nodeBinaryDirectory: String by lazy {
162
- with (rootProject.extensions.getByType< org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension > ()) {
163
- requireConfigured().nodeBinDir.toString()
145
+ experimental {
146
+ web.application {}
164
147
}
165
148
}
166
149
167
- fun Exec.addNodePath () {
168
- environment(" PATH" , " ${System .getenv(" PATH" )} :$nodeBinaryDirectory " )
169
- }
170
-
150
+ // Hack to use kotlinx-datetime with Wasm
171
151
rootProject.tasks {
172
- val yarnLockName = " yarn.lock"
173
- val yarnBuildDirectory = " $rootDir /build/js"
174
- val yarnLockBuildPath = " $yarnBuildDirectory /$yarnLockName "
175
- val yarnLockPrimaryName = " $yarnLockName .primary"
176
- val yarnLockStorageDirectory = " $rootDir /kotlin-js-store"
177
- val yarnLockPrimaryPath = " $yarnLockStorageDirectory /$yarnLockPrimaryName "
178
-
179
- val yarnShowAuditReport by registering(Exec ::class ) {
180
- group = " nodejs"
181
- description = " Shows an audit report for npm packages, listing known vulnerabilities."
182
- workingDir = File (yarnBuildDirectory)
183
- addNodePath()
184
- commandLine = mutableListOf (yarnExecutablePath, " audit" )
185
- }
186
-
187
- val yarnShowOutdatedPackages by registering(Exec ::class ) {
188
- group = " nodejs"
189
- description = " Shows outdated npm packages."
190
- workingDir = File (yarnBuildDirectory)
191
- addNodePath()
192
- commandLine = mutableListOf (yarnExecutablePath, " outdated" )
193
- isIgnoreExitValue = true
194
- }
195
-
196
- val yarnLockUpdatePrimary by registering {
197
- group = " nodejs"
198
- description =
199
- " Updates '$yarnLockPrimaryName ' from the build-generated '$yarnLockName '. Must be invoked manually."
200
-
201
- doLast {
202
- copy {
203
- from(yarnLockBuildPath)
204
- rename { yarnLockPrimaryName }
205
- into(yarnLockStorageDirectory)
206
- }
152
+ val hackNodeModuleImports by registering(Copy ::class ) {
153
+ group = " kotlin browser"
154
+ mustRunAfter(" kotlinNpmInstall" )
155
+ from(layout.buildDirectory.file(" js/node_modules/@js-joda" ))
156
+ into(layout.buildDirectory.file(" js/packages/app/kotlin/@js-joda" ))
157
+ }
158
+ for (dependent in listOf (" wasmJsBrowserProductionRun" , " wasmJsBrowserDevelopmentRun" )) {
159
+ named(dependent) {
160
+ dependsOn(hackNodeModuleImports)
207
161
}
208
-
209
- inputs.file(yarnLockBuildPath).withPropertyName(" inputFile" )
210
- outputs.file(yarnLockPrimaryPath).withPropertyName(" outputFile" )
211
- }
212
-
213
- val yarnLockRestore by registering {
214
- group = " nodejs"
215
- description = " Restores '$yarnLockName ' from '$yarnLockPrimaryName ' to ensure stable builds."
216
-
217
- // Kotlin >=1.6.10 restores 'yarn.lock' from 'kotlin-js-store/yarn.lock', but also updates the latter
218
- // unconditionally, without any checks performed. To avoid green-lighting unchecked code, make sure
219
- // our version always gets precedence.
220
- mustRunAfter(" kotlinRestoreYarnLock" )
221
-
222
- doLast {
223
- copy {
224
- from(yarnLockPrimaryPath)
225
- rename { yarnLockName }
226
- into(yarnBuildDirectory)
227
- }
228
- }
229
-
230
- inputs.file(yarnLockPrimaryPath).withPropertyName(" inputFile" )
231
- outputs.file(yarnLockBuildPath).withPropertyName(" outputFile" )
232
- }
233
-
234
- val yarnLockValidate by registering {
235
- group = " nodejs"
236
- description = (
237
- " Validates that the build directory's '$yarnLockName ' corresponds" +
238
- " to '$yarnLockPrimaryName ' in the project root directory."
239
- )
240
- dependsOn(" kotlinNpmInstall" )
241
-
242
- doLast {
243
- val expected = File (yarnLockPrimaryPath).readText().trim()
244
- val actual = File (yarnLockBuildPath).readText().trim()
245
-
246
- if (expected != actual) {
247
- // WORKAROUND https://youtrack.jetbrains.com/issue/IDEA-267343 –
248
- // 'idea diff ...' produces an exception and does not immediately complete, although it does
249
- // open the diff window.
250
- // Replace the following workaround with the code in comments when the issue is fixed.
251
- ProcessBuilder (" idea" , " diff" , yarnLockPrimaryPath, yarnLockBuildPath)
252
- .redirectOutput(ProcessBuilder .Redirect .INHERIT )
253
- .redirectError(ProcessBuilder .Redirect .DISCARD )
254
- .start()
255
- /* Replace with:
256
- exec {
257
- commandLine = mutableListOf("idea", "diff", yarnLockPrimaryPath, yarnLockBuildPath)
258
- }
259
- */
260
-
261
- throw AssertionError (
262
- " The build-generated '$yarnLockName ' differs from '$yarnLockPrimaryName '" +
263
- " in the project root directory." +
264
- " Each difference indicates a dependency update which has not been confirmed by" +
265
- " running './gradlew :yarnLockUpdatePrimary'.\n " +
266
- " \t An idea diff window has been opened.\n " +
267
- " \t To explore differences later, please run:" +
268
- " idea diff '$yarnLockPrimaryPath ' '$yarnLockBuildPath '\n " +
269
- " \t To assess package risks, please run: gradlew :analyseSupplyChain"
270
- )
271
- }
272
- }
273
- }
274
-
275
- named< org.jetbrains.kotlin.gradle.targets.js.npm.tasks.KotlinNpmInstallTask > (" kotlinNpmInstall" ) {
276
- dependsOn(yarnLockRestore)
277
- finalizedBy(yarnLockValidate)
278
-
279
- // Avoid package installation scripts vulnerability:
280
- // https://blog.npmjs.org/post/141702881055/package-install-scripts-vulnerability
281
- args + = " --ignore-scripts"
282
- // To detect packages, which use installation scripts, see 'can-i-ignore-scripts', described here:
283
- // https://dev.to/naugtur/get-safe-and-remain-productive-with-can-i-ignore-scripts-2ddc
284
- }
285
-
286
- val analyzeNpmSupplyChain by registering(Exec ::class ) {
287
- group = " nodejs"
288
- description = " Analyses the npm package supply chain, hinting on possible security risks."
289
-
290
- dependsOn(" kotlinNpmInstall" )
291
-
292
- val packagesToExclude = listOf (" packages" , " packages_imported" ).flatMap { packageDirectory ->
293
- File (" $yarnBuildDirectory /$packageDirectory " )
294
- .listFiles()?.mapNotNull { if (it.isDirectory) it.name else null } ? : listOf ()
295
- }
296
-
297
- commandLine = mutableListOf (
298
- " sca" ,
299
- " --exclude" ,
300
- packagesToExclude.joinToString(" |" ),
301
- " $yarnBuildDirectory /node_modules"
302
- )
303
- }
304
-
305
- named(" check" ) {
306
- dependsOn(" :yarnLockValidate" )
307
162
}
308
163
}
0 commit comments