The project is a Compose Multiplatform app targeting Android, iOS, Desktop, and Web (JS + WASM). The goals are:
- Fix
OutOfMemoryError: Java heap spacewhen running WASM distribution build - Deploy WASM to
animations.jayeshseth.proand JS tojs.animations.jayeshseth.pro - Understand debug vs production build commands for all platforms
File: gradle.properties (lines 9, 20)
- Increase Gradle daemon heap:
-Xmx4096M→-Xmx8192M(line 9) - Increase Kotlin daemon heap:
-Xmx4096M→-Xmx8192M(line 20) - Enable parallel builds: uncomment
org.gradle.parallel=true(line 13)
Why 8GB: WASM production builds run Binaryen optimization which is very memory-intensive. 4GB is insufficient. 8GB works for local dev; CI will use GRADLE_OPTS=-Xmx6g to fit within GitHub Actions runner limits (~7GB RAM).
GitHub Pages only supports one site per repo, so both approaches are provided:
WASM at root (/) → animations.jayeshseth.pro
JS at /js/ path → js.animations.jayeshseth.pro redirects here
New file: .github/workflows/deploy-web-ghpages.yml
name: Deploy Web (GitHub Pages)
on:
push:
branches: [main]
workflow_dispatch:
permissions:
contents: read
pages: write
id-token: write
concurrency:
group: "pages"
cancel-in-progress: true
jobs:
build-wasm:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 17
- uses: gradle/actions/setup-gradle@v4
- name: Build WASM distribution
run: ./gradlew :composeApp:wasmJsBrowserDistribution
env:
GRADLE_OPTS: "-Xmx6g"
- uses: actions/upload-artifact@v4
with:
name: wasm-dist
path: composeApp/build/dist/wasmJs/productionExecutable/
build-js:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 17
- uses: gradle/actions/setup-gradle@v4
- name: Build JS distribution
run: ./gradlew :composeApp:jsBrowserDistribution
env:
GRADLE_OPTS: "-Xmx6g"
- uses: actions/upload-artifact@v4
with:
name: js-dist
path: composeApp/build/dist/js/productionExecutable/
deploy:
needs: [build-wasm, build-js]
runs-on: ubuntu-latest
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- uses: actions/download-artifact@v4
with:
name: wasm-dist
path: site/
- uses: actions/download-artifact@v4
with:
name: js-dist
path: site/js/
- name: Add CNAME
run: echo "animations.jayeshseth.pro" > site/CNAME
- uses: actions/configure-pages@v5
- uses: actions/upload-pages-artifact@v3
with:
path: site/
- id: deployment
uses: actions/deploy-pages@v4Manual setup required:
- DNS:
animations.jayeshseth.pro→ CNAME to<username>.github.io - DNS:
js.animations.jayeshseth.pro→ CNAME/redirect toanimations.jayeshseth.pro/js/ - Repo Settings > Pages > Source: "GitHub Actions"
- Repo Settings > Pages > Custom domain:
animations.jayeshseth.pro
Each subdomain gets its own Cloudflare Pages project with independent deployments.
New file: .github/workflows/deploy-web-cloudflare.yml
name: Deploy Web (Cloudflare Pages)
on:
push:
branches: [main]
workflow_dispatch:
jobs:
deploy-wasm:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 17
- uses: gradle/actions/setup-gradle@v4
- name: Build WASM distribution
run: ./gradlew :composeApp:wasmJsBrowserDistribution
env:
GRADLE_OPTS: "-Xmx6g"
- name: Deploy WASM to Cloudflare Pages
uses: cloudflare/wrangler-action@v3
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
command: pages deploy composeApp/build/dist/wasmJs/productionExecutable --project-name=compose-animations-wasm
deploy-js:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 17
- uses: gradle/actions/setup-gradle@v4
- name: Build JS distribution
run: ./gradlew :composeApp:jsBrowserDistribution
env:
GRADLE_OPTS: "-Xmx6g"
- name: Deploy JS to Cloudflare Pages
uses: cloudflare/wrangler-action@v3
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
command: pages deploy composeApp/build/dist/js/productionExecutable --project-name=compose-animations-jsManual setup required:
- Cloudflare account with two Pages projects:
compose-animations-wasmandcompose-animations-js - Add GitHub secrets:
CLOUDFLARE_API_TOKEN,CLOUDFLARE_ACCOUNT_ID - Cloudflare DNS:
animations.jayeshseth.pro→ Pages projectcompose-animations-wasm - Cloudflare DNS:
js.animations.jayeshseth.pro→ Pages projectcompose-animations-js - Custom domains configured in each Cloudflare Pages project settings
No code changes needed — these are the existing Gradle tasks for each platform.
| Mode | Command |
|---|---|
| Debug APK | ./gradlew :composeApp:assembleDebug |
| Release APK | ./gradlew :composeApp:assembleRelease |
| Install Debug | ./gradlew :composeApp:installDebug |
| Debug Bundle | ./gradlew :composeApp:bundleDebug |
| Release Bundle | ./gradlew :composeApp:bundleRelease |
Release already has R8/ProGuard enabled.
| Mode | Mechanism |
|---|---|
| Debug | Xcode > Run (Debug scheme) |
| Release | Xcode > Archive (Release scheme) |
| Mode | Command |
|---|---|
| Debug run | ./gradlew :composeApp:run |
| Package DMG | ./gradlew :composeApp:packageDmg |
| Package MSI | ./gradlew :composeApp:packageMsi |
| Package Deb | ./gradlew :composeApp:packageDeb |
| All formats | ./gradlew :composeApp:createDistributable |
| Mode | Command | Output |
|---|---|---|
| Dev server (hot-reload) | ./gradlew :composeApp:wasmJsBrowserDevelopmentRun |
localhost |
| Dev build | ./gradlew :composeApp:wasmJsBrowserDevelopmentWebpack |
build/dist/wasmJs/developmentExecutable/ |
| Prod build | ./gradlew :composeApp:wasmJsBrowserDistribution |
build/dist/wasmJs/productionExecutable/ |
| Mode | Command | Output |
|---|---|---|
| Dev server (hot-reload) | ./gradlew :composeApp:jsBrowserDevelopmentRun |
localhost |
| Dev build | ./gradlew :composeApp:jsBrowserDevelopmentWebpack |
build/dist/js/developmentExecutable/ |
| Prod build | ./gradlew :composeApp:jsBrowserDistribution |
build/dist/js/productionExecutable/ |
Production web builds include webpack minification, tree-shaking, and (for WASM) Binaryen optimization.
| File | Action |
|---|---|
gradle.properties |
Edit: increase heap to 8GB, enable parallel |
.github/workflows/deploy-web-ghpages.yml |
Create: GitHub Pages workflow (Approach A) |
.github/workflows/deploy-web-cloudflare.yml |
Create: Cloudflare Pages workflow (Approach B) |
- OOM fix: Run
./gradlew :composeApp:wasmJsBrowserDistributionlocally — should complete without OOM - JS build: Run
./gradlew :composeApp:jsBrowserDistribution— verify output inbuild/dist/js/productionExecutable/ - Dev servers: Run
wasmJsBrowserDevelopmentRunandjsBrowserDevelopmentRunto test debug builds - CI: Push to main, verify GitHub Actions workflow runs both builds and deploys