-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
performance: using custom watcher instead esbuild.watch
- `chokidar` based custom watcher - watch root dir and sub directories - watch resolving extension files - ignore local cache directory - enhance transform plugin - re-transform only changed file
- Loading branch information
1 parent
64a6a02
commit df3855f
Showing
9 changed files
with
221 additions
and
63 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
import path from 'node:path'; | ||
import type { Stats } from 'node:fs'; | ||
import * as chokidar from 'chokidar'; | ||
import { | ||
SOURCE_EXTENSIONS, | ||
ASSET_EXTENSIONS, | ||
} from '@react-native-esbuild/internal'; | ||
import { LOCAL_CACHE_DIR } from '@react-native-esbuild/config'; | ||
import { logger } from '../shared'; | ||
|
||
const WATCH_EXTENSIONS_REGEXP = new RegExp( | ||
`(?:${[...SOURCE_EXTENSIONS, ...ASSET_EXTENSIONS].join('|')})$`, | ||
); | ||
|
||
export class FileSystemWatcher { | ||
private static instance: FileSystemWatcher | null = null; | ||
private watcher: chokidar.FSWatcher | null = null; | ||
private onWatch?: (path: string, stats?: Stats) => void; | ||
|
||
private constructor() { | ||
// empty constructor | ||
} | ||
|
||
public static getInstance(): FileSystemWatcher { | ||
if (FileSystemWatcher.instance === null) { | ||
FileSystemWatcher.instance = new FileSystemWatcher(); | ||
} | ||
return FileSystemWatcher.instance; | ||
} | ||
|
||
private handleWatch(path: string, stats?: Stats): void { | ||
logger.debug('event received from watcher', { path }); | ||
if (!WATCH_EXTENSIONS_REGEXP.test(path)) { | ||
return; | ||
} | ||
this.onWatch?.(path, stats); | ||
} | ||
|
||
setHandler(handler: (path: string, stats?: Stats) => void): this { | ||
this.onWatch = handler; | ||
return this; | ||
} | ||
|
||
watch(targetPath: string): void { | ||
if (this.watcher) { | ||
logger.debug('already watching'); | ||
return; | ||
} | ||
|
||
const ignoreDirectories = [path.join(targetPath, LOCAL_CACHE_DIR)]; | ||
|
||
this.watcher = chokidar | ||
.watch(targetPath, { | ||
alwaysStat: true, | ||
ignoreInitial: true, | ||
ignored: ignoreDirectories, | ||
}) | ||
.on('add', this.handleWatch.bind(this) as typeof this.handleWatch) | ||
.on('addDir', this.handleWatch.bind(this) as typeof this.handleWatch) | ||
.on('change', this.handleWatch.bind(this) as typeof this.handleWatch) | ||
.on('unlink', this.handleWatch.bind(this) as typeof this.handleWatch) | ||
.on('unlinkDir', this.handleWatch.bind(this) as typeof this.handleWatch) | ||
.on('ready', () => { | ||
logger.debug(`watching '${targetPath}'`); | ||
}) | ||
.on('error', (error) => { | ||
logger.error('unexpected error on watcher', error); | ||
}); | ||
} | ||
|
||
close(): void { | ||
if (!this.watcher) { | ||
logger.debug('not watching'); | ||
return; | ||
} | ||
this.watcher.close(); | ||
this.watcher = null; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from './FileSystemWatcher'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
87 changes: 40 additions & 47 deletions
87
packages/plugins/lib/reactNativeRuntimeTransformPlugin/helpers/caches.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,73 +1,66 @@ | ||
import fs from 'node:fs/promises'; | ||
import type { Stats } from 'node:fs'; | ||
import type { OnLoadArgs } from 'esbuild'; | ||
import type { | ||
CacheController, | ||
PluginContext, | ||
} from '@react-native-esbuild/core'; | ||
import type { CacheConfig } from '../../types'; | ||
|
||
export const getTransformedCodeFromCache = async ( | ||
export const makeCacheConfig = async ( | ||
controller: CacheController, | ||
args: OnLoadArgs, | ||
context: PluginContext, | ||
): Promise<{ | ||
code: string | null; | ||
hash: string; | ||
mtimeMs: number; | ||
}> => { | ||
stats?: Stats, | ||
): Promise<CacheConfig> => { | ||
/** | ||
* `id` is combined value (platform, dev, minify) | ||
* use `id` as filesystem hash key generation | ||
* | ||
* md5(id + modified time + file path) = cache key | ||
* number + number + string | ||
* number + number + string | ||
*/ | ||
const { mtimeMs } = await fs.stat(args.path); | ||
const hash = controller.getCacheHash(context.id + mtimeMs + args.path); | ||
const inMemoryCache = controller.readFromMemory(hash); | ||
|
||
const makeReturnValue = ( | ||
data: string | null, | ||
): { | ||
code: string | null; | ||
hash: string; | ||
mtimeMs: number; | ||
} => { | ||
return { code: data, hash, mtimeMs }; | ||
const mtimeMs = (stats ?? (await fs.stat(args.path))).mtimeMs; | ||
return { | ||
hash: controller.getCacheHash(context.id + mtimeMs + args.path), | ||
mtimeMs, | ||
}; | ||
}; | ||
|
||
// 1. find cache from memory | ||
if (inMemoryCache) { | ||
if (inMemoryCache.modifiedAt === mtimeMs) { | ||
// file is not modified, using cache data | ||
return makeReturnValue(inMemoryCache.data); | ||
} | ||
return makeReturnValue(null); | ||
} | ||
|
||
const fsCache = await controller.readFromFileSystem(hash); | ||
|
||
// 2. find cache from file system | ||
if (fsCache) { | ||
controller.writeToMemory(hash, { | ||
data: fsCache, | ||
modifiedAt: mtimeMs, | ||
}); | ||
return makeReturnValue(fsCache); | ||
} | ||
export const getTransformedCodeFromInMemoryCache = ( | ||
controller: CacheController, | ||
cacheConfig: CacheConfig, | ||
): string | null => { | ||
const inMemoryCache = controller.readFromMemory(cacheConfig.hash); | ||
// file is not modified, using cache data | ||
return inMemoryCache && inMemoryCache.modifiedAt === cacheConfig.mtimeMs | ||
? inMemoryCache.data | ||
: null; | ||
}; | ||
|
||
// 3. cache not found | ||
return makeReturnValue(null); | ||
export const getTransformedCodeFromFileSystemCache = async ( | ||
controller: CacheController, | ||
cacheConfig: CacheConfig, | ||
): Promise<string | null> => { | ||
const fsCache = await controller.readFromFileSystem(cacheConfig.hash); | ||
return fsCache ?? null; | ||
}; | ||
|
||
export const writeTransformedCodeToCache = async ( | ||
export const writeTransformedCodeToInMemoryCache = ( | ||
controller: CacheController, | ||
code: string, | ||
hash: string, | ||
mtimeMs: number, | ||
): Promise<void> => { | ||
controller.writeToMemory(hash, { | ||
cacheConfig: CacheConfig, | ||
): void => { | ||
controller.writeToMemory(cacheConfig.hash, { | ||
data: code, | ||
modifiedAt: mtimeMs, | ||
modifiedAt: cacheConfig.mtimeMs, | ||
}); | ||
await controller.writeToFileSystem(hash, code); | ||
}; | ||
|
||
export const writeTransformedCodeToFileSystemCache = ( | ||
controller: CacheController, | ||
code: string, | ||
cacheConfig: CacheConfig, | ||
): Promise<void> => { | ||
return controller.writeToFileSystem(cacheConfig.hash, code); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
df3855f
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Coverage report
Test suite run success
98 tests passing in 14 suites.
Report generated by 🧪jest coverage report action from df3855f