or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

browser-integration.mdindex.mdmaterial-design.mdresource-management.mdstate-management.mdui-components.mdwindow-management.md

resource-management.mddocs/

0

# Resource Management

1

2

Resource management in Compose Multiplatform for WASM/JS provides an efficient system for loading and managing application assets including images, strings, fonts, and other resources. The system is optimized for web deployment with asynchronous loading, caching, and web-specific optimizations.

3

4

## Resource Configuration

5

6

### configureWebResources

7

8

Essential function for setting up resource loading in WASM applications.

9

10

```kotlin { .api }

11

@OptIn(ExperimentalResourceApi::class)

12

fun configureWebResources(configure: WebResourcesConfiguration.() -> Unit)

13

```

14

15

**Basic Setup:**

16

```kotlin { .api }

17

@OptIn(ExperimentalResourceApi::class)

18

fun main() {

19

configureWebResources {

20

resourcePathMapping { path -> "./$path" }

21

}

22

CanvasBasedWindow("MyApp") {

23

App()

24

}

25

}

26

```

27

28

**Advanced Configuration:**

29

```kotlin { .api }

30

@OptIn(ExperimentalResourceApi::class)

31

fun main() {

32

configureWebResources {

33

resourcePathMapping { path ->

34

when {

35

path.startsWith("images/") -> "./assets/$path"

36

path.startsWith("fonts/") -> "./static/fonts/${path.removePrefix("fonts/")}"

37

else -> "./$path"

38

}

39

}

40

}

41

}

42

```

43

44

### WebResourcesConfiguration

45

46

Configuration object for customizing resource loading behavior.

47

48

```kotlin { .api }

49

class WebResourcesConfiguration {

50

fun resourcePathMapping(mapping: (String) -> String)

51

}

52

```

53

54

## Image Resources

55

56

### painterResource

57

58

Load image resources asynchronously.

59

60

```kotlin { .api }

61

@Composable

62

@OptIn(ExperimentalResourceApi::class)

63

fun painterResource(resource: DrawableResource): Painter

64

```

65

66

**Basic Usage:**

67

```kotlin { .api }

68

@OptIn(ExperimentalResourceApi::class)

69

@Composable

70

fun ImageExample() {

71

Image(

72

painter = painterResource(Res.drawable.logo),

73

contentDescription = "App logo",

74

modifier = Modifier.size(100.dp)

75

)

76

}

77

```

78

79

**Resource Definition:**

80

```kotlin { .api }

81

// Generated resource accessor

82

object Res {

83

object drawable {

84

val logo: DrawableResource = DrawableResource("drawable/logo.png")

85

val background: DrawableResource = DrawableResource("drawable/background.jpg")

86

val icon_user: DrawableResource = DrawableResource("drawable/icon_user.svg")

87

}

88

}

89

```

90

91

### Image Loading States

92

93

Handle loading, success, and error states:

94

95

```kotlin { .api }

96

@OptIn(ExperimentalResourceApi::class)

97

@Composable

98

fun AsyncImageExample() {

99

var imageState by remember { mutableStateOf<ImageLoadState>(ImageLoadState.Loading) }

100

101

Box(modifier = Modifier.size(200.dp)) {

102

when (imageState) {

103

is ImageLoadState.Loading -> {

104

CircularProgressIndicator(

105

modifier = Modifier.align(Alignment.Center)

106

)

107

}

108

is ImageLoadState.Success -> {

109

Image(

110

painter = painterResource(Res.drawable.photo),

111

contentDescription = "Photo",

112

modifier = Modifier.fillMaxSize(),

113

contentScale = ContentScale.Crop

114

)

115

}

116

is ImageLoadState.Error -> {

117

Icon(

118

imageVector = Icons.Default.Error,

119

contentDescription = "Error loading image",

120

modifier = Modifier.align(Alignment.Center),

121

tint = MaterialTheme.colors.error

122

)

123

}

124

}

125

}

126

}

127

128

sealed class ImageLoadState {

129

object Loading : ImageLoadState()

130

object Success : ImageLoadState()

131

data class Error(val exception: Throwable) : ImageLoadState()

132

}

133

```

134

135

### Supported Image Formats

136

137

- **PNG**: Full transparency support

138

- **JPEG**: Optimized compression

139

- **SVG**: Vector graphics with scaling

140

- **WebP**: Modern web format (browser dependent)

141

- **GIF**: Static images (animated GIF support limited)

142

143

## String Resources

144

145

### stringResource

146

147

Load localized string resources.

148

149

```kotlin { .api }

150

@Composable

151

@OptIn(ExperimentalResourceApi::class)

152

fun stringResource(resource: StringResource): String

153

```

154

155

**Usage:**

156

```kotlin { .api }

157

@OptIn(ExperimentalResourceApi::class)

158

@Composable

159

fun LocalizedText() {

160

Text(

161

text = stringResource(Res.string.welcome_message),

162

style = MaterialTheme.typography.h4

163

)

164

}

165

```

166

167

**String Resource Definition:**

168

```kotlin { .api }

169

// Generated resource accessor

170

object Res {

171

object string {

172

val welcome_message: StringResource = StringResource("string/welcome_message")

173

val button_continue: StringResource = StringResource("string/button_continue")

174

val error_network: StringResource = StringResource("string/error_network")

175

}

176

}

177

```

178

179

### Parameterized Strings

180

181

Handle strings with parameters:

182

183

```kotlin { .api }

184

@OptIn(ExperimentalResourceApi::class)

185

@Composable

186

fun ParameterizedString(userName: String, count: Int) {

187

Text(

188

text = stringResource(

189

Res.string.welcome_user,

190

userName,

191

count

192

)

193

)

194

}

195

```

196

197

### Pluralization Support

198

199

```kotlin { .api }

200

@OptIn(ExperimentalResourceApi::class)

201

@Composable

202

fun PluralString(itemCount: Int) {

203

Text(

204

text = pluralStringResource(

205

Res.plurals.items_count,

206

itemCount,

207

itemCount

208

)

209

)

210

}

211

```

212

213

## Font Resources

214

215

### fontResource

216

217

Load custom fonts for typography.

218

219

```kotlin { .api }

220

@Composable

221

@OptIn(ExperimentalResourceApi::class)

222

fun fontResource(resource: FontResource): androidx.compose.ui.text.font.Font

223

```

224

225

**Usage:**

226

```kotlin { .api }

227

@OptIn(ExperimentalResourceApi::class)

228

@Composable

229

fun CustomFontExample() {

230

val customFont = FontFamily(

231

fontResource(Res.font.roboto_regular),

232

fontResource(Res.font.roboto_bold)

233

)

234

235

Text(

236

text = "Custom Font Text",

237

fontFamily = customFont,

238

fontWeight = FontWeight.Bold

239

)

240

}

241

```

242

243

**Font Family Creation:**

244

```kotlin { .api }

245

@OptIn(ExperimentalResourceApi::class)

246

val AppFontFamily = FontFamily(

247

Font(

248

resource = Res.font.opensans_light,

249

weight = FontWeight.Light

250

),

251

Font(

252

resource = Res.font.opensans_regular,

253

weight = FontWeight.Normal

254

),

255

Font(

256

resource = Res.font.opensans_medium,

257

weight = FontWeight.Medium

258

),

259

Font(

260

resource = Res.font.opensans_bold,

261

weight = FontWeight.Bold

262

)

263

)

264

```

265

266

### Supported Font Formats

267

268

- **TTF**: TrueType fonts

269

- **OTF**: OpenType fonts

270

- **WOFF**: Web Open Font Format

271

- **WOFF2**: Web Open Font Format 2.0 (preferred for web)

272

273

## Raw Resources

274

275

### Access Raw Files

276

277

Load arbitrary resource files:

278

279

```kotlin { .api }

280

@OptIn(ExperimentalResourceApi::class)

281

suspend fun readResourceBytes(resource: Resource): ByteArray

282

283

@OptIn(ExperimentalResourceApi::class)

284

suspend fun readResourceText(resource: Resource): String

285

```

286

287

**Usage:**

288

```kotlin { .api }

289

@OptIn(ExperimentalResourceApi::class)

290

@Composable

291

fun ConfigLoader() {

292

var config by remember { mutableStateOf<String?>(null) }

293

294

LaunchedEffect(Unit) {

295

config = readResourceText(Res.files.config_json)

296

}

297

298

config?.let { configText ->

299

// Parse and use configuration

300

val configData = Json.decodeFromString<Config>(configText)

301

ConfigDisplay(configData)

302

}

303

}

304

```

305

306

## Resource Organization

307

308

### Directory Structure

309

310

```

311

src/commonMain/composeResources/

312

├── drawable/

313

│ ├── logo.png

314

│ ├── background.jpg

315

│ └── icons/

316

│ ├── user.svg

317

│ └── settings.png

318

├── font/

319

│ ├── roboto-regular.ttf

320

│ ├── roboto-bold.ttf

321

│ └── opensans.woff2

322

├── values/

323

│ ├── strings.xml

324

│ └── strings-es.xml

325

└── files/

326

├── config.json

327

└── data.csv

328

```

329

330

### Resource Naming

331

332

**Naming Conventions:**

333

- Use lowercase with underscores: `user_profile.png`

334

- Group related resources: `icon_home.svg`, `icon_settings.svg`

335

- Include size indicators: `logo_small.png`, `logo_large.png`

336

- Use descriptive names: `background_login.jpg`, `button_primary.png`

337

338

## Localization

339

340

