|
| 1 | +--- |
| 2 | +name: antfu |
| 3 | +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. |
| 4 | +metadata: |
| 5 | + author: Anthony Fu |
| 6 | + version: "2026.05.01" |
| 7 | +--- |
| 8 | + |
| 9 | +## Coding Practices |
| 10 | + |
| 11 | +### Code Organization |
| 12 | + |
| 13 | +- **Single responsibility**: Each source file should have a clear, focused scope/purpose |
| 14 | +- **Split large files**: Break files when they become large or handle too many concerns |
| 15 | +- **Type separation**: Always separate types and interfaces into `types.ts` or `types/*.ts` |
| 16 | +- **Constants extraction**: Move constants to a dedicated `constants.ts` file |
| 17 | + |
| 18 | +### Runtime Environment |
| 19 | + |
| 20 | +- **Prefer isomorphic code**: Write runtime-agnostic code that works in Node, browser, and workers whenever possible |
| 21 | +- **Clear runtime indicators**: When code is environment-specific, add a comment at the top of the file: |
| 22 | + |
| 23 | +```ts |
| 24 | +// @env node |
| 25 | +// @env browser |
| 26 | +``` |
| 27 | + |
| 28 | +### TypeScript |
| 29 | + |
| 30 | +- **Explicit return types**: Declare return types explicitly when possible |
| 31 | +- **Avoid complex inline types**: Extract complex types into dedicated `type` or `interface` declarations |
| 32 | + |
| 33 | +### Comments |
| 34 | + |
| 35 | +- **Avoid unnecessary comments**: Code should be self-explanatory |
| 36 | +- **Explain "why" not "how"**: Comments should describe the reasoning or intent, not what the code does |
| 37 | + |
| 38 | +### Testing (Vitest) |
| 39 | + |
| 40 | +- Test files: `foo.ts` → `foo.test.ts` (same directory) |
| 41 | +- Use `describe`/`it` API (not `test`) |
| 42 | +- Use `toMatchSnapshot` for complex outputs |
| 43 | +- Use `toMatchFileSnapshot` with explicit path for language-specific snapshots |
| 44 | + |
| 45 | +--- |
| 46 | + |
| 47 | +## Tooling Choices |
| 48 | + |
| 49 | +### @antfu/ni Commands |
| 50 | + |
| 51 | +| Command | Description | |
| 52 | +|---------|-------------| |
| 53 | +| `ni` | Install dependencies | |
| 54 | +| `ni <pkg>` / `ni -D <pkg>` | Add dependency / dev dependency | |
| 55 | +| `nr <script>` | Run script | |
| 56 | +| `nu` | Upgrade dependencies | |
| 57 | +| `nun <pkg>` | Uninstall dependency | |
| 58 | +| `nci` | Clean install (`pnpm i --frozen-lockfile`) | |
| 59 | +| `nlx <pkg>` | Execute package (`npx`) | |
| 60 | + |
| 61 | +### Checking npm Package Versions |
| 62 | + |
| 63 | +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). |
| 64 | + |
| 65 | +```bash |
| 66 | +nlx fast-npm-meta version vite # 7.3.1 |
| 67 | +nlx fast-npm-meta version "nuxt@^3.5" # 3.5.22 — range-aware |
| 68 | +nlx fast-npm-meta version vite nuxt vue # multiple at once |
| 69 | +nlx fast-npm-meta version vite --json # JSON for scripting |
| 70 | +nlx fast-npm-meta full vite # full version list + dist-tags |
| 71 | +``` |
| 72 | + |
| 73 | +Prefer this over `npm view <pkg> version` when you only need the latest version, and over reading `package.json` from the registry directly. |
| 74 | + |
| 75 | +### TypeScript Config |
| 76 | + |
| 77 | +```json |
| 78 | +{ |
| 79 | + "compilerOptions": { |
| 80 | + "target": "ESNext", |
| 81 | + "module": "ESNext", |
| 82 | + "moduleResolution": "bundler", |
| 83 | + "strict": true, |
| 84 | + "esModuleInterop": true, |
| 85 | + "skipLibCheck": true, |
| 86 | + "resolveJsonModule": true, |
| 87 | + "isolatedModules": true, |
| 88 | + "noEmit": true |
| 89 | + } |
| 90 | +} |
| 91 | +``` |
| 92 | + |
| 93 | +### ESLint Setup |
| 94 | + |
| 95 | +```js |
| 96 | +// eslint.config.mjs |
| 97 | +import antfu from '@antfu/eslint-config' |
| 98 | + |
| 99 | +export default antfu() |
| 100 | +``` |
| 101 | + |
| 102 | + |
| 103 | +When completing tasks, run `pnpm run lint --fix` to format the code and fix coding style. |
| 104 | + |
| 105 | +For detailed configuration options: [antfu-eslint-config](references/antfu-eslint-config.md) |
| 106 | + |
| 107 | +### Git Hooks |
| 108 | + |
| 109 | +```json |
| 110 | +{ |
| 111 | + "simple-git-hooks": { |
| 112 | + "pre-commit": "pnpm i --frozen-lockfile --ignore-scripts --offline && npx lint-staged" |
| 113 | + }, |
| 114 | + "lint-staged": { "*": "eslint --fix" }, |
| 115 | + "scripts": { |
| 116 | + "prepare": "npx simple-git-hooks" |
| 117 | + } |
| 118 | +} |
| 119 | +``` |
| 120 | + |
| 121 | +### pnpm Catalogs |
| 122 | + |
| 123 | +Use named catalogs in `pnpm-workspace.yaml` for version management: |
| 124 | + |
| 125 | +| Catalog | Purpose | |
| 126 | +|---------|---------| |
| 127 | +| `prod` | Production dependencies | |
| 128 | +| `inlined` | Bundler-inlined dependencies | |
| 129 | +| `dev` | Dev tools (linter, bundler, testing) | |
| 130 | +| `frontend` | Frontend libraries | |
| 131 | + |
| 132 | +Avoid the default catalog. Catalog names can be adjusted per project needs. |
| 133 | + |
| 134 | +--- |
| 135 | + |
| 136 | +## References |
| 137 | + |
| 138 | +| Topic | Description | Reference | |
| 139 | +|-------|-------------|-----------| |
| 140 | +| ESLint Config | Framework support, formatters, rule overrides, VS Code settings | [antfu-eslint-config](references/antfu-eslint-config.md) | |
| 141 | +| Project Setup | .gitignore, GitHub Actions, VS Code extensions | [setting-up](references/setting-up.md) | |
| 142 | +| App Development | Vue/Nuxt/UnoCSS conventions and patterns | [app-development](references/app-development.md) | |
| 143 | +| Library Development | tsdown bundling, pure ESM publishing | [library-development](references/library-development.md) | |
| 144 | +| Monorepo | pnpm workspaces, centralized alias, Turborepo | [monorepo](references/monorepo.md) | |
0 commit comments