Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Kotlinしか書けなくても⼤丈夫! Compose for Webで もっと⼿軽に Webア...
Search
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
Eriko Suto
November 01, 2025
Programming
150
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Kotlinしか書けなくても⼤丈夫! Compose for Webで もっと⼿軽に Webアプリを作ろう
Eriko Suto
November 01, 2025
Other Decks in Programming
See All in Programming
なぜ関数型プログラミングで「型」と「証明」が語られるのか #fp_matsuri
kajitack
3
1k
FDEが実現するAI駆動経営の現在地
gonta
2
220
はてなアカウント基盤 State of the Union
cockscomb
1
1.3k
アルゴリズムは何を圧縮しているのか ─ Haskell から育った「圧縮代数」というメンタルモデル
naoya
16
3.6k
5分で問診!Composer セキュリティ健康診断
codmoninc
0
610
コーディングルールの鮮度を保ちたい for SRE NEXT 2026 / keep-fresh-go-internal-conventions-sre-next-2026
handlename
0
150
型も通る、synthも通る、それでも危ない 〜AIのCDKの権限とコストを機械で検証する〜 / It Passes Type Checks, It Passes Synth Checks, but It’s Still Risky — Automatically Verifying Permissions and Costs in AI’s CDK —
seike460
PRO
1
440
Apache Hive: Toward a Cloud Native Lakehouse
okumin
0
160
テーブルをDELETEした
yuzneri
0
100
Generative UI & AI-Assistants for Your Angular Solutions
manfredsteyer
PRO
0
120
任せる範囲はこう広がった / How the Scope of AI Delegation Has Expanded
nrslib
1
280
音楽のための関数型プログラミング言語mimiumにおける多段階計算の活用
tomoyanonymous
1
360
Featured
See All Featured
Product Roadmaps are Hard
iamctodd
55
12k
Efficient Content Optimization with Google Search Console & Apps Script
katarinadahlin
PRO
1
740
Into the Great Unknown - MozCon
thekraken
41
2.6k
The Curious Case for Waylosing
cassininazir
1
440
Accessibility Awareness
sabderemane
1
160
The MySQL Ecosystem @ GitHub 2015
samlambert
251
13k
Beyond borders and beyond the search box: How to win the global "messy middle" with AI-driven SEO
davidcarrasco
3
190
Effective software design: The role of men in debugging patriarchy in IT @ Voxxed Days AMS
baasie
0
450
Marketing Yourself as an Engineer | Alaka | Gurzu
gurzu
0
260
AI Search: Implications for SEO and How to Move Forward - #ShenzhenSEOConference
aleyda
1
1.3k
Designing Experiences People Love
moore
143
24k
YesSQL, Process and Tooling at Scale
rocio
174
15k
Transcript
Kotlinしか書けなくても⼤丈夫! Compose for Webで もっと⼿軽に Webアプリを作ろう Eriko Suto KotlinFest 2025
Compose for Webとは? Compose Multiplatformをブラウザで動作可能にし、 UI実装をWebで再利用できるようにする仕組み https://www.jetbrains.com/ja-jp/compose-multiplatform/ Compose Multiplatform •
Androidアプリ開発で利用する宣言的UIのフレーム ワークであるJetpack Composeを拡張し、様々なプ ラットフォームで利用できるようにしたもの • Web以外にもiOS/Android/デスクトップがサポート されている 2
Compose for Webを選んだ背景 結婚式の余興を盛り上げるためにクイズアプリを作りたかった 「AndroidだけでなくiOSユーザーもサポートする必要が・・・」 「Compose Multiplatform(iOS/Android)だと審査や配布に問題が ・・・」 「Webアプリを1から学ぶほどの時間はない・・・」 3
Compose for Webを選んだ背景 結婚式の余興を盛り上げるためにクイズアプリを作りたかった 「AndroidだけでなくiOSユーザーもサポートする必要が・・・」 「Compose Multiplatform(iOS/Android)だと審査や配布に問題が ・・・」 「Webアプリを1から学ぶほどの時間はない・・・」 4
Compose for Webなら使い慣れた ComposeでWebアプリが作れる!
利用に注意が必要なケース • 非Stableバージョンを許容できない保守的なシナリオ • SEOやページ内検索などHTMLの構造に依存する機能が必要なケース ◦ Compose for WebはUIをHTML要素で構成せず、Skiko(2Dグラフィックエンジ ンSkiaをKotlinで使えるようにしたもの)によってHTML
Canvasに描画する特性 上、利用できない機能がある • ComposeによるUIの再利用を全く行わないケース ◦ Compose for Webの基本的なユースケースとしては、プラットフォームを跨いだ UIの再利用である https://www.jetbrains.com/help/kotlin-multiplatform-dev/choosing-web-target.html#when-to-choose-kot lin-wasm 5
目次 • Compose for Webの動作環境 • Compose for Webのはじめ方 •
Androidアプリのこれ、Webだとどうなる? • パフォーマンス最適化 • その他の改善 • 情報のキャッチアップ • まとめ 6
Compose for Webの 動作環境 7
前提:Compose for Webの動作条件 • Compose for Webは、Kotlin/Wasm コンパイラで Kotlinから WebAssembly
へ変換することでブラウザで動作 • Kotlin/Wasmで構築したアプリの実⾏には WasmGCサポートするブ ラウザ環境が必要 8
WasmGC対応ブラウザの現状 ※1 iOS18以降のデバイス(iOS18~18.1.1含む)の割合 主要モバイルブラウザの WasmGC対応バージョン インストール可能なOS 各OSの利⽤率 Chrome 119以降 Android7
Nougat以降 98.6%(2025年4⽉時点)※2 Safari 18.2以降 iOS18.2以降 約82%未満 ※1 (2025年6⽉4⽇時点)※3 9 ※2 JetBrains s.r.o.「Android Platform/API Version Distribution」.AndroidStudio内Minimum SDK選択時の 「Help me choose」のリンクより https://kotlinlang.org/docs/wasm-configuration.html#chromium-based ※3 Apple Inc.「App Store」.https://developer.apple.com/support/app-store/
サポート外ブラウザへの対応 1.9.0のBeta版でJavaScriptにフォールバックするためのGradle taskが追加 →Kotlin/WasmとKotlin/JS両⽅でコンパイルし、 ユーザー環境に適したプラットフォームを使⽤するコードを⽣成 10
サポート外ブラウザへの対応 1.9.0のBeta版でJavaScriptにフォールバックするためのGradle taskが追加 →Kotlin/WasmとKotlin/JS両⽅でコンパイルし、 ユーザー環境に適したプラットフォームを使⽤するコードを⽣成 11 全てのブラウザで使えるように!
Compose for Webの はじめ方 12
プロジェクト作成 AndroidStudioの場合、主に3ステップで作成可能 1. Kotlin Multiplatformプラグインをインストール 2. New ProjectでKotlin Multiplatformテンプレートを選択 3.
Web>Share UIを選択して作成 https://kotlinlang.org/docs/wasm-get-started.html?_cl=MTsxOzE7VnJQR0p3MTB5a0s5T0JJT2hBV0FYd3BISmN zOEE2ekh3dmM1eDRucDQ1NnJhNFkwM3NWV29RUHF2bkNkRUVoZjs= 13
14 https://kotlinlang.org/docs/whatsnew2220.html#shared-source-set-for-js-and-wasmjs-targets Compose Multiplatformのソースセット階層 (Kotlin 2.2.20〜)
15 https://kotlinlang.org/docs/whatsnew2220.html#shared-source-set-for-js-and-wasmjs-targets 共通のCompose実装 ターゲットごとの実装 Compose Multiplatformのソースセット階層 (Kotlin 2.2.20〜)
16 https://kotlinlang.org/docs/whatsnew2220.html#shared-source-set-for-js-and-wasmjs-targets 共通のCompose実装 ターゲットごとの実装 Compose Multiplatformのソースセット階層 (Kotlin 2.2.20〜) 今まではjsとwasmJsが独立していたが、 webの共通実装はまとめて書けるように
なった
webMainの中⾝ webMain ├── kotlin │ ├── main.kt │ └── ・・・
└── resources ├── index.html └── styles.css 17 共通のCompose実装を呼び出すエントリポイント
アプリの実行や配布 便利なGradle tasksが用意されている 18
ローカル環境での実行 →ローカルサーバー(webpack dev server)を⽴ち上げ実行する 19
アーティファクトの⽣成 →build/dist/wasmJs/productionExecutable/に アーティファクトを生成する 20 ◀左図をフォルダの中身ごとデプロイすればOK
補足:生成されたコード(index.html) .jsや.cssを呼び出す記述のみ。bodyの中身は空っぽ 21
補足:生成されたコード(style.css) 枠いっぱいに表示する記述のみ 22
補足:生成されたコード(composeApp.js) 28000行ほどのコードの中に.wasmへの参照やインスタンス 化の処理が含まれている 23
補足:生成されたコード(~.wasm) 中身は読めないが、2つの.wasmファイルが生成される。 ファイル名はハッシュ化されているが、Dev版のcomposeApp.jsのコ メントなどから片方がSkikoライブラリで、もう片方がアプリ本体で あることがわかる 24
Androidアプリのこれ、 Webだとどうなる? 25
作成したアプリ • 出題中の問題をリアルタイムで取得 し、問題に4択で回答できる • 全ての問題を出題後、採点結果/解説 /ランキングを閲覧できる 26
Composeが再利用できるのはわかったけど、 以下のようなケースはどうする? 1. 開発したアプリをデバッグしたい →? 2. クイズをリアルタイムに購読したり、選択した回答を送信をしたい →? 3. デバッグの合間やクイズ終了後などバックグラウンドでの不要な購読を防ぎたい
→? 4. クイズを選択中に誤ってタスクキルしてしまった場合にケアしたい →? 5. QRコードからユーザ固有のパラメータを取得したい →? 27
色々あるけどもしAndroidならこうするかも では、Webだとどうなる? 1. 開発したアプリをデバッグしたい →printlnやLog.dで出力してlogcatで確認 2. クイズをリアルタイムに購読したり、選択した回答を送信をしたい →Apolloライブラリを利用したGraphQL通信 3. デバッグの合間やクイズ終了後などバックグラウンドでの不要な購読を防ぎたい
→Jetpack Lifecycleでの購読管理 4. クイズを選択中に誤ってタスクキルしてしまった場合にケアしたい →Jetpack DataStoreやSharedPreferencesに保存したデータを復元 5. QRコードからユーザ固有のパラメータを取得したい →Android アプリリンクを使いIntent経由でデータ取得 28
実装例の比較 29 項番 項目 Android Compose for Web(Kotlin/Wasm) 1 デバッグ
ログ出力: printlnやLog.d ログ確認: Logcat デバッガー: AndroidStudioでブレークポイント 設定 ログ出力: printlnやKermitなどのサードパーティ製ライ ブラリ ログ確認: DevTools デバッガー: Devtoolsからブレイクポイント設定 2 GraphQL通信 Apollo Kotlin Apollo Kotlin v5 3 購読のライフサイクル管理 Jetpack Lifecycle Jetpack Lifecycle 4 データの永続化 Jetpack DataStore SharedPreferences Web Storage API 5 URLからのパラメータ取得 Intent Window Interface
実装例の比較 30 項番 項目 Android Compose for Web(Kotlin/Wasm) 1 デバッグ
ログ出力: printlnやLog.d ログ確認: Logcat デバッガー: AndroidStudioでブレークポイント 設定 ログ出力: printlnやKermitなどのサードパーティ製ライ ブラリ ログ確認: DevTools デバッガー: Devtoolsからブレイクポイント設定 2 GraphQL通信 Apollo Kotlin Apollo Kotlin v5 3 購読のライフサイクル管理 Jetpack Lifecycle Jetpack Lifecycle 4 データの永続化 Jetpack DataStore SharedPreferences Web Storage API 5 URLからのパラメータ取得 Intent Window Interface
1.デバッグ(ログ出力/確認) • kotlin.io.printlnが利用可能 • android.util.Logは利用できないため、ログレベルを付与したい場合は Kermitなどのサードパーティライブラリを利用する • 出力結果はDevTools > Consoleで確認可能
31
補足:Wasm-JSのkotlin.io.printlnの内部実装 Wasm-JSのprintln実装では内部的にJavaScriptのconsole.logを 呼ぶことでDevToolsのコンソールへの出力を可能にしている 32 https://github.com/JetBrains/kotlin/blob/2.2.20/libraries/stdlib/wasm/js/src/kotlin/io.kt#L23 Kotlin/WasmはJS相互運用の仕組 みを提供しており、 js関数を使うことでJavaScriptスニ ペットを追加できる
1.デバッグ(ブレイクポイント) • DevTools > Sourcesでブレイクポイントを設定可能 33
2.GraphQL通信 • 今回はGraphQLのクライアントライブラリであるApollo Kotlinを利⽤ • commonMainに依存関係を追加し、Android同様の実装を行う ことでMutation(更新)とQuery(取得)は問題なく動作し た • Subscription(購読)は5⽉時点で利⽤したApollo
Kotlin v3で は動作しなかったが、Apollo Kotlin v5(Preview)では wasmJsターゲットもサポート済み 34 https://github.com/apollographql/apollo-kotlin/pull/6637 https://github.com/apollographql/apollo-kotlin/releases
3.購読のライフサイクル管理 • androidx.lifecycle.LifecycleでWebのNative eventがLifecycle eventにマッピ ングされている • Android同様、collectAsStateWithLifecycleで購読することで、コンテンツ非表 示時の購読を避けることが可能(androidx.lifecycle:lifecycle-*:2.9.3以降) 35
https://www.jetbrains.com/help/kotlin-multiplatform-dev/compose-lifecycle.html#web
4.データの永続化 • Webの世界ではブラウザの機能を利用するため、 JavaScriptのBrowser API(Web API)が提供されている • Kotlin/Wasmの標準ライブラリは上記の一部を利用するための宣言を予め定 義しており、これらはパッケージをimportするだけで利用できる 36
https://github.com/Kotlin/kotlinx-browser/blob/master/src/webMain/kotlin/kotlinx/browser/declarations.kt
4.データの永続化 • Browser API(Web API)ではWeb Storage APIでブラウザにキーバ リュー形式の値を保存できる (セッションを超えて値を保持したい場合はlocalStorage) •
kotlinx.browser.localStorageを使って実装する 37 ▼実装例(wasmJsMain/kotlin/LocalStorage.kt)
5.URLからのパラメータ取得 • Browser API(Web API)ではWindow.location.searchからクエリ文字列を 取得できる • kotlinx.browser.windowからsearchプロパティを取得し、よしなにパースす る ※公開運用では個人情報のURL掲載は推奨しません
38 ▶実装例 (wasmJSMain/kotlin/main.kt)
Composeは本当にそのまま実装できる? 39
Composeは本当にそのまま実装できる? →ほとんどできる 40
注意点 • リソース管理 ◦ 画像/フォント/文字列などを共有リソースとして管理するため components-resources ライブラリの追加が必要 ◦ commonMain/composeResources/などに配置し、Resクラスを 介してアクセスする
• ⽇本語表⽰ ◦ デフォルトでフォントがなく⾖腐になるため、フォントファイル をリソースに含める必要がある 41
日本語表示の対応 1. Google FontsなどからttfファイルをDL 2. 共有のリソース置き場(commonMain/composeResources/font/など)に配置 3. Res.font.~で参照しFontFamilyを設定 42 ▼実装例(commonMain/kotlin/App.kt)
Composeは本当にそのまま実装できる? ほとんどできる! https://www.jetbrains.com/help/kotlin-multiplatform-dev/compose-multiplatform-and-jetpack-compose.ht ml#compose-multiplatform-and-jetpack-compose-features 43
補足:参考になるリポジトリ • compose-material-3-gallery ◦ JetBrainsのterrakokさんが作 成したMaterial 3コンポーネン トのショーケース ◦ Android/iOS/Desktop/Browse
rをサポートしており、ほとんど のコンポーネントがWeb版でも そのまま動作することを確認で きる (タブレットではNavigation railを表示するなどAdaptive対 応もされていてすごい) 44
パフォーマンス最適化 45
実際に困ったこと • 初回表示に時間がかかる (特にモバイル回線だと顕著) • フォントのDLが終わるまでの間に 豆腐が表示されてしまう 46
DevToolsでの確認 Networkタブでファイルの転送時間を計測。 モバイル回線での初回表示をシミュレートするために、以下の条 件を設定 • Disable cache:ON • Throttling:カスタムプロファイルで下り50Mbpsを設定 47
補足:検証用のThrottling速度の決め方 以下のデータを参考に日本の一般的なモバイル通信でのダウンロード 速度を50Mbps程度と想定 • 日本の主要4キャリア(au、NTTドコモ、楽天モバイル、ソフト バンク)のDownload速度体験値は43.8〜55.8Mbps(※1) • 日本のモバイル回線でのDownloadの中央値は60.72Mbps (※2) ※1
Opensignal.「Japan Mobile Network Experience Report(April 2025)」.https://www.opensignal.com/reports/2025/04/japan/mobile-network-experience/dt ※2 Ookla.「Speedtest Global Index」(September 2025)」. https://www.speedtest.net/global-index/japan#mobile 48
DevToolsでの確認 全てのファイル転送に3.7秒 主に.wasm/.ttfの転送で時間がかかっている 49
効果のあった対策 1. フォントファイルの圧縮 2. Wasmファイルの圧縮 3. preloadで読み込みの並列化(要HTML修正) 4. 軽量フォントの選定 50
対策1:フォントファイルの圧縮 • woff2形式に圧縮することで半分以下に (4.5MB→2.2MB) • デプロイ時に以下のメタデータを設定する ◦ Content-Type:font/woff2 51
対策2:Wasmファイルの圧縮 • gzip形式に圧縮することで2〜3分の1に (zstdの⽅が⾼圧縮だがSafari⾮対応のため要注意) • デプロイ時にファイル名を.wasm.gzから.wasmに戻し、 以下のメタデータを設定 ◦ Content-Type:application/wasm ◦
Content-Encoding:gzip 52
対策3:preloadで読み込みの並列化 (要HTML修正) HTMLでリソースを事前読み込みさせ、ロードを並列化。 wasmファイルもpreload可能 53 ▼preload設定例(webMain/resouces/index.html)
対策3:preloadで読み込みの並列化 (要HTML修正) 54 ▼修正前 ▼修正後
対策3:preloadで読み込みの並列化 (要HTML修正) 元々は.js→.wasm→.ttf の順にシーケンシャルにloadしていたが、 preloadの設 定をしたことでフォントファイルとその他の loadが並列で行われている 55 ▼修正前 ▼修正後
最適化結果 修正前(3.7秒)→修正後(1.16秒) なんとか許容範囲まで改善 56 対策4:軽量フォントの選定 さらに、 NotoSansJP-Regular(5.5MB)からM PLUS 1p(1.7MB) にすることで0.91秒まで短縮できた
(見た目が変わりすぎるため今回は結局採用せず)
その他の改善 57
ローディング表⽰の追加(要HTML/CSS修正) 平均的なモバイル回線で約1秒、 速度制限などがかかっている場合はもっと長い間、 Composeの描画を開始できない →この間のローディング表⽰はHTML/CSSで記述し、 Composeの描画開始タイミングで非表示にする 58
▼ローディングUI例(webMain/resources/index.html) 59 ▼Composeでの実装例(wasmJSMain/kotlin/main.kt)
サポート外ブラウザへの警告UI表⽰ (要HTML/CSS修正) JavaScriptへのフォールバックを行わない場合、WasmGCサ ポート外のブラウザでは真っ白な画面が表示されてしまう →JavaScriptでWasmの読み込みエラーを検知し、 HTML/CSSで警告⽂などを表⽰する 60
61 ▼警告表⽰UI例(webMain/resources/index.html) ▼Wasmのコンパイルエラーをハンドリングする処理(webMain/resources/index.html)
情報のキャッチアップ 62
おすすめのツール • kotlinlangのSlack ◦ #compose-web ◦ #webassembly • Klibs.io ◦
KMP対応のライブラリ検索に 便利 ◦ Wasmに対応しているものの みをフィルタできる 63
まとめ 64
まとめ • Compose for Webを使い、実際にWebアプリを作成できた ◦ UI実装はもちろん、基本的な実装がしやすいように標準ライブラリでサポートさ れている ◦ サポートされていない実装もサードパーティライブラリで補うことができた
◦ 初回表示の速度に課題があったが、Web特有の最適化を少し行うことで改善でき た • Compose for Webはすべてのブラウザへのサポートを提供している ◦ WasmGCサポートブラウザの普及 ◦ Beta版でのJSフォールバックのサポート 65
まとめ • Compose for Webを使い、実際にWebアプリを作成できた ◦ UI実装はもちろん、基本的な実装がしやすいように標準ライブラリでサポートさ れている ◦ サポートされていない実装もサードパーティライブラリで補うことができた
◦ 初回表示の速度に課題があったが、Web特有の最適化を少し行うことで改善でき た • Compose for Webはすべてのブラウザへのサポートを提供している ◦ WasmGCサポートブラウザの普及 ◦ Beta版でのJSフォールバックのサポート 66 KotlinエンジニアがWebアプリを作る時の選択肢の一つとしていかがでしょうか?
ご清聴いただきありがとうございました 67