Skip to content

Commit

Permalink
Cache auto-save 3/3: Expose watcher.unstable_autoSaveCache, default e…
Browse files Browse the repository at this point in the history
…nabled (#1434)

Summary:
Pull Request resolved: #1434

Configures a new mechanism for the file map cache to re-save after changes made to the file system while Metro is running.

Currently, If you make a change while Metro is running, Metro will re-process (hash) that file and update an in-memory record, but won't save it. The next time Metro starts up, it will process that file again, and write the cache at the end of startup.

In most cases this provides a modest reduction in startup work/time - proportional to the number of changes in the previous Metro session.

However, it unlocks the potential of doing more processing lazily - ie, we don't need to hash everything up front if we can hash only what we need for a bundle, and then save those hashes in a cache.

We'll use this to implement lazy hashing.

## Implementation
The auto save mechanism is contained within `DiskCacheManager` via generic listening APIs. When the file map emits a `change` event to Metro, we start/restart a configurable debounce timer, and save the cache asynchronously.

The 5 second default is chosen so that we don't try to save while Metro may be busy - eg, a change is likely to be followed by an HMR exchange over the next second or two.

Changelog:
```
 - **[Experimental]**: Auto-save file cache via `config.watcher.unstable_autoSaveCache`
```

Reviewed By: huntie

Differential Revision: D69024198

fbshipit-source-id: 1ab06fba567e981bfa59f0e2f045ee3bcb75e3d5
  • Loading branch information
robhogan authored and facebook-github-bot committed Feb 4, 2025
1 parent af5ffb3 commit 0d39866
Show file tree
Hide file tree
Showing 6 changed files with 47 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,10 @@ Object {
"interval": 30000,
"timeout": 5000,
},
"unstable_autoSaveCache": Object {
"debounceMs": 5000,
"enabled": true,
},
"unstable_workerThreads": false,
"watchman": Object {
"deferStates": Array [
Expand Down Expand Up @@ -356,6 +360,10 @@ Object {
"interval": 30000,
"timeout": 5000,
},
"unstable_autoSaveCache": Object {
"debounceMs": 5000,
"enabled": true,
},
"unstable_workerThreads": false,
"watchman": Object {
"deferStates": Array [
Expand Down Expand Up @@ -539,6 +547,10 @@ Object {
"interval": 30000,
"timeout": 5000,
},
"unstable_autoSaveCache": Object {
"debounceMs": 5000,
"enabled": true,
},
"unstable_workerThreads": false,
"watchman": Object {
"deferStates": Array [
Expand Down Expand Up @@ -722,6 +734,10 @@ Object {
"interval": 30000,
"timeout": 5000,
},
"unstable_autoSaveCache": Object {
"debounceMs": 5000,
"enabled": true,
},
"unstable_workerThreads": false,
"watchman": Object {
"deferStates": Array [
Expand Down
7 changes: 7 additions & 0 deletions packages/metro-config/src/configTypes.flow.js
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,10 @@ type WatcherConfigT = {
timeout: number,
filePrefix: string,
}>,
unstable_autoSaveCache: $ReadOnly<{
enabled: boolean,
debounceMs?: number,
}>,
unstable_workerThreads: boolean,
watchman: $ReadOnly<{
deferStates: $ReadOnlyArray<string>,
Expand All @@ -223,6 +227,9 @@ export type InputConfigT = $ReadOnly<
Partial<{
...WatcherConfigT,
healthCheck?: $ReadOnly<Partial<WatcherConfigT['healthCheck']>>,
unstable_autoSaveCache?: $ReadOnly<
Partial<WatcherConfigT['unstable_autoSaveCache']>,
>,
}>,
>,
}>,
Expand Down
4 changes: 4 additions & 0 deletions packages/metro-config/src/defaults/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,10 @@ const getDefaultValues = (projectRoot: ?string): ConfigT => ({
timeout: 5000,
},
unstable_workerThreads: false,
unstable_autoSaveCache: {
enabled: true,
debounceMs: 5000,
},
watchman: {
deferStates: ['hg.update'],
},
Expand Down
5 changes: 5 additions & 0 deletions packages/metro-config/src/loadConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,11 @@ function mergeConfig<T: $ReadOnly<InputConfigT>>(
// $FlowFixMe: Spreading shapes creates an explosion of union types
...nextConfig.watcher?.healthCheck,
},
unstable_autoSaveCache: {
// $FlowFixMe[exponential-spread]
...totalConfig.watcher?.unstable_autoSaveCache,
...nextConfig.watcher?.unstable_autoSaveCache,
},
},
}),
defaultConfig,
Expand Down
9 changes: 8 additions & 1 deletion packages/metro-config/types/configTypes.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -200,11 +200,18 @@ export interface WatcherConfigT {
timeout: number;
filePrefix: string;
};
unstable_autoSaveCache: {
enabled: boolean;
debounceMs?: number;
};
}

export interface WatcherInputConfigT
extends Partial<Omit<WatcherConfigT, 'healthCheck'>> {
extends Partial<
Omit<WatcherConfigT, 'healthCheck' | 'unstable_autoSaveCache'>
> {
healthCheck?: Partial<WatcherConfigT['healthCheck']>;
unstable_autoSaveCache?: Partial<WatcherConfigT['unstable_autoSaveCache']>;
}

export interface InputConfigT
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,11 @@ function createFileMap(
: config.resolver.dependencyExtractor;
const computeDependencies = dependencyExtractor != null;

const watch = options?.watch == null ? !ci.isCI : options.watch;
const {enabled: autoSaveEnabled, ...autoSaveOpts} =
config.watcher.unstable_autoSaveCache ?? {};
const autoSave = watch && autoSaveEnabled ? autoSaveOpts : false;

return MetroFileMap.create({
cacheManagerFactory:
config?.unstable_fileMapCacheManagerFactory ??
Expand All @@ -76,6 +81,7 @@ function createFileMap(
cacheDirectory:
config.fileMapCacheDirectory ?? config.hasteMapCacheDirectory,
cacheFilePrefix: options?.cacheFilePrefix,
autoSave,
})),
perfLoggerFactory: config.unstable_perfLoggerFactory,
computeDependencies,
Expand Down Expand Up @@ -104,7 +110,7 @@ function createFileMap(
roots: config.watchFolders,
throwOnModuleCollision: options?.throwOnModuleCollision ?? true,
useWatchman: config.resolver.useWatchman,
watch: options?.watch == null ? !ci.isCI : options.watch,
watch,
watchmanDeferStates: config.watcher.watchman.deferStates,
});
}
Expand Down

0 comments on commit 0d39866

Please sign in to comment.