Skip to content

Commit 45fd3ad

Browse files
nakasyouantfu
andauthoredNov 15, 2024··
feat(vitepress-twoslash): cache type informations to improve performance (#798)
Co-authored-by: Anthony Fu <github@antfu.me>
1 parent 33b8b49 commit 45fd3ad

File tree

10 files changed

+160
-18
lines changed

10 files changed

+160
-18
lines changed
 

‎docs/.vitepress/config.ts

+2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { withMermaid } from 'vitepress-plugin-mermaid'
66
import { version } from '../../package.json'
77
import { transformerColorizedBrackets } from '../../packages/colorized-brackets/src'
88
import { transformerMetaWordHighlight, transformerNotationWordHighlight, transformerRemoveNotationEscape } from '../../packages/transformers/src'
9+
import { createFileSystemTypesCache } from '../../packages/vitepress-twoslash/src/cache-fs'
910
import { defaultHoverInfoProcessor, transformerTwoslash } from '../../packages/vitepress-twoslash/src/index'
1011
import vite from './vite.config'
1112

@@ -125,6 +126,7 @@ export default withMermaid(defineConfig({
125126
// Remove shiki_core namespace
126127
.replace(/_shikijs_core\w*\./g, '')
127128
},
129+
typesCache: createFileSystemTypesCache(),
128130
}),
129131
transformerRemoveNotationEscape(),
130132
transformerColorizedBrackets({ explicitTrigger: true }),

‎docs/packages/vitepress.md

+23
Original file line numberDiff line numberDiff line change
@@ -117,3 +117,26 @@ onMounted(() => {
117117
</button>
118118
</template>
119119
```
120+
121+
### File System Cache
122+
123+
To speed up the build process, you can enable the file system cache for the generated types, that shares across multiple builds. By default the cache is stored in the `.vitepress/cache/twoslash` along with other VitePress caches.
124+
125+
In your [`.vitepress/config.ts`](https://vitepress.dev/reference/site-config):
126+
127+
```ts
128+
// .vitepress/config.ts
129+
import { transformerTwoslash } from '@shikijs/vitepress-twoslash'
130+
import { createFileSystemTypesCache } from '@shikijs/vitepress-twoslash/cache-fs' // [!code hl]
131+
import { defineConfig } from 'vitepress'
132+
133+
export default defineConfig({
134+
markdown: {
135+
codeTransformers: [
136+
transformerTwoslash({
137+
typesCache: createFileSystemTypesCache() // [!code hl]
138+
})
139+
]
140+
}
141+
})
142+
```

‎package.json

+4
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
"@rollup/plugin-node-resolve": "catalog:",
2727
"@rollup/plugin-replace": "catalog:",
2828
"@rollup/plugin-terser": "catalog:",
29+
"@shikijs/engine-javascript": "workspace:*",
30+
"@shikijs/engine-oniguruma": "workspace:*",
2931
"@shikijs/markdown-it": "workspace:*",
3032
"@shikijs/monaco": "workspace:*",
3133
"@shikijs/rehype": "workspace:*",
@@ -75,6 +77,8 @@
7577
"resolutions": {
7678
"@shikijs/compat": "workspace:*",
7779
"@shikijs/core": "workspace:*",
80+
"@shikijs/engine-javascript": "workspace:*",
81+
"@shikijs/engine-oniguruma": "workspace:*",
7882
"@shikijs/markdown-it": "workspace:*",
7983
"@shikijs/rehype": "workspace:*",
8084
"@shikijs/transformers": "workspace:*",

‎packages/vitepress-twoslash/build.config.ts

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ export default defineBuildConfig({
55
entries: [
66
'src/index.ts',
77
'src/client.ts',
8+
'src/cache-fs.ts',
89
],
910
declaration: true,
1011
rollup: {

‎packages/vitepress-twoslash/package.json

+4
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@
2727
"types": "./dist/client.d.mts",
2828
"default": "./dist/client.mjs"
2929
},
30+
"./cache-fs": {
31+
"types": "./dist/cache-fs.d.mts",
32+
"default": "./dist/cache-fs.mjs"
33+
},
3034
"./style.css": "./style.css",
3135
"./style-core.css": "./style-core.css"
3236
},
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import type { TwoslashTypesCache } from './types'
2+
import { createHash } from 'node:crypto'
3+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'
4+
import { join, resolve } from 'node:path'
5+
import process from 'node:process'
6+
7+
export interface FileSystemTypeResultCacheOptions {
8+
/**
9+
* The directory to store the cache files.
10+
*
11+
* @default '.vitepress/cache/twoslash'
12+
*/
13+
dir?: string
14+
}
15+
16+
export function createFileSystemTypesCache(options: FileSystemTypeResultCacheOptions = {}): TwoslashTypesCache {
17+
const dir = resolve(process.cwd(), options.dir ?? '.vitepress/cache/twoslash')
18+
19+
return {
20+
init() {
21+
mkdirSync(dir, { recursive: true })
22+
},
23+
read(code) {
24+
const hash = createHash('SHA256').update(code).digest('hex').slice(0, 12)
25+
const filePath = join(dir, `${hash}.json`)
26+
if (!existsSync(filePath)) {
27+
return null
28+
}
29+
return JSON.parse(readFileSync(filePath, { encoding: 'utf-8' }))
30+
},
31+
write(code, data) {
32+
const hash = createHash('SHA256').update(code).digest('hex').slice(0, 12)
33+
const filePath = join(dir, `${hash}.json`)
34+
const json = JSON.stringify(data)
35+
writeFileSync(filePath, json, { encoding: 'utf-8' })
36+
},
37+
}
38+
}

‎packages/vitepress-twoslash/src/index.ts

+24-18
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,14 @@
11
/* eslint-disable node/prefer-global/process */
2-
import type { TransformerTwoslashOptions } from '@shikijs/twoslash/core'
32
import type { ShikiTransformer } from 'shiki'
4-
import type { VueSpecificOptions } from 'twoslash-vue'
5-
import type { TwoslashFloatingVueRendererOptions } from './renderer-floating-vue'
3+
import type { TwoslashExecuteOptions, TwoslashReturn } from 'twoslash'
4+
import type { VitePressPluginTwoslashOptions } from './types'
65
import { createTransformerFactory } from '@shikijs/twoslash/core'
76
import { removeTwoslashNotations } from 'twoslash'
87
import { createTwoslasher } from 'twoslash-vue'
98
import { rendererFloatingVue } from './renderer-floating-vue'
109

1110
export * from './renderer-floating-vue'
12-
13-
interface TransformerTwoslashVueOptions extends TransformerTwoslashOptions {
14-
twoslashOptions?: TransformerTwoslashOptions['twoslashOptions'] & VueSpecificOptions
15-
}
16-
17-
export interface VitePressPluginTwoslashOptions extends TransformerTwoslashVueOptions, TwoslashFloatingVueRendererOptions {
18-
/**
19-
* Requires adding `twoslash` to the code block explicitly to run twoslash
20-
* @default true
21-
*/
22-
explicitTrigger?: TransformerTwoslashOptions['explicitTrigger']
23-
}
11+
export * from './types'
2412

2513
/**
2614
* Create a Shiki transformer for VitePress to enable twoslash integration
@@ -30,6 +18,7 @@ export interface VitePressPluginTwoslashOptions extends TransformerTwoslashVueOp
3018
export function transformerTwoslash(options: VitePressPluginTwoslashOptions = {}): ShikiTransformer {
3119
const {
3220
explicitTrigger = true,
21+
typesCache,
3322
} = options
3423

3524
const onError = (error: any, code: string): void => {
@@ -44,9 +33,24 @@ export function transformerTwoslash(options: VitePressPluginTwoslashOptions = {}
4433
removeTwoslashNotations(code)
4534
}
4635

47-
const twoslash = createTransformerFactory(
48-
createTwoslasher(options.twoslashOptions),
49-
)({
36+
const defaultTwoslasher = createTwoslasher(options.twoslashOptions)
37+
38+
let twoslasher = defaultTwoslasher
39+
// Wrap twoslasher with cache when `resultCache` is provided
40+
if (typesCache) {
41+
twoslasher = ((code: string, extension?: string, options?: TwoslashExecuteOptions): TwoslashReturn => {
42+
const cached = typesCache.read(code) // Restore cache
43+
if (cached)
44+
return cached
45+
46+
const twoslashResult = defaultTwoslasher(code, extension, options)
47+
typesCache.write(code, twoslashResult)
48+
return twoslashResult
49+
}) as typeof defaultTwoslasher
50+
twoslasher.getCacheMap = defaultTwoslasher.getCacheMap
51+
}
52+
53+
const twoslash = createTransformerFactory(twoslasher)({
5054
langs: ['ts', 'tsx', 'js', 'jsx', 'json', 'vue'],
5155
renderer: rendererFloatingVue(options),
5256
onTwoslashError: onError,
@@ -59,6 +63,8 @@ export function transformerTwoslash(options: VitePressPluginTwoslashOptions = {}
5963
? explicitTrigger
6064
: /\btwoslash\b/
6165

66+
typesCache?.init?.()
67+
6268
return {
6369
...twoslash,
6470
name: '@shikijs/vitepress-twoslash',
+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import type { TransformerTwoslashOptions } from '@shikijs/twoslash/core'
2+
import type { TwoslashReturn } from 'twoslash'
3+
import type { VueSpecificOptions } from 'twoslash-vue'
4+
import type { TwoslashFloatingVueRendererOptions } from './renderer-floating-vue'
5+
6+
interface TransformerTwoslashVueOptions extends TransformerTwoslashOptions {
7+
twoslashOptions?: TransformerTwoslashOptions['twoslashOptions'] & VueSpecificOptions
8+
}
9+
10+
export interface VitePressPluginTwoslashOptions extends TransformerTwoslashVueOptions, TwoslashFloatingVueRendererOptions {
11+
/**
12+
* Requires adding `twoslash` to the code block explicitly to run twoslash
13+
* @default true
14+
*/
15+
explicitTrigger?: TransformerTwoslashOptions['explicitTrigger']
16+
17+
/**
18+
* The options for caching resolved types
19+
*
20+
* @example
21+
* ```ts
22+
* import { transformerTwoslash } from '@shikijs/vitepress-twoslash'
23+
* import { createFileSystemTypesCache } from '@shikijs/vitepress-twoslash/cache-fs'
24+
*
25+
* transformerTwoslash({
26+
* typesCache: createFileSystemTypesCache({
27+
* dir: './my-cache-dir'
28+
* })
29+
* })
30+
* ```
31+
*/
32+
typesCache?: TwoslashTypesCache
33+
}
34+
35+
export interface TwoslashTypesCache {
36+
/**
37+
* Read cached result
38+
*
39+
* @param code Source code
40+
*/
41+
read: (code: string) => TwoslashReturn | null
42+
43+
/**
44+
* Save result to cache
45+
*
46+
* @param code Source code
47+
* @param data Twoslash data
48+
*/
49+
write: (code: string, data: TwoslashReturn) => void
50+
51+
/**
52+
* On initialization
53+
*/
54+
init?: () => void
55+
}

‎pnpm-lock.yaml

+8
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎tsconfig.json

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
"@shikijs/transformers": ["./packages/transformers/src/index.ts"],
1313
"@shikijs/twoslash/core": ["./packages/twoslash/src/core.ts"],
1414
"@shikijs/twoslash": ["./packages/twoslash/src/index.ts"],
15+
"@shikijs/vitepress-twoslash/cache-fs": ["./packages/vitepress-twoslash/src/cache-fs.ts"],
1516
"@shikijs/vitepress-twoslash/client": ["./packages/vitepress-twoslash/src/client.ts"],
1617
"@shikijs/vitepress-twoslash": ["./packages/vitepress-twoslash/src/index.ts"],
1718
"@shikijs/markdown-it": ["./packages/markdown-it/src/index.ts"],

0 commit comments

Comments
 (0)
Please sign in to comment.