0
# Asset Resolution
1
2
Specialized handling for asset files including support for scaling variants, platform-specific assets, and custom asset resolution strategies. Integrates with Metro bundler's asset system for React Native development.
3
4
## Capabilities
5
6
### Asset Resolution Function
7
8
Core function for resolving asset files with scaling variants.
9
10
```typescript { .api }
11
/**
12
* Resolve a file path as an asset with scaling variants
13
* @param context - Resolution context containing asset configuration
14
* @param filePath - Path to the asset file
15
* @returns Asset resolution with file paths or null if not an asset
16
*/
17
function resolveAsset(
18
context: ResolutionContext,
19
filePath: string
20
): AssetResolution | null;
21
22
interface AssetResolution {
23
readonly type: 'assetFiles';
24
readonly filePaths: ReadonlyArray<string>;
25
}
26
```
27
28
**Usage Example:**
29
30
```javascript
31
const { resolveAsset } = require("metro-resolver/src/resolveAsset");
32
33
const context = {
34
assetExts: ['png', 'jpg', 'gif'],
35
resolveAsset: (dirPath, name, ext) => [
36
`${dirPath}/${name}@3x${ext}`,
37
`${dirPath}/${name}@2x${ext}`,
38
`${dirPath}/${name}${ext}`
39
]
40
};
41
42
const result = resolveAsset(context, '/app/assets/icon.png');
43
// Result:
44
// {
45
// type: 'assetFiles',
46
// filePaths: [
47
// '/app/assets/icon@3x.png',
48
// '/app/assets/icon@2x.png',
49
// '/app/assets/icon.png'
50
// ]
51
// }
52
```
53
54
### ResolveAsset Function Type
55
56
Custom asset resolution function interface.
57
58
```typescript { .api }
59
/**
60
* Function to resolve asset files in a directory
61
* @param dirPath - Directory containing the asset
62
* @param assetName - Base name of the asset (without extension)
63
* @param extension - File extension including the dot
64
* @returns Array of resolved asset file paths, or undefined if not found
65
*/
66
type ResolveAsset = (
67
dirPath: string,
68
assetName: string,
69
extension: string
70
) => ReadonlyArray<string> | undefined;
71
```
72
73
### Asset Detection
74
75
Utility function to determine if a filename represents an asset file.
76
77
```typescript { .api }
78
/**
79
* Check if a filename represents an asset based on extension
80
* @param fileName - Filename to check
81
* @param assetExts - Array of asset extensions (without dots)
82
* @returns True if the file is an asset
83
*/
84
function isAssetFile(fileName: string, assetExts: ReadonlyArray<string>): boolean;
85
```
86
87
**Usage Example:**
88
89
```javascript
90
const { isAssetFile } = require("metro-resolver/src/utils/isAssetFile");
91
92
const assetExts = ['png', 'jpg', 'gif', 'svg'];
93
94
console.log(isAssetFile('icon.png', assetExts)); // true
95
console.log(isAssetFile('script.js', assetExts)); // false
96
console.log(isAssetFile('image.jpeg', assetExts)); // false (jpeg not in list)
97
```
98
99
### Asset Extensions Configuration
100
101
Common asset file extensions supported by Metro bundler.
102
103
```typescript { .api }
104
interface AssetConfiguration {
105
/** File extensions considered as assets (without dots) */
106
readonly assetExts: ReadonlyArray<string>;
107
}
108
```
109
110
**Common Asset Extensions:**
111
112
```javascript
113
const assetExts = [
114
// Images
115
'png', 'jpg', 'jpeg', 'gif', 'webp', 'svg',
116
117
// Fonts
118
'ttf', 'otf', 'woff', 'woff2',
119
120
// Audio/Video
121
'mp3', 'mp4', 'wav', 'mov', 'avi',
122
123
// Documents
124
'pdf', 'zip'
125
];
126
```
127
128
### Scaling Variants
129
130
Support for device pixel ratio scaling variants in asset resolution.
131
132
**Scaling Suffix Patterns:**
133
- `@1x` - Standard density (optional, default)
134
- `@2x` - Double density (Retina)
135
- `@3x` - Triple density (iPhone Plus)
136
- `@4x` - Quad density (future devices)
137
138
**Asset Resolution Priority:**
139
1. Exact density match for target device
140
2. Higher density variants (downscaled)
141
3. Lower density variants (upscaled)
142
4. Base variant (no suffix)
143
144
**Example Asset Structure:**
145
146
```
147
assets/
148
├── icon.png # Base 1x version
149
├── icon@2x.png # 2x version for Retina
150
├── icon@3x.png # 3x version for iPhone Plus
151
└── logo.svg # Vector graphics (no scaling needed)
152
```
153
154
### Platform-Specific Assets
155
156
Support for platform-specific asset variants.
157
158
**Platform Suffix Patterns:**
159
- `.ios.png` - iOS specific
160
- `.android.png` - Android specific
161
- `.web.png` - Web specific
162
- `.native.png` - React Native (both iOS and Android)
163
164
**Combined Platform and Scaling:**
165
166
```
167
assets/
168
├── icon.ios.png
169
├── icon.ios@2x.png
170
├── icon.ios@3x.png
171
├── icon.android.png
172
├── icon.android@2x.png
173
└── icon.android@3x.png
174
```
175
176
### Custom Asset Resolution
177
178
Implementation of custom asset resolution strategies.
179
180
**Example: Custom Resolution with Platform Support:**
181
182
```javascript
183
const customResolveAsset = (dirPath, assetName, extension) => {
184
const fs = require('fs');
185
const path = require('path');
186
187
const variants = [];
188
const scales = ['@3x', '@2x', ''];
189
const platforms = context.platform ? [`.${context.platform}`, '.native', ''] : [''];
190
191
// Check all combinations of platform and scale
192
for (const platform of platforms) {
193
for (const scale of scales) {
194
const filename = `${assetName}${platform}${scale}${extension}`;
195
const fullPath = path.join(dirPath, filename);
196
197
if (fs.existsSync(fullPath)) {
198
variants.push(fullPath);
199
}
200
}
201
}
202
203
return variants.length > 0 ? variants : undefined;
204
};
205
206
const context = {
207
assetExts: ['png', 'jpg', 'gif'],
208
resolveAsset: customResolveAsset,
209
platform: 'ios'
210
};
211
```
212
213
### Asset Scaling Detection
214
215
Detection and handling of pre-scaled assets to prevent double-processing.
216
217
```typescript { .api }
218
/**
219
* Regular expression to detect scaling suffixes in asset names
220
*/
221
const SCALING_REGEX = /@\d+(?:\.\d+)?x$/;
222
```
223
224
**Usage in Resolution:**
225
226
```javascript
227
function resolveAsset(context, filePath) {
228
const path = require('path');
229
const basename = path.basename(filePath, path.extname(filePath));
230
231
// Skip resolution for already-scaled assets
232
if (/@\d+(?:\.\d+)?x$/.test(basename)) {
233
return null;
234
}
235
236
// Proceed with normal asset resolution
237
const dirPath = path.dirname(filePath);
238
const extension = path.extname(filePath);
239
const assetName = path.basename(filePath, extension);
240
241
const assets = context.resolveAsset(dirPath, assetName, extension);
242
return assets ? { type: 'assetFiles', filePaths: assets } : null;
243
}
244
```
245
246
### Asset Resolution Context
247
248
Configuration options specific to asset resolution.
249
250
```typescript { .api }
251
interface AssetResolutionContext {
252
/** File extensions considered as assets */
253
assetExts: ReadonlyArray<string>;
254
255
/** Custom asset resolution function */
256
resolveAsset: ResolveAsset;
257
258
/** Current platform for platform-specific assets */
259
platform?: string;
260
261
/** Whether to prefer native variants over platform-specific ones */
262
preferNativePlatform?: boolean;
263
}
264
```
265
266
### Error Handling for Assets
267
268
Asset-specific error handling and fallback strategies.
269
270
```typescript { .api }
271
interface AssetCandidates {
272
readonly type: 'asset';
273
readonly name: string;
274
}
275
```
276
277
**Error Example:**
278
279
```javascript
280
try {
281
const result = Resolver.resolve(context, './missing-image.png', 'ios');
282
} catch (error) {
283
if (error instanceof Resolver.FailedToResolvePathError) {
284
const { candidates } = error;
285
if (candidates.file?.type === 'asset') {
286
console.log(`Asset not found: ${candidates.file.name}`);
287
}
288
}
289
}
290
```
291
292
### Asset Bundle Integration
293
294
Integration with Metro bundler's asset processing pipeline.
295
296
**Asset Resolution Flow:**
297
1. Detect asset file by extension
298
2. Resolve scaling variants
299
3. Apply platform-specific filtering
300
4. Return ordered array of asset paths
301
5. Metro processes assets for bundling
302
303
**Asset Metadata:**
304
305
```typescript { .api }
306
interface AssetMetadata {
307
name: string;
308
type: string;
309
hash: string;
310
scales: number[];
311
platform?: string;
312
width?: number;
313
height?: number;
314
}
315
```
316
317
### Performance Considerations
318
319
Optimization strategies for asset resolution.
320
321
**Caching Strategy:**
322
323
```javascript
324
class CachedAssetResolver {
325
constructor() {
326
this.cache = new Map();
327
}
328
329
resolveAsset(dirPath, assetName, extension) {
330
const key = `${dirPath}/${assetName}${extension}`;
331
332
if (this.cache.has(key)) {
333
return this.cache.get(key);
334
}
335
336
const result = this.performResolution(dirPath, assetName, extension);
337
this.cache.set(key, result);
338
return result;
339
}
340
341
performResolution(dirPath, assetName, extension) {
342
// Actual resolution logic
343
}
344
}
345
```
346
347
**Batch Resolution:**
348
349
```javascript
350
function batchResolveAssets(context, assetPaths) {
351
const results = new Map();
352
353
for (const assetPath of assetPaths) {
354
try {
355
const result = resolveAsset(context, assetPath);
356
if (result) {
357
results.set(assetPath, result);
358
}
359
} catch (error) {
360
// Handle individual asset errors
361
results.set(assetPath, { error: error.message });
362
}
363
}
364
365
return results;
366
}
367
```
368
369
### Asset Development Workflow
370
371
Best practices for organizing assets in development.
372
373
**Recommended Directory Structure:**
374
375
```
376
src/
377
├── assets/
378
│ ├── images/
379
│ │ ├── icons/
380
│ │ │ ├── home.png
381
│ │ │ ├── home@2x.png
382
│ │ │ └── home@3x.png
383
│ │ └── backgrounds/
384
│ ├── fonts/
385
│ └── sounds/
386
└── components/
387
```
388
389
**Asset Import Patterns:**
390
391
```javascript
392
// Direct asset imports
393
import icon from '../assets/images/icons/home.png';
394
395
// Dynamic asset imports
396
const getAsset = (name) => require(`../assets/images/${name}.png`);
397
398
// Platform-specific imports
399
import iconIOS from '../assets/images/icon.ios.png';
400
import iconAndroid from '../assets/images/icon.android.png';
401
```