0
# Cache Management
1
2
Pluggable caching system with disk-based implementation for persistent storage of file system state, module maps, and plugin data. The cache system significantly improves startup performance by avoiding full file system crawls when possible.
3
4
## Capabilities
5
6
### CacheManager Interface
7
8
Core interface for implementing custom cache managers.
9
10
```javascript { .api }
11
/**
12
* Interface for cache management implementations
13
*/
14
interface CacheManager {
15
/**
16
* Read cached data during startup
17
* @returns Promise resolving to cached data or null if not available
18
*/
19
read(): Promise<CacheData | null>;
20
21
/**
22
* Write current state to cache
23
* @param getSnapshot - Function returning current state snapshot
24
* @param opts - Write options with event handling
25
* @returns Promise that resolves when write completes
26
*/
27
write(
28
getSnapshot: () => CacheData,
29
opts: CacheManagerWriteOptions
30
): Promise<void>;
31
32
/**
33
* Clean up cache manager resources
34
* @returns Promise that resolves when cleanup completes
35
*/
36
end(): Promise<void>;
37
}
38
```
39
40
**Usage Examples:**
41
42
```javascript
43
// Implement custom cache manager
44
class MemoryCacheManager {
45
constructor() {
46
this.cache = null;
47
}
48
49
async read() {
50
return this.cache;
51
}
52
53
async write(getSnapshot, opts) {
54
this.cache = getSnapshot();
55
console.log('Cache updated in memory');
56
}
57
58
async end() {
59
this.cache = null;
60
}
61
}
62
63
// Use custom cache manager
64
const fileMap = new FileMap({
65
// ... other options
66
cacheManagerFactory: () => new MemoryCacheManager()
67
});
68
```
69
70
### DiskCacheManager Class
71
72
Default disk-based cache manager with automatic persistence and debouncing.
73
74
```javascript { .api }
75
/**
76
* Disk-based cache manager with auto-save capabilities
77
*/
78
class DiskCacheManager implements CacheManager {
79
/**
80
* Create disk cache manager
81
* @param options - Factory options with build parameters
82
* @param config - Disk-specific configuration
83
*/
84
constructor(
85
options: CacheManagerFactoryOptions,
86
config?: DiskCacheConfig
87
);
88
89
/**
90
* Get cache file path for given parameters
91
* @param buildParameters - Build configuration parameters
92
* @param cacheFilePrefix - Optional file prefix (default: 'metro-file-map')
93
* @param cacheDirectory - Optional directory (default: OS temp dir)
94
* @returns Absolute path to cache file
95
*/
96
static getCacheFilePath(
97
buildParameters: BuildParameters,
98
cacheFilePrefix?: string,
99
cacheDirectory?: string
100
): string;
101
102
/**
103
* Get cache file path for this instance
104
* @returns Absolute path to cache file
105
*/
106
getCacheFilePath(): string;
107
108
// CacheManager interface implementation
109
read(): Promise<CacheData | null>;
110
write(getSnapshot: () => CacheData, opts: CacheManagerWriteOptions): Promise<void>;
111
end(): Promise<void>;
112
}
113
```
114
115
**Usage Examples:**
116
117
```javascript
118
import { DiskCacheManager } from "metro-file-map";
119
120
// Create with default configuration
121
const cacheManager = new DiskCacheManager({
122
buildParameters: {
123
// ... build parameters
124
}
125
});
126
127
// Create with custom configuration
128
const customCacheManager = new DiskCacheManager(
129
{ buildParameters },
130
{
131
cacheDirectory: './my-cache',
132
cacheFilePrefix: 'my-app-cache',
133
autoSave: {
134
debounceMs: 2000
135
}
136
}
137
);
138
139
// Get cache file path
140
const cachePath = DiskCacheManager.getCacheFilePath(
141
buildParameters,
142
'my-prefix',
143
'/custom/cache/dir'
144
);
145
console.log('Cache will be stored at:', cachePath);
146
147
// Use with FileMap
148
const fileMap = new FileMap({
149
// ... other options
150
cacheManagerFactory: (options) => new DiskCacheManager(options, {
151
cacheDirectory: process.env.CACHE_DIR || './cache',
152
autoSave: true
153
})
154
});
155
```
156
157
### Cache Data Structure
158
159
Structure of data stored in the cache.
160
161
```javascript { .api }
162
/**
163
* Cache data structure containing file system and plugin state
164
*/
165
interface CacheData {
166
/** Watchman clocks for incremental updates */
167
clocks: WatchmanClocks;
168
/** Serialized file system data */
169
fileSystemData: unknown;
170
/** Plugin state data keyed by plugin name */
171
plugins: ReadonlyMap<string, unknown>;
172
}
173
174
type WatchmanClocks = Map<string, WatchmanClockSpec>;
175
176
type WatchmanClockSpec = string | {
177
scm: {
178
'mergebase-with': string;
179
};
180
};
181
```
182
183
**Usage Examples:**
184
185
```javascript
186
// Read and inspect cache data
187
const cacheData = await fileMap.read();
188
if (cacheData) {
189
console.log('Watchman clocks:', cacheData.clocks.size);
190
console.log('Plugin states:', Array.from(cacheData.plugins.keys()));
191
192
// Check if specific plugin data exists
193
if (cacheData.plugins.has('HastePlugin')) {
194
console.log('Haste plugin state cached');
195
}
196
}
197
```
198
199
### Cache Write Options
200
201
Configuration for cache write operations with event handling.
202
203
```javascript { .api }
204
/**
205
* Options for cache write operations
206
*/
207
interface CacheManagerWriteOptions {
208
/** Whether data changed since last cache read */
209
changedSinceCacheRead: boolean;
210
/** Event source for change notifications */
211
eventSource: CacheManagerEventSource;
212
/** Error handler for write failures */
213
onWriteError: (error: Error) => void;
214
}
215
216
/**
217
* Event source for cache change notifications
218
*/
219
interface CacheManagerEventSource {
220
/**
221
* Subscribe to change events
222
* @param listener - Change event listener
223
* @returns Unsubscribe function
224
*/
225
onChange(listener: () => void): () => void;
226
}
227
```
228
229
**Usage Examples:**
230
231
```javascript
232
// Custom cache manager with event handling
233
class LoggingCacheManager {
234
async write(getSnapshot, opts) {
235
if (opts.changedSinceCacheRead) {
236
console.log('Data changed since cache read, updating...');
237
}
238
239
// Subscribe to future changes
240
const unsubscribe = opts.eventSource.onChange(() => {
241
console.log('File system changed, cache may need update');
242
});
243
244
try {
245
const data = getSnapshot();
246
await this.persistData(data);
247
} catch (error) {
248
opts.onWriteError(error);
249
}
250
251
// Cleanup subscription when appropriate
252
setTimeout(unsubscribe, 60000); // Unsubscribe after 1 minute
253
}
254
}
255
```
256
257
### Cache Factory Pattern
258
259
Factory function pattern for creating cache managers.
260
261
```javascript { .api }
262
/**
263
* Factory function for creating cache managers
264
*/
265
type CacheManagerFactory = (
266
options: CacheManagerFactoryOptions
267
) => CacheManager;
268
269
/**
270
* Options passed to cache manager factories
271
*/
272
interface CacheManagerFactoryOptions {
273
/** Build parameters for cache key generation */
274
buildParameters: BuildParameters;
275
}
276
```
277
278
**Usage Examples:**
279
280
```javascript
281
// Simple factory
282
const simpleCacheFactory = (options) => {
283
return new DiskCacheManager(options, {
284
cacheDirectory: './cache'
285
});
286
};
287
288
// Environment-aware factory
289
const environmentCacheFactory = (options) => {
290
if (process.env.NODE_ENV === 'test') {
291
return new MemoryCacheManager();
292
} else if (process.env.CACHE_DISABLED) {
293
return new NullCacheManager(); // No-op cache
294
} else {
295
return new DiskCacheManager(options, {
296
cacheDirectory: process.env.CACHE_DIR || './cache',
297
autoSave: process.env.NODE_ENV === 'production'
298
});
299
}
300
};
301
302
// Use factory with FileMap
303
const fileMap = new FileMap({
304
// ... other options
305
cacheManagerFactory: environmentCacheFactory
306
});
307
```
308
309
### Auto-Save Configuration
310
311
Automatic cache persistence with debouncing to reduce I/O overhead.
312
313
```javascript { .api }
314
/**
315
* Disk cache configuration options
316
*/
317
interface DiskCacheConfig {
318
/** Auto-save configuration (boolean or options) */
319
autoSave?: boolean | Partial<AutoSaveOptions>;
320
/** Cache file prefix (default: 'metro-file-map') */
321
cacheFilePrefix?: string;
322
/** Cache directory (default: OS temp directory) */
323
cacheDirectory?: string;
324
}
325
326
/**
327
* Auto-save configuration options
328
*/
329
interface AutoSaveOptions {
330
/** Debounce time in milliseconds (default: 5000) */
331
debounceMs: number;
332
}
333
```
334
335
**Usage Examples:**
336
337
```javascript
338
// Enable auto-save with default settings
339
const autoSaveCacheManager = new DiskCacheManager(options, {
340
autoSave: true
341
});
342
343
// Custom auto-save configuration
344
const customAutoSave = new DiskCacheManager(options, {
345
autoSave: {
346
debounceMs: 1000 // Save 1 second after last change
347
},
348
cacheDirectory: './build/cache',
349
cacheFilePrefix: 'my-app'
350
});
351
352
// Disable auto-save (manual control)
353
const manualCacheManager = new DiskCacheManager(options, {
354
autoSave: false
355
});
356
357
// Manual cache operations
358
await manualCacheManager.write(() => getCurrentState(), writeOptions);
359
```
360
361
## Types
362
363
```javascript { .api }
364
interface BuildParameters {
365
computeDependencies: boolean;
366
computeSha1: boolean;
367
enableHastePackages: boolean;
368
enableSymlinks: boolean;
369
extensions: ReadonlyArray<string>;
370
forceNodeFilesystemAPI: boolean;
371
ignorePattern: RegExp;
372
plugins: ReadonlyArray<FileMapPlugin>;
373
retainAllFiles: boolean;
374
rootDir: string;
375
roots: ReadonlyArray<string>;
376
skipPackageJson: boolean;
377
dependencyExtractor: string | null;
378
hasteImplModulePath: string | null;
379
cacheBreaker: string;
380
}
381
```