### Multi-language Support

341

342

**String Resources (values/strings.xml):**

343

```xml

344

<resources>

345

<string name="app_name">My App</string>

346

<string name="welcome_message">Welcome to the app!</string>

347

<string name="button_continue">Continue</string>

348

</resources>

349

```

350

351

**Spanish Resources (values-es/strings.xml):**

352

```xml

353

<resources>

354

<string name="app_name">Mi Aplicación</string>

355

<string name="welcome_message">¡Bienvenido a la aplicación!</string>

356

<string name="button_continue">Continuar</string>

357

</resources>

358

```

359

360

### Language Detection

361

362

```kotlin { .api }

363

@Composable

364

fun LocalizedApp() {

365

val currentLanguage = getCurrentLanguage()

366

367

// Resources automatically load based on system language

368

Text(stringResource(Res.string.welcome_message))

369

}

370

371

fun getCurrentLanguage(): String {

372

return kotlinx.browser.window.navigator.language

373

}

374

```

375

376

## Caching and Performance

377

378

### Browser Caching

379

380

Resources are automatically cached by the browser:

381

- **Images**: Cached with ETags and cache headers

382

- **Fonts**: Long-term browser caching

383

- **Strings**: Loaded once and cached in memory

384

385

### Preloading Strategies

386

387

**Critical Resources:**

388

```kotlin { .api }

389

@OptIn(ExperimentalResourceApi::class)

390

@Composable

391

fun PreloadCriticalResources() {

392

LaunchedEffect(Unit) {

393

// Preload critical images

394

painterResource(Res.drawable.logo)

395

painterResource(Res.drawable.splash_background)

396

397

// Preload fonts

398

fontResource(Res.font.primary_font)

399

}

400

}

401

```

402

403

**Lazy Loading:**

404

```kotlin { .api }

405

@OptIn(ExperimentalResourceApi::class)

406

@Composable

407

fun LazyImageGrid(images: List<ImageResource>) {

408

LazyColumn {

409

items(images) { imageResource ->

410

// Images load only when needed

411

AsyncImage(

412

resource = imageResource,

413

contentDescription = null,

414

modifier = Modifier.fillMaxWidth()

415

)

416

}

417

}

418

}

419

```

420

421

## Error Handling

422

423

### Resource Loading Errors

424

425

```kotlin { .api }

426

@OptIn(ExperimentalResourceApi::class)

427

@Composable

428

fun RobustImageLoading() {

429

var hasError by remember { mutableStateOf(false) }

430

431

if (hasError) {

432

// Fallback content

433

Box(

434

modifier = Modifier.size(100.dp),

435

contentAlignment = Alignment.Center

436

) {

437

Icon(

438

imageVector = Icons.Default.BrokenImage,

439

contentDescription = "Image not available"

440

)

441

}

442

} else {

443

Image(

444

painter = painterResource(Res.drawable.user_photo),

445

contentDescription = "User photo",

446

modifier = Modifier.size(100.dp),

447

onError = { hasError = true }

448

)

449

}

450

}

451

```

452

453

### Network Failures

454

455

```kotlin { .api }

456

@OptIn(ExperimentalResourceApi::class)

457

@Composable

458

fun NetworkAwareResourceLoading() {

459

var isOnline by remember { mutableStateOf(true) }

460

461

LaunchedEffect(Unit) {

462

// Monitor network status

463

isOnline = checkNetworkStatus()

464

}

465

466

if (isOnline) {

467

Image(painterResource(Res.drawable.online_content))

468

} else {

469

// Show cached or offline content

470

Image(painterResource(Res.drawable.offline_placeholder))

471

Text("Offline mode")

472

}

473

}

474

```

475

476

## WASM-Specific Considerations

477

478

### Bundle Size Optimization

479

480

- **Image compression**: Use WebP and optimized formats

481

- **Font subsetting**: Include only required character sets

482

- **Tree shaking**: Unused resources are automatically excluded

483

- **Compression**: Resources are compressed in the build process

484

485

### Loading Performance

486

487

- **Async loading**: All resources load asynchronously

488

- **Streaming**: Large resources can be streamed

489

- **Parallel loading**: Multiple resources load simultaneously

490

- **Progressive enhancement**: App starts before all resources load

491

492

### Memory Management

493

494

- **Automatic cleanup**: Browser manages resource memory

495

- **Cache limits**: Browser enforces cache size limits

496

- **Manual cleanup**: Use `DisposableEffect` for large resources

497

498

```kotlin { .api }

499

@OptIn(ExperimentalResourceApi::class)

500

@Composable

501

fun LargeResourceManager() {

502

DisposableEffect(Unit) {

503

val largeResource = loadLargeResource()

504

505

onDispose {

506

// Cleanup if needed

507

largeResource.dispose()

508

}

509

}

510

}

511

```