Skip to content

Commit b91c3f1

Browse files
committed
library: Add Js platform support
1 parent 21ea910 commit b91c3f1

File tree

15 files changed

+289
-59
lines changed

15 files changed

+289
-59
lines changed

composeApp/build.gradle.kts

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import com.android.build.gradle.internal.api.BaseVariantOutputImpl
44
import org.jetbrains.compose.desktop.application.dsl.TargetFormat
55
import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl
66
import org.jetbrains.kotlin.gradle.plugin.mpp.apple.XCFramework
7-
import org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpackConfig
87
import java.util.Properties
98

109
plugins {
@@ -58,16 +57,20 @@ kotlin {
5857
browser {
5958
commonWebpackConfig {
6059
outputFileName = "uitest.js"
61-
devServer = (devServer ?: KotlinWebpackConfig.DevServer()).apply {
62-
static = (static ?: mutableListOf()).apply {
63-
// Serve sources to debug inside browser
64-
add(project.projectDir.path)
65-
}
66-
}
6760
}
6861
}
6962
binaries.executable()
7063
}
64+
js(IR) {
65+
moduleName = "uitest"
66+
browser {
67+
commonWebpackConfig {
68+
outputFileName = "uitest.js"
69+
}
70+
}
71+
binaries.executable()
72+
}
73+
7174

7275
sourceSets {
7376
val desktopMain by getting
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import androidx.compose.runtime.LaunchedEffect
2+
import androidx.compose.runtime.mutableStateOf
3+
import androidx.compose.runtime.remember
4+
import androidx.compose.ui.ExperimentalComposeUiApi
5+
import androidx.compose.ui.platform.LocalFontFamilyResolver
6+
import androidx.compose.ui.text.font.FontFamily
7+
import androidx.compose.ui.text.platform.Font
8+
import androidx.compose.ui.window.ComposeViewport
9+
import kotlinx.browser.window
10+
import kotlinx.coroutines.await
11+
import org.jetbrains.skiko.wasm.onWasmReady
12+
import org.khronos.webgl.ArrayBuffer
13+
import org.khronos.webgl.Int8Array
14+
15+
private const val MiSanVF = "./MiSans VF.woff2"
16+
17+
@OptIn(ExperimentalComposeUiApi::class)
18+
fun main() {
19+
onWasmReady {
20+
ComposeViewport(
21+
viewportContainerId = "composeApplication"
22+
) {
23+
val fontFamilyResolver = LocalFontFamilyResolver.current
24+
val fontsLoaded = remember { mutableStateOf(false) }
25+
26+
if (fontsLoaded.value) {
27+
hideLoading()
28+
App()
29+
}
30+
31+
LaunchedEffect(Unit) {
32+
val miSanVFBytes = loadRes(MiSanVF).toByteArray()
33+
val fontFamily = FontFamily(Font("MiSans VF", miSanVFBytes))
34+
fontFamilyResolver.preload(fontFamily)
35+
fontsLoaded.value = true
36+
}
37+
}
38+
}
39+
}
40+
41+
42+
suspend fun loadRes(url: String): ArrayBuffer {
43+
return window.fetch(url).await().arrayBuffer().await()
44+
}
45+
46+
fun ArrayBuffer.toByteArray(): ByteArray {
47+
val source = Int8Array(this, 0, byteLength)
48+
return jsInt8ArrayToKotlinByteArray(source)
49+
}
50+
51+
external fun hideLoading()
52+
53+
external fun jsInt8ArrayToKotlinByteArray(x: Int8Array): ByteArray
495 KB
Binary file not shown.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
function hideLoading() {
2+
document.getElementById('loading').style.display = 'none';
3+
document.getElementById('composeApplication').style.display = 'block';
4+
}
5+
6+
function jsInt8ArrayToKotlinByteArray(x) {
7+
const size = x.length;
8+
const memBuffer = new ArrayBuffer(size);
9+
const mem8 = new Int8Array(memBuffer);
10+
mem8.set(x);
11+
const byteArray = new Uint8Array(memBuffer);
12+
return byteArray;
13+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
4+
<head>
5+
<meta charset="UTF-8">
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
7+
<title>miuix</title>
8+
<script type="application/javascript" src="skiko.js"></script>
9+
<script type="application/javascript" src="app.js"></script>
10+
<link type="text/css" rel="stylesheet" href="styles.css">
11+
</head>
12+
13+
<body>
14+
<div id="loading">Loading</div>
15+
<div id="composeApplication"></div>
16+
<script type="application/javascript" src="uitest.js"></script>
17+
</body>
18+
19+
</html>
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*
2+
* Copyright 2024 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
html, body {
18+
margin: 0;
19+
padding: 0;
20+
width: 100%;
21+
height: 100%;
22+
display: flex;
23+
overflow: hidden;
24+
}
25+
26+
#loading {
27+
position: absolute;
28+
top: 50%;
29+
left: 50%;
30+
transform: translate(-50%, -50%);
31+
font-size: 24px;
32+
font-weight: bold;
33+
}
34+
35+
#loading::after {
36+
content: '.';
37+
animation: ellipsis 1.5s infinite;
38+
}
39+
40+
@keyframes ellipsis {
41+
0% {
42+
content: '.';
43+
}
44+
45+
33% {
46+
content: '..';
47+
}
48+
49+
66% {
50+
content: '...';
51+
}
52+
53+
100% {
54+
content: '.';
55+
}
56+
}
57+
58+
#composeApplication {
59+
width: 100%;
60+
height: 100%;
61+
}

