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:
// @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
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.ts → foo.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
| Command |
Description |
ni |
Install dependencies |
ni <pkg> / ni -D <pkg> |
Add dependency / dev dependency |
nr <script> |
Run script |
nu |
Upgrade dependencies |
nun <pkg> |
Uninstall dependency |
nci |
Clean install (pnpm i --frozen-lockfile) |
nlx <pkg> |
Execute package (npx) |
TypeScript Config
{
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "bundler",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true
}
}
ESLint Setup
// 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
Git Hooks
{
"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:
| Catalog |
Purpose |
prod |
Production dependencies |
inlined |
Bundler-inlined dependencies |
dev |
Dev tools (linter, bundler, testing) |
frontend |
Frontend libraries |
Avoid the default catalog. Catalog names can be adjusted per project needs.
References
| Topic |
Description |
Reference |
| ESLint Config |
Framework support, formatters, rule overrides, VS Code settings |
antfu-eslint-config |
| Project Setup |
.gitignore, GitHub Actions, VS Code extensions |
setting-up |
| App Development |
Vue/Nuxt/UnoCSS conventions and patterns |
app-development |
| Library Development |
tsdown bundling, pure ESM publishing |
library-development |
| Monorepo |
pnpm workspaces, centralized alias, Turborepo |
monorepo |
1---2name: antfu3description: Applies Anthony Fu's opinionated tooling and conventions to JavaScript/TypeScript projects, covering code organization, TypeScript config, ESLint, testing, and pnpm monorepo setup.4---56## Coding Practices78### Code Organization910- **Single responsibility**: Each source file should have a clear, focused scope/purpose11- **Split large files**: Break files when they become large or handle too many concerns12- **Type separation**: Always separate types and interfaces into `types.ts` or `types/*.ts`13- **Constants extraction**: Move constants to a dedicated `constants.ts` file1415### Runtime Environment1617- **Prefer isomorphic code**: Write runtime-agnostic code that works in Node, browser, and workers whenever possible18- **Clear runtime indicators**: When code is environment-specific, add a comment at the top of the file:1920```ts21// @env node22// @env browser23```2425### TypeScript2627- **Explicit return types**: Declare return types explicitly when possible28- **Avoid complex inline types**: Extract complex types into dedicated `type` or `interface` declarations2930### Comments3132- **Avoid unnecessary comments**: Code should be self-explanatory33- **Explain "why" not "how"**: Comments should describe the reasoning or intent, not what the code does3435### Testing (Vitest)3637- Test files: `foo.ts` → `foo.test.ts` (same directory)38- Use `describe`/`it` API (not `test`)39- Use `toMatchSnapshot` for complex outputs40- Use `toMatchFileSnapshot` with explicit path for language-specific snapshots4142---4344## Tooling Choices4546### @antfu/ni Commands4748| Command | Description |49|---------|-------------|50| `ni` | Install dependencies |51| `ni <pkg>` / `ni -D <pkg>` | Add dependency / dev dependency |52| `nr <script>` | Run script |53| `nu` | Upgrade dependencies |54| `nun <pkg>` | Uninstall dependency |55| `nci` | Clean install (`pnpm i --frozen-lockfile`) |56| `nlx <pkg>` | Execute package (`npx`) |5758### TypeScript Config5960```json61{62 "compilerOptions": {63 "target": "ESNext",64 "module": "ESNext",65 "moduleResolution": "bundler",66 "strict": true,67 "esModuleInterop": true,68 "skipLibCheck": true,69 "resolveJsonModule": true,70 "isolatedModules": true,71 "noEmit": true72 }73}74```7576### ESLint Setup7778```js79// eslint.config.mjs80import antfu from '@antfu/eslint-config'8182export default antfu()83```848586When completing tasks, run `pnpm run lint --fix` to format the code and fix coding style.8788For detailed configuration options: [antfu-eslint-config](references/antfu-eslint-config.md)8990### Git Hooks9192```json93{94 "simple-git-hooks": {95 "pre-commit": "pnpm i --frozen-lockfile --ignore-scripts --offline && npx lint-staged"96 },97 "lint-staged": { "*": "eslint --fix" },98 "scripts": {99 "prepare": "npx simple-git-hooks"100 }101}102```103104### pnpm Catalogs105106Use named catalogs in `pnpm-workspace.yaml` for version management:107108| Catalog | Purpose |109|---------|---------|110| `prod` | Production dependencies |111| `inlined` | Bundler-inlined dependencies |112| `dev` | Dev tools (linter, bundler, testing) |113| `frontend` | Frontend libraries |114115Avoid the default catalog. Catalog names can be adjusted per project needs.116117---118119## References120121| Topic | Description | Reference |122|-------|-------------|-----------|123| ESLint Config | Framework support, formatters, rule overrides, VS Code settings | [antfu-eslint-config](references/antfu-eslint-config.md) |124| Project Setup | .gitignore, GitHub Actions, VS Code extensions | [setting-up](references/setting-up.md) |125| App Development | Vue/Nuxt/UnoCSS conventions and patterns | [app-development](references/app-development.md) |126| Library Development | tsdown bundling, pure ESM publishing | [library-development](references/library-development.md) |127| Monorepo | pnpm workspaces, centralized alias, Turborepo | [monorepo](references/monorepo.md) |128