feat(antfu): document tsnapi, tsdown-stale-guard, and fast-npm-meta

Add an API Stability section to library-development covering tsnapi +
tsdown-stale-guard as paired tsdown plugins for snapshotting public
exports and guarding against stale builds in CI. Add a fast-npm-meta
recipe under Tooling Choices for cheap latest-version lookups.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Anthony Fu
2026-05-01 18:52:15 +09:00
parent c35a5588a5
commit ec2b317091
2 changed files with 68 additions and 1 deletions
+15 -1
View File
@@ -3,7 +3,7 @@ name: antfu
description: Anthony Fu's opinionated tooling and conventions for JavaScript/TypeScript projects. Use when setting up new projects, configuring ESLint/Prettier alternatives, monorepos, library publishing, or when the user mentions Anthony Fu's preferences.
metadata:
author: Anthony Fu
version: "2026.02.03"
version: "2026.05.01"
---
## Coding Practices
@@ -58,6 +58,20 @@ metadata:
| `nci` | Clean install (`pnpm i --frozen-lockfile`) |
| `nlx <pkg>` | Execute package (`npx`) |
### Checking npm Package Versions
Use [`fast-npm-meta`](https://github.com/antfu/fast-npm-meta) to look up the latest version of a package — it queries a small metadata endpoint instead of downloading the full registry payload (which can be megabytes per package).
```bash
nlx fast-npm-meta version vite # 7.3.1
nlx fast-npm-meta version "nuxt@^3.5" # 3.5.22 — range-aware
nlx fast-npm-meta version vite nuxt vue # multiple at once
nlx fast-npm-meta version vite --json # JSON for scripting
nlx fast-npm-meta full vite # full version list + dist-tags
```
Prefer this over `npm view <pkg> version` when you only need the latest version, and over reading `package.json` from the registry directly.
### TypeScript Config
```json
@@ -52,6 +52,59 @@ The `exports: true` option auto-generates the `exports` field in `package.json`
---
## API Stability
For published libraries, lock the public API surface so accidental breaking changes appear as a diff in code review.
| Tool | Purpose |
|------|---------|
| [`tsnapi`](https://github.com/antfu/tsnapi) | Snapshots runtime exports + type declarations into committed `.snapshot.js` / `.snapshot.d.ts` files |
| [`tsdown-stale-guard`](https://github.com/antfu-collective/tsdown-stale-guard) | Hashes build inputs/outputs so CI can prove the committed snapshots match current source |
Install both as dev dependencies and wire them as tsdown plugins:
```ts
// tsdown.config.ts
import { defineConfig } from 'tsdown'
import ApiSnapshot from 'tsnapi/rolldown'
import { StaleGuardRecorder } from 'tsdown-stale-guard'
export default defineConfig({
entry: ['src/index.ts'],
format: ['esm'],
dts: true,
exports: true,
plugins: [
ApiSnapshot(),
StaleGuardRecorder(),
],
})
```
### Updating snapshots
After an intentional API change, regenerate snapshots and commit them:
```bash
nr build # runs tsdown, regenerates .snapshot.* files
# or, ad-hoc:
nlx tsnapi -u
UPDATE_SNAPSHOT=1 nlx tsnapi
```
### CI guard
`tsdown-stale-guard` ships a CLI that exits non-zero when the cached build hash no longer matches the source — run it before snapshot/test steps to guarantee the committed snapshots reflect current code:
```yaml
# .github/workflows/unit-test.yml (excerpt)
- run: nr build
- run: nlx tsdown-stale-guard # fails CI if build is stale
- run: nr test
```
---
## package.json
Required fields for pure ESM library: