antfu

Skill

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.

Files6
  • @skills/antfu/SKILL.md
  • @skills/antfu/references/antfu-eslint-config.md
  • @skills/antfu/references/app-development.md
  • @skills/antfu/references/library-development.md
  • @skills/antfu/references/monorepo.md
  • @skills/antfu/references/setting-up.md

Coding Practices

Code Organization

  • Single responsibility: Each source file should have a clear, focused scope/purpose
  • Split large files: Break files when they become large or handle too many concerns
  • Type separation: Always separate types and interfaces into types.ts or types/*.ts
  • Constants extraction: Move constants to a dedicated constants.ts file

Runtime Environment

  • Prefer isomorphic code: Write runtime-agnostic code that works in Node, browser, and workers whenever possible
  • Clear runtime indicators: When code is environment-specific, add a comment at the top of the file:
typescript
// @env node
// @env browser

TypeScript

  • Explicit return types: Declare return types explicitly when possible
  • Avoid complex inline types: Extract complex types into dedicated type or interface declarations

Explicitness

Favor explicit, traceable code over implicit "magic". A reader (human or agent) should be able to follow where every name comes from without running tooling.
  • Explicit imports: Prefer explicit import statements. Avoid auto-imports — when a framework provides them (e.g. Nuxt/Nitro), turn them off for new projects (see app-development [blocked]).
  • No path aliases by default: Use relative imports (./foo, ../bar). Only use path aliases (@/, ~/, #imports, etc.) when they are already configured in the project; don't introduce new ones for greenfield code.

Comments

  • Avoid unnecessary comments: Code should be self-explanatory
  • Explain "why" not "how": Comments should describe the reasoning or intent, not what the code does

Testing (Vitest)

  • Test files: foo.tsfoo.test.ts (same directory)
  • Use describe/it API (not test)
  • Use toMatchSnapshot for complex outputs
  • Use toMatchFileSnapshot with explicit path for language-specific snapshots

Tooling Choices

@antfu/ni Commands

CommandDescription
niInstall dependencies
ni <pkg> / ni -D <pkg>Add dependency / dev dependency
nr <script>Run script
nuUpgrade dependencies
nun <pkg>Uninstall dependency
nciClean install (pnpm i --frozen-lockfile)
nlx <pkg>Execute package (npx)

Checking npm Package Versions

Use 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
{
  "compilerOptions": {
    "target": "ESNext",
    "module": "ESNext",
    "moduleResolution": "bundler",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true
  }
}

ESLint Setup

javascript
// eslint.config.mjs
import antfu from '@antfu/eslint-config'

export default antfu()
When completing tasks, run pnpm run lint --fix to format the code and fix coding style.
For detailed configuration options: antfu-eslint-config [blocked]

Git Hooks

json
{
  "simple-git-hooks": {
    "pre-commit": "pnpm i --frozen-lockfile --ignore-scripts --offline && npx lint-staged"
  },
  "lint-staged": { "*": "eslint --fix" },
  "scripts": {
    "prepare": "npx simple-git-hooks"
  }
}

pnpm Catalogs

Use named catalogs in pnpm-workspace.yaml for version management:
CatalogPurpose
prodProduction dependencies
inlinedBundler-inlined dependencies
devDev tools (linter, bundler, testing)
frontendFrontend libraries
Avoid the default catalog. Catalog names can be adjusted per project needs.

References

TopicDescriptionReference
ESLint ConfigFramework support, formatters, rule overrides, VS Code settingsantfu-eslint-config [blocked]
Project Setup.gitignore, GitHub Actions, VS Code extensionssetting-up [blocked]
App DevelopmentVue/Nuxt/UnoCSS conventions, auto-import control, Storybook component testingapp-development [blocked]
Library Developmenttsdown bundling, pure ESM publishinglibrary-development [blocked]
Monorepopnpm workspaces, centralized alias, Turborepomonorepo [blocked]
antfu — Kortix Marketplace | Kortix