Skip to content

Commit d8eeff0

Browse files
sapphi-redantfu
andauthored
feat: add fsCache option to improve build performance (#56)
Co-authored-by: Anthony Fu <github@antfu.me>
1 parent 5698a87 commit d8eeff0

File tree

2 files changed

+58
-10
lines changed

2 files changed

+58
-10
lines changed

packages/twoslash/src/core.ts

Lines changed: 51 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { ErrorLevel, NodeError, NodeWithoutPosition, Position, Range } from 'twoslash-protocol'
2-
import type { CompilerOptions, CompletionEntry, CompletionTriggerKind, DiagnosticCategory, JsxEmit } from 'typescript'
2+
import type { CompilerOptions, CompletionEntry, CompletionTriggerKind, DiagnosticCategory, JsxEmit, System } from 'typescript'
33

44
import type { CompilerOptionDeclaration, CreateTwoslashOptions, TwoslashExecuteOptions, TwoslashInstance, TwoslashOptions, TwoslashReturn, TwoslashReturnMeta, VirtualFile } from './types'
55
import { createFSBackedSystem, createSystem, createVirtualTypeScriptEnvironment } from '@typescript/vfs'
@@ -28,15 +28,7 @@ export function createTwoslasher(createOptions: CreateTwoslashOptions = {}): Two
2828
const vfs = createOptions.fsMap || new Map<string, string>()
2929
const system = useFS
3030
? createSystem(vfs)
31-
: {
32-
...createFSBackedSystem(vfs, _root, ts, createOptions.tsLibDirectory),
33-
// To work with non-hoisted packages structure
34-
realpath(path: string) {
35-
if (vfs.has(path))
36-
return path
37-
return ts.sys.realpath?.(path) || path
38-
},
39-
}
31+
: createCacheableFSBackedSystem(vfs, _root, ts, createOptions.tsLibDirectory, createOptions.fsCache)
4032
const fsRoot = useFS ? '/' : `${_root}/`
4133

4234
const cache = createOptions.cache === false
@@ -508,6 +500,55 @@ export function createTwoslasher(createOptions: CreateTwoslashOptions = {}): Two
508500
return twoslasher
509501
}
510502

503+
function createCacheableFSBackedSystem(
504+
vfs: Map<string, string>,
505+
root: string,
506+
ts: TS,
507+
tsLibDirectory?: string,
508+
enableFsCache = true,
509+
): System {
510+
function withCache<T>(fn: (key: string) => T) {
511+
const cache = new Map<string, T>()
512+
return (key: string) => {
513+
const cached = cache.get(key)
514+
if (cached !== undefined)
515+
return cached
516+
517+
const result = fn(key)
518+
cache.set(key, result)
519+
return result
520+
}
521+
}
522+
const cachedReadFile = withCache(ts.sys.readFile)
523+
524+
const cachedTs = enableFsCache
525+
? {
526+
...ts,
527+
sys: {
528+
...ts.sys,
529+
directoryExists: withCache(ts.sys.directoryExists),
530+
fileExists: withCache(ts.sys.fileExists),
531+
...(ts.sys.realpath ? { realpath: withCache(ts.sys.realpath) } : {}),
532+
readFile(path, encoding) {
533+
if (encoding === undefined)
534+
return cachedReadFile(path)
535+
return ts.sys.readFile(path, encoding)
536+
},
537+
} satisfies System,
538+
}
539+
: ts
540+
541+
return {
542+
...createFSBackedSystem(vfs, root, cachedTs, tsLibDirectory),
543+
// To work with non-hoisted packages structure
544+
realpath(path: string) {
545+
if (vfs.has(path))
546+
return path
547+
return cachedTs.sys.realpath?.(path) || path
548+
},
549+
}
550+
}
551+
511552
/**
512553
* Run Twoslash on a string of code
513554
*

packages/twoslash/src/types/options.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,4 +85,11 @@ export interface CreateTwoslashOptions extends TwoslashExecuteOptions {
8585
* Cache the ts envs based on compiler options, defaults to true
8686
*/
8787
cache?: boolean | Map<string, VirtualTypeScriptEnvironment>
88+
89+
/**
90+
* Cache file system requests
91+
*
92+
* @default true
93+
*/
94+
fsCache?: boolean
8895
}

0 commit comments

Comments
 (0)