Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/caching-docs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"expressive-code-twoslash": patch
---

feat: add opt-in build-time cache for Twoslash results
8 changes: 8 additions & 0 deletions docs/astro.config.mts
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,14 @@ export default defineConfig({
label: "External Types",
link: "usage/external-types",
},
{
label: "Build-Time Cache",
link: "usage/build-time-cache",
badge: {
text: "v0.6.2",
variant: "success",
},
},
{
label: "Show Emitted Files",
link: "usage/show-emitted-files",
Expand Down
4 changes: 3 additions & 1 deletion docs/src/content/docs/getting-started/installation.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { PackageManagers } from 'starlight-package-managers'
| [Code Cutting](/usage/code-cutting) | ✅ |
| [Callouts](/usage/banners/callouts) | ✅ |
| [TS Compiler Overrides](/usage/ts-compiler-flags) | ✅ |
| [Build-Time Cache](/usage/build-time-cache) | ✅ |
| [Show Emitted Files](/usage/show-emitted-files) | ✅ |

### Installation
Expand Down Expand Up @@ -164,6 +165,7 @@ ecTwoSlash({
includeJsDoc: true,
// @annotate: allowNonStandardJsDocTags is required for like this to work
allowNonStandardJsDocTags: true,
cache: false,
twoslashOptions: {
compilerOptions: {
moduleResolution: 100 satisfies ts.ModuleResolutionKind.Bundler,
Expand All @@ -188,4 +190,4 @@ Another option is to set the `NODE_OPTIONS` environment variable to increase the

```bash
NODE_OPTIONS="--max-old-space-size=8192" astro build
```
```
59 changes: 58 additions & 1 deletion docs/src/content/docs/reference/configuration.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,63 @@ export default defineEcConfig({
});
```

### cache

<PropertySignature>
- Type: `boolean | TwoslashCacheOptions`
- Default: `false`
</PropertySignature>

The `cache` option enables the opt-in persistent disk cache for Twoslash JSON results. Set it to `true` to use the default cache directory, or pass an object to customize where entries are stored, how verbose logging should be, and how cache invalidation should work.

#### Example

```ts twoslash title="ec.config.mjs" {7-12}
import { defineEcConfig } from 'astro-expressive-code';
import ecTwoSlash from "expressive-code-twoslash";

export default defineEcConfig({
plugins: [
ecTwoSlash({
cache: {
dir: ".cache/twoslash",
fingerprint: "docs-v2",
logLevel: "summary",
},
}),
],
});
```

#### TwoslashCacheOptions

##### dir

<PropertySignature>
- Type: `string`
- Default: `.cache/expressive-code-twoslash`
</PropertySignature>

Directory used to persist cached Twoslash JSON artifacts. Relative paths resolve from the plugin `cwd`.

##### fingerprint

<PropertySignature>
- Type: `string`
- Default: `undefined`
</PropertySignature>

Optional caller-controlled invalidation string. Change it whenever you want to force a new cache namespace without moving directories.

##### logLevel

<PropertySignature>
- Type: `"off" | "summary" | "debug"`
- Default: `"summary"`
</PropertySignature>

Controls cache logging verbosity. Use `off` to stay silent, `summary` for one end-of-build summary, or `debug` to also log cache read and write errors as they happen.

### twoslashOptions

<PropertySignature>
Expand Down Expand Up @@ -302,4 +359,4 @@ type CreateTwoslashESLintOptions = {
*/
mergeMessages?: boolean;
}
```
```
100 changes: 100 additions & 0 deletions docs/src/content/docs/usage/build-time-cache.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
---
title: Build-Time Cache
description: Speed up repeated Twoslash builds with the opt-in disk cache.
sidebar:
order: 7
---

import { Aside, TabItem, Tabs } from '@astrojs/starlight/components';

EC-Twoslash can persist Twoslash JSON output to disk and reuse it on later builds. The cache is disabled by default and only turns on when you set the `cache` option.

## Enable the cache

<Tabs>
<TabItem label="Astro">

```ts twoslash title="ec.config.mjs" {7-12}
import { defineEcConfig } from 'astro-expressive-code';
import ecTwoSlash from 'expressive-code-twoslash';

export default defineEcConfig({
plugins: [
ecTwoSlash({
cache: true,
}),
],
});
```

</TabItem>
<TabItem label="Starlight">

```ts twoslash title="ec.config.mjs" {7-12}
import { defineEcConfig } from '@astrojs/starlight/expressive-code';
import ecTwoSlash from 'expressive-code-twoslash';

export default defineEcConfig({
plugins: [
ecTwoSlash({
cache: true,
}),
],
});
```

</TabItem>
</Tabs>

With `cache: true`, EC-Twoslash writes entries to `.cache/expressive-code-twoslash` relative to the plugin `cwd`.

## Customize cache behavior

```ts twoslash title="ec.config.mjs" {7-14}
import { defineEcConfig } from 'astro-expressive-code';
import ecTwoSlash from 'expressive-code-twoslash';

export default defineEcConfig({
plugins: [
ecTwoSlash({
cache: {
dir: '.cache/twoslash',
fingerprint: 'docs-v2',
logLevel: 'summary',
},
}),
],
});
```

- `dir`: cache directory, resolved from the plugin `cwd`
- `fingerprint`: optional invalidation string for forcing a fresh cache namespace
- `logLevel`: `off`, `summary`, or `debug`

## Cache keys

Each cache key includes the rendered snippet input plus the relevant execution context. That means cache entries are automatically invalidated when the code sample or Twoslash environment changes.

The key currently includes:

- snippet contents
- effective Twoslash create and execute options
- plugin context passed into the render
- cache fingerprint
- `expressive-code-twoslash` version
- `@ec-ts/twoslash` version
- `typescript` version

<Aside>
Use `fingerprint` when you want to manually bust the cache, for example after changing external files that affect many snippets or when rotating CI cache keys.
</Aside>

## Logging

- `off`: no cache logging
- `summary`: prints one end-of-build summary with hits, misses, writes, and errors
- `debug`: prints the summary plus per-entry read and write errors

## When to use it

The cache helps most when your docs render the same Twoslash blocks across repeated local builds or CI runs. For one-off builds, leaving it disabled keeps behavior simple.
54 changes: 37 additions & 17 deletions packages/expressive-code-twoslash/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,29 +11,49 @@ A Expressive Code plugin that adds Twoslash support to your Expressive Code Type

[Read the full documentation →](https://twoslash.studiocms.dev)

## Build-Time Cache

Disk caching is opt-in:

```ts
ecTwoSlash({
cache: {
dir: ".cache/twoslash",
logLevel: "summary",
},
});
```

- `dir`: cache directory, resolved from the plugin `cwd`
- `fingerprint`: optional caller-controlled invalidation string
- `logLevel`: `off`, `summary`, or `debug`

The cache key includes the snippet contents, effective Twoslash options, cache fingerprint, plugin version, `@ec-ts/twoslash` version, and TypeScript version.

## Currently Supported Languages

| Language | Identifier |
| -------- | ---------- |
| TypeScript | `ts` |
| React TSX | `tsx` |
| Vue | `vue` |
| Language | Identifier |
| ---------- | ---------- |
| TypeScript | `ts` |
| React TSX | `tsx` |
| Vue | `vue` |

## Currently Supported Features

| Feature | Supported Status |
|-----------------------------------------------------------|------------------|
| [JSDocs and Type Hover boxes](https://twoslash.studiocms.dev/getting-started/basic) | ✅ |
| [Error Handling/Messages](https://twoslash.studiocms.dev/usage/banners/errors) | ✅ |
| [Type Extraction](https://twoslash.studiocms.dev/usage/queries/extractions) | ✅ |
| [Code Completions](https://twoslash.studiocms.dev/usage/queries/completions) | ✅ |
| [Code Highlighting](https://twoslash.studiocms.dev/usage/queries/highlights) | ✅ |
| [Code Cutting](https://twoslash.studiocms.dev/usage/code-cutting) | ✅ |
| [Callouts](https://twoslash.studiocms.dev/usage/banners/callouts) | ✅ |
| [TS Compiler Overrides](https://twoslash.studiocms.dev/usage/ts-compiler-flags) | ✅ |
| [Show Emitted Files](https://twoslash.studiocms.dev/usage/show-emitted-files) | ✅ |
| Feature | Supported Status |
| ----------------------------------------------------------------------------------- | ---------------- |
| [JSDocs and Type Hover boxes](https://twoslash.studiocms.dev/getting-started/basic) | ✅ |
| [Error Handling/Messages](https://twoslash.studiocms.dev/usage/banners/errors) | ✅ |
| [Type Extraction](https://twoslash.studiocms.dev/usage/queries/extractions) | ✅ |
| [Code Completions](https://twoslash.studiocms.dev/usage/queries/completions) | ✅ |
| [Code Highlighting](https://twoslash.studiocms.dev/usage/queries/highlights) | ✅ |
| [Code Cutting](https://twoslash.studiocms.dev/usage/code-cutting) | ✅ |
| [Callouts](https://twoslash.studiocms.dev/usage/banners/callouts) | ✅ |
| [TS Compiler Overrides](https://twoslash.studiocms.dev/usage/ts-compiler-flags) | ✅ |
| [Show Emitted Files](https://twoslash.studiocms.dev/usage/show-emitted-files) | ✅ |

### TODO

- [ ] Make Annotations accessible
- [ ] Use EC's Markdown processing system once released. (Requires support from EC (Planned))

Expand All @@ -45,4 +65,4 @@ A Expressive Code plugin that adds Twoslash support to your Expressive Code Type

- [GitHub: @Hippotastic](https://github.com/hippotastic) for providing/maintaining Expressive Code as well as being a huge help during the development of this plugin!
- [EffectTS Website](https://effect.website/docs) for showing the EC Community that Twoslash CAN be used with Expressive-Code. While they did have the first working version, this re-sparked interest in me building out a fully featured EC-Twoslash plugin for the community.
- [`shiki-twoslash`](https://github.com/shikijs/twoslash/tree/main/packages/shiki-twoslash) for being the example of how to implement the elements within codeblocks as well as providing the basic layouts of the elements.
- [`shiki-twoslash`](https://github.com/shikijs/twoslash/tree/main/packages/shiki-twoslash) for being the example of how to implement the elements within codeblocks as well as providing the basic layouts of the elements.
Loading
Loading