跳到主要內容

精選文章

把 Kotlin Wasm / JS 專案佈署到 GitHub.io

用 Compose Multiplatform 或 Kotlin/Wasm 寫好網頁版之後,最直覺的公開方式就是放到 GitHub Pages。網址會是 https://你的帳號.github.io,免費、HTTPS 現成,也適合當作品展示。

這篇整理實務流程:先用 Gradle 打出發行包,再把 dist 裡的靜態檔拷到 github.io 倉庫。


先搞清楚兩種站

GitHub Pages 常見有兩種位置,拷檔前先決定要用哪一種。

個人首頁站
倉庫名稱必須剛好是 帳號.github.io。
網址:https://帳號.github.io/
檔案放倉庫根目錄,瀏覽器會直接讀 index.html。

專案站
倉庫可以叫任何名字,例如 my-wasm-app。
網址:https://帳號.github.io/my-wasm-app/
檔案一樣可放根目錄,或放 docs/,再到 Settings → Pages 指定來源。

後面範例以「獨立的 帳號.github.io 倉庫」為主,也就是很多人說的「拷到 github.io repo」。


第一步:打 production 發行包

專案根目錄執行(有 gradlew 的那層):

Bash
./gradlew wasmJsBrowserDistribution

若模組名稱是 KMP Wizard 預設的 composeApp:

Bash
./gradlew :composeApp:wasmJsBrowserDistribution

目標是 Kotlin/JS、不是 Wasm 時:

Bash
./gradlew jsBrowserDistribution
# 或
./gradlew :composeApp:jsBrowserDistribution

重點是任務名稱裡的 BrowserDistribution。它會把 HTML、JS、WASM、圖片與 composeResources 一次打包成可直接給瀏覽器讀的靜態網站。

這幾個不要搞混:

任務用途
wasmJsBrowserDevelopmentRun本機開發預覽
wasmJsBrowserProductionRun本機用 production 設定預覽
wasmJsBrowserProductionWebpack多半只有 webpack 產物,資源常要自己補
wasmJsBrowserDistribution要上傳 GitHub Pages 用這個

官方教學也是跑 wasmJsBrowserDistribution,再到發行目錄拿檔案去佈署。


第二步:找到真正要上傳的資料夾

產物不是專案根目錄下隨便一個叫 dist 的資料夾,而是模組 build 裡面這層:

text
composeApp/build/dist/wasmJs/productionExecutable/

常見對照:

目標目錄
Kotlin/WasmcomposeApp/build/dist/wasmJs/productionExecutable/
Kotlin/JScomposeApp/build/dist/js/productionExecutable/
模組叫 webAppwebApp/build/dist/wasmJs/productionExecutable/

打開後通常會看到:

  • index.html
  • *.js
  • *.wasm
  • 資源目錄(例如 composeResources)

拷這個資料夾的內容,不要整份 build/ 丟上去。build/ 裡還有快取、中間檔,又大又沒必要公開。


第三步:拷進 github.io 倉庫

假設目錄長這樣:

text
~/code/
  my-kmp-app/                 ← 原始專案(跑 gradlew 的地方)
  yourname.github.io/         ← Pages 專用倉庫

在原始專案打完包之後:

Bash
# 建議用 rsync:同步且可刪掉舊產物,但不會動到目的地的 .git
rsync -av --delete \
  composeApp/build/dist/wasmJs/productionExecutable/ \
  ../yourname.github.io/

沒有 rsync 也可以:

Bash
cp -R composeApp/build/dist/wasmJs/productionExecutable/. ../yourname.github.io/

注意結尾的 /.:拷的是「資料夾裡的檔案」,不是再套一層 productionExecutable。GitHub Pages 根目錄必須直接看得到 index.html。

用 rsync --delete 前先確認目的地路徑沒寫錯。它會刪掉目的地裡「發行包沒有的檔案」,但應保留 .git。CNAME、自訂 README.md 若不想被刪,就不要加 --delete,或把這些檔另外備份。


第四步:提交並打開 Pages

進 github.io 倉庫:

Bash
cd ../yourname.github.io
git add -A
git commit -m "Update wasm/js build"
git push

第一次佈署時,到該倉庫:

  1. Settings → Pages
  2. Source 選 Deploy from a branch
  3. Branch 選 main(或你實際推送的分支)
  4. Folder 選 / (root)
  5. Save

等一兩分鐘,打開:

text
https://yourname.github.io/

若是專案站,網址會多一層倉庫名:

text
https://yourname.github.io/my-wasm-app/

專案站特別注意:路徑不是根目錄

個人站 帳號.github.io 的資源路徑是 /xxx.js。
專案站卻是 /倉庫名/xxx.js。

如果 index.html 寫死從網站根目錄載入 JS / WASM,專案站會 404、畫面空白。處理方式:

  • 儘量用相對路徑(./composeApp.js),不要寫成 /composeApp.js
  • 或在 index.html 加正確的 base,例如:
HTML
<base href="/my-wasm-app/">

本機用 file:// 開 index.html 通常也不行,Wasm 需要透過 HTTP 提供。要預覽請用 Gradle 的 *Run 任務,或任意靜態伺服器指到 productionExecutable。


瀏覽器與 GitHub Pages 的限制

Kotlin/Wasm 需要較新的瀏覽器(例如 Chrome 119+),因為依賴 WasmGC。

另外,若應用用到 SharedArrayBuffer 或 Wasm threads,伺服器需要這兩個 HTTP header:

text
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp

GitHub Pages 本身不能自訂這些 header。 多數 Compose for Web 展示站仍可直接放上 github.io;若執行期明確要求 cross-origin isolation,可考慮:

  • 在頁面加 coi-serviceworker 這類 service worker 補 header
  • 或改放到能設 _headers 的平台(例如 Cloudflare Pages)

第一次打開後若白畫面,先開開發者工具看 Console / Network:是 .wasm 404、路徑錯,還是瀏覽器太舊,通常一眼能分出來。


建議的更新節奏

之後每次要更新網站,固定三步就好:

Bash
# 1. 在原始專案重建
./gradlew :composeApp:wasmJsBrowserDistribution

# 2. 同步產物到 Pages 倉庫
rsync -av --delete \
  composeApp/build/dist/wasmJs/productionExecutable/ \
  ../yourname.github.io/

# 3. 推送
cd ../yourname.github.io
git add -A && git commit -m "Update site" && git push

想省手動拷檔,也可以之後再加 GitHub Actions:在原始專案 CI 裡跑同一個 Gradle 任務,把 productionExecutable 發到 Pages。手動流程搞懂後,自動化只是把這三步搬到雲端。


快速檢查清單

  • 跑的是 wasmJsBrowserDistribution 或 jsBrowserDistribution,不是 *Run
  • 拷的是 build/dist/.../productionExecutable/ 的內容
  • github.io 根目錄有 index.html
  • Pages 已指定正確分支與 / (root)(或 docs/)
  • 專案站的資源路徑有考慮子路徑
  • 用支援 WasmGC 的瀏覽器測試

一句話記住:Gradle 負責產出可上線的靜態檔,GitHub.io 只負責托管這些檔。 中間那次 copy,就是把程式從開發專案交到公開網站的那一步。 

留言

熱門文章