composeApp/src/wasmJsMain/kotlin/main.kt

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import androidx.compose.ui.ExperimentalComposeUiApi
55
import androidx.compose.ui.platform.LocalFontFamilyResolver
66
import androidx.compose.ui.text.font.FontFamily
77
import androidx.compose.ui.text.platform.Font
8-
import androidx.compose.ui.window.CanvasBasedWindow
8+
import androidx.compose.ui.window.ComposeViewport
99
import kotlinx.browser.window
1010
import kotlinx.coroutines.await
1111
import org.khronos.webgl.ArrayBuffer
@@ -18,7 +18,9 @@ private const val MiSanVF = "./MiSans VF.woff2"
1818

1919
@OptIn(ExperimentalComposeUiApi::class)
2020
fun main() {
21-
CanvasBasedWindow("miuix", canvasElementId = "uitestCanvas") {
21+
ComposeViewport(
22+
viewportContainerId = "composeApplication"
23+
) {
2224
val fontFamilyResolver = LocalFontFamilyResolver.current
2325
val fontsLoaded = remember { mutableStateOf(false) }
2426

@@ -50,7 +52,7 @@ fun ArrayBuffer.toByteArray(): ByteArray {
5052
"""
5153
function hideLoading() {
5254
document.getElementById('loading').style.display = 'none';
53-
document.getElementById('uitestCanvas').style.display = 'block';
55+
document.getElementById('composeApplication').style.display = 'block';
5456
}
5557
"""
5658
)

composeApp/src/wasmJsMain/resources/index.html

Lines changed: 3 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -5,58 +5,13 @@
55
<meta charset="UTF-8">
66
<meta name="viewport" content="width=device-width, initial-scale=1.0">
77
<title>miuix</title>
8-
<script type="application/javascript" src="uitest.js"></script>
9-
<style>
10-
html,
11-
body {
12-
width: 100%;
13-
height: 100%;
14-
margin: 0;
15-
padding: 0;
16-
overflow: hidden;
17-
}
18-
19-
#loading {
20-
position: absolute;
21-
top: 50%;
22-
left: 50%;
23-
transform: translate(-50%, -50%);
24-
font-size: 24px;
25-
font-weight: bold;
26-
}
27-
28-
#loading::after {
29-
content: '.';
30-
animation: ellipsis 1.5s infinite;
31-
}
32-
33-
@keyframes ellipsis {
34-
0% {
35-
content: '.';
36-
}
37-
38-
33% {
39-
content: '..';
40-
}
41-
42-
66% {
43-
content: '...';
44-
}
45-
46-
100% {
47-
content: '.';
48-
}
49-
}
50-
51-
#uitestCanvas {
52-
display: none;
53-
}
54-
</style>
8+
<link type="text/css" rel="stylesheet" href="styles.css">
9+
<script src="uitest.js"></script>
5510
</head>
5611

5712
<body>
5813
<div id="loading">Loading</div>
59-
<canvas id="uitestCanvas"></canvas>
14+
<div id="composeApplication"></div>
6015
</body>
6116

6217
</html>
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/*
2+
* Copyright 2024 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
18+
html,
19+
body {
20+
width: 100%;
21+
height: 100%;
22+
margin: 0;
23+
padding: 0;
24+
overflow: hidden;
25+
}
26+
27+
#loading {
28+
position: absolute;
29+
top: 50%;
30+
left: 50%;
31+
transform: translate(-50%, -50%);
32+
font-size: 24px;
33+
font-weight: bold;
34+
}
35+
36+
#loading::after {
37+
content: '.';
38+
animation: ellipsis 1.5s infinite;
39+
}
40+
41+
@keyframes ellipsis {
42+
0% {
43+
content: '.';
44+
}
45+
46+
33% {
47+
content: '..';
48+
}
49+
50+
66% {
51+
content: '...';
52+
}
53+
54+
100% {
55+
content: '.';
56+
}
57+
}
58+
59+
#composeApplication {
60+
width: 100%;
61+
height: 100%;
62+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
const TerserPlugin = require("terser-webpack-plugin");
2+
3+
config.optimization = config.optimization || {};
4+
config.optimization.minimize = true;
5+
config.optimization.minimizer = [
6+
new TerserPlugin({
7+
terserOptions: {
8+
mangle: true, // Note: By default, mangle is set to true.
9+
compress: false, // Disable the transformations that reduce the code size.
10+
output: {
11+
beautify: false,
12+
},
13+
},
14+
}),
15+
];

0 commit comments

Comments
 (0)