Repository: molefrog/wouter
Branch: v3
Commit: 2061eacda7f8
Files: 93
Total size: 252.1 KB
Directory structure:
gitextract_4azr5gv8/
├── .cursor/
│ └── rules/
│ ├── contributing.mdc
│ └── publishing.mdc
├── .gitattributes
├── .github/
│ ├── FUNDING.yml
│ └── workflows/
│ ├── ci-tests.yml
│ └── size.yml
├── .gitignore
├── CLAUDE.md
├── LICENSE
├── README.md
├── bunfig.toml
├── package.json
├── packages/
│ ├── magazin/
│ │ ├── .gitignore
│ │ ├── App.tsx
│ │ ├── client.tsx
│ │ ├── components/
│ │ │ ├── footer.tsx
│ │ │ ├── navbar.tsx
│ │ │ ├── star-wouter.tsx
│ │ │ └── with-status-code.tsx
│ │ ├── db/
│ │ │ └── products.ts
│ │ ├── index.html
│ │ ├── index.tsx
│ │ ├── package.json
│ │ ├── routes/
│ │ │ ├── 404.tsx
│ │ │ ├── about.tsx
│ │ │ ├── cart.tsx
│ │ │ ├── home.tsx
│ │ │ └── products/
│ │ │ └── [slug].tsx
│ │ ├── styles.css
│ │ └── tsconfig.json
│ ├── wouter/
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── index.d.ts
│ │ │ ├── index.js
│ │ │ ├── memory-location.d.ts
│ │ │ ├── memory-location.js
│ │ │ ├── paths.js
│ │ │ ├── react-deps.js
│ │ │ ├── use-browser-location.d.ts
│ │ │ ├── use-browser-location.js
│ │ │ ├── use-hash-location.d.ts
│ │ │ ├── use-hash-location.js
│ │ │ ├── use-sync-external-store.js
│ │ │ └── use-sync-external-store.native.js
│ │ ├── test/
│ │ │ ├── history-patch.test.ts
│ │ │ ├── jest-dom.d.ts
│ │ │ ├── link.test-d.tsx
│ │ │ ├── link.test.tsx
│ │ │ ├── location-hook.test-d.ts
│ │ │ ├── match-route.test-d.ts
│ │ │ ├── memory-location.test-d.ts
│ │ │ ├── memory-location.test.ts
│ │ │ ├── nested-route.test.tsx
│ │ │ ├── parser.test.tsx
│ │ │ ├── redirect.test-d.tsx
│ │ │ ├── redirect.test.tsx
│ │ │ ├── route.test-d.tsx
│ │ │ ├── route.test.tsx
│ │ │ ├── router.test-d.tsx
│ │ │ ├── router.test.tsx
│ │ │ ├── setup.ts
│ │ │ ├── ssr.test.tsx
│ │ │ ├── switch.test.tsx
│ │ │ ├── test-utils.ts
│ │ │ ├── use-browser-location.test-d.ts
│ │ │ ├── use-browser-location.test.tsx
│ │ │ ├── use-hash-location.test-d.ts
│ │ │ ├── use-hash-location.test.tsx
│ │ │ ├── use-location.test.tsx
│ │ │ ├── use-params.test-d.ts
│ │ │ ├── use-params.test.tsx
│ │ │ ├── use-route.test-d.ts
│ │ │ ├── use-route.test.tsx
│ │ │ ├── use-search-params.test.tsx
│ │ │ ├── use-search.test.tsx
│ │ │ └── view-transitions.test.tsx
│ │ └── types/
│ │ ├── index.d.ts
│ │ ├── location-hook.d.ts
│ │ ├── memory-location.d.ts
│ │ ├── router.d.ts
│ │ ├── use-browser-location.d.ts
│ │ └── use-hash-location.d.ts
│ └── wouter-preact/
│ ├── .gitignore
│ ├── package.json
│ ├── src/
│ │ └── react-deps.js
│ ├── test/
│ │ └── preact.test.tsx
│ └── types/
│ ├── index.d.ts
│ ├── location-hook.d.ts
│ ├── memory-location.d.ts
│ ├── router.d.ts
│ ├── use-browser-location.d.ts
│ └── use-hash-location.d.ts
├── specs/
│ └── view-transitions-spec.md
└── tsconfig.json
================================================
FILE CONTENTS
================================================
================================================
FILE: .cursor/rules/contributing.mdc
================================================
---
description:
globs:
alwaysApply: true
---
# Wouter - Minimalist React Router
## Project Overview
Wouter is a **minimalist-friendly ~2.1KB React router** that focuses on performance, small bundle size, and simplicity. It provides hook-based routing for React and Preact applications.
### Key Features
- Tiny bundle size (2.1KB gzipped vs 18.7KB React Router)
- Hook-based API (`useLocation`, `useRoute`, `useParams`, etc.)
- Zero dependencies
- Supports React and Preact
- Optional top-level `` component
- Nested routing support
- SSR support
- Memory location for testing
## Project Structure
```
wouter/
├── packages/
│ ├── wouter/ # Main React package
│ │ ├── src/
│ │ │ ├── index.js # Main router implementation
│ │ │ ├── use-browser-location.js
│ │ │ ├── use-hash-location.js
│ │ │ ├── memory-location.js
│ │ │ ├── react-deps.js # React imports
│ │ │ └── paths.js # Path utilities
│ │ ├── test/ # Test files
│ │ ├── types/ # TypeScript definitions
│ │ └── esm/ # Built ES modules
│ └── wouter-preact/ # Preact package
├── assets/ # Documentation assets
└── .github/ # GitHub workflows
```
## Development Workflow
### Prerequisites
- Node.js v20.17.0+ or v22.9.0+
- npm
### Commands
```bash
# Install dependencies
npm install
# Run tests (watch mode)
npm test
# Run tests (single run)
npm test -- --run
# Run specific test file
npm test -- packages/wouter/test/router.test.tsx --run
# Run tests with coverage
npm test -- --coverage
# Build packages
npm run build
# Type checking
npm run typecheck
# Lint code
npm run lint
```
### Test Files Organization
- `test/router.test.tsx` - Router component and memoization tests
- `test/use-location.test.tsx` - Location hook tests
- `test/use-route.test.tsx` - Route matching tests
- `test/link.test.tsx` - Link component tests
- `test/memory-location.test.ts` - Memory location for testing
- `test/nested-route.test.tsx` - Nested routing tests
- `test/ssr.test.tsx` - Server-side rendering tests
## Key Development Principles
### Performance First
- **Bundle size matters**: Every byte counts. Use size-limit CI checks
- **Stable object references**: Prevent unnecessary re-renders with proper memoization
- **Minimize dependencies**: Zero external dependencies policy
### Code Style
- **Functional programming**: Prefer hooks over class components
- **Compact code**: Optimize for bundle size (may sacrifice readability)
- **React patterns**: Use `React.memo`, `useCallback`, `useMemo` appropriately
### Testing Guidelines
- **Comprehensive coverage**: Test all public APIs
- **Real-world scenarios**: Include complex use cases (like language switching)
- **Memory location**: Use for isolated testing
- **Memoization tests**: Verify stable object references
## Core APIs
### Hooks
- `useLocation()` - Get/set current location
- `useRoute(pattern)` - Match current location against pattern
- `useParams()` - Extract route parameters
- `useSearch()` - Get search/query string
- `useSearchParams()` - Get/set URLSearchParams
- `useRouter()` - Access router configuration
### Components
- `` - Optional configuration wrapper
- `` - Conditional rendering based on path
- `` - Navigation component
- `` - Exclusive routing
- `` - Programmatic navigation
### Location Hooks
- `useBrowserLocation` - Browser history API
- `useHashLocation` - Hash-based routing
- `memoryLocation` - In-memory for testing
## Performance Considerations
### Router Memoization
The Router component uses sophisticated memoization to prevent unnecessary re-renders:
- Only creates new router objects when props actually change
- Preserves stable references for `React.memo` components
- Critical for performance in complex applications
### Bundle Optimization
- Use `// ... existing code ...` pattern in edits to minimize diffs
- Prefer shorter variable names in production builds
- Optimize for gzip/brotli compression
## Common Patterns
### Testing Router Components
```javascript
import { memoryLocation } from "wouter/memory-location";
const { hook } = memoryLocation({ path: "/test/path" });
render(
);
```
### Custom Location Hooks
```javascript
const useCustomLocation = () => {
const [location, setLocation] = useBrowserLocation();
// Add custom logic here
return [location, setLocation];
};
```
### Nested Routing
```javascript
```
## Debugging Tips
### Common Issues
1. **Router memoization**: Check if unnecessary re-renders occur
2. **Base path conflicts**: Verify base path inheritance in nested routers
3. **Pattern matching**: Use regexparam syntax for route patterns
4. **SSR hydration**: Ensure client/server router configs match
### Debugging Tools
- React DevTools Profiler for render tracking
- Network tab for bundle size verification
- Console warnings for deprecated patterns
## Contributing Guidelines
### Before Making Changes
1. Run full test suite: `npm test -- --run`
2. Check bundle size impact
3. Verify TypeScript definitions
4. Test with both React and Preact
### Adding New Features
1. Consider bundle size impact
2. Add comprehensive tests
3. Update TypeScript definitions
4. Document in README if public API
5. Maintain backward compatibility
### Performance Changes
1. Add before/after performance tests
2. Verify memoization behavior
3. Test with complex nested scenarios
4. Check for memory leaks in long-running apps
## Architecture Notes
### Router Context System
- Default router created on-demand
- Context inheritance with override capabilities
- Memoization prevents cascade re-renders
- Base path accumulation in nested routers
### Pattern Matching
- Uses regexparam library internally
- Supports named parameters, wildcards, optional segments
- Regex patterns supported for complex matching
- Loose mode for nested routing
This project prioritizes performance and minimalism while maintaining full feature parity with larger routing solutions.
================================================
FILE: .cursor/rules/publishing.mdc
================================================
---
description:
globs:
alwaysApply: true
---
# Publishing Wouter Packages
This document outlines the process for publishing new versions of the wouter packages to npm.
## Prerequisites
- Ensure you have npm publish permissions for both `wouter` and `wouter-preact` packages
- Have npm authentication set up (you'll need OTP access)
- All tests should be passing
- All changes should be committed to the repository
## Publishing Process
### 1. Version Bump
Update the version in both package.json files:
- `packages/wouter/package.json`
- `packages/wouter-preact/package.json`
For semantic versioning:
- **Patch** (x.x.X): Bug fixes, small improvements
- **Minor** (x.X.x): New features, backward compatible
- **Major** (X.x.x): Breaking changes
### 2. Dry Run Validation
Run dry publish commands to validate the packages before actual publishing:
```bash
npm publish --dry-run -w wouter
npm publish --dry-run -w wouter-preact
```
This will show you:
- Package contents and file list
- Bundle size information
- Version confirmation
- Any potential issues
### 3. Build Verification (Optional)
Check the build artifacts in the `/esm/` folders to ensure the latest updates are properly built:
- `packages/wouter/esm/`
- `packages/wouter-preact/esm/`
The `prepublishOnly` script automatically builds the packages, but it's good to verify.
## ⚠️ Confirmation Required
**ALWAYS ask for user confirmation before proceeding with the following steps:**
### 4. Publish to npm
Publish both packages to the npm registry:
```bash
npm publish -w wouter
npm publish -w wouter-preact
```
**Note:** npm might fail with "EOTP" (Error One-Time Password) even when the OTP was entered correctly in the browser. This is a known npm issue - the packages are usually still published successfully despite the error message.
### 5. Git Commit and Tag
After successful publishing:
1. **Commit the version changes:**
```bash
git add packages/wouter/package.json packages/wouter-preact/package.json
git commit -m "Bump version to X.X.X"
```
2. **Create a version tag:**
```bash
git tag vX.X.X
```
3. **Push to remote (optional):**
```bash
git push origin main
git push origin vX.X.X
```
## Troubleshooting
### Common Issues
- **Authentication errors**: Run `npm login` or use the browser authentication flow
- **OTP timeout**: Generate a fresh OTP code from your authenticator app
- **Permission denied**: Ensure you have publish permissions for both packages
- **Version conflicts**: Check if the version already exists on npm
### Verification
After publishing, verify the packages are available:
- Check [wouter on npm](mdc:https:/www.npmjs.com/package/wouter)
- Check [wouter-preact on npm](mdc:https:/www.npmjs.com/package/wouter-preact)
- Test installation: `npm install wouter@latest`
## Package Information
- **wouter**: Main React package (~22KB package size)
- **wouter-preact**: Preact-specific package (~22KB package size)
- Both packages maintain version parity and should be published together
================================================
FILE: .gitattributes
================================================
* text=auto eol=lf
================================================
FILE: .github/FUNDING.yml
================================================
# These are supported funding model platforms
github: ["molefrog"]
================================================
FILE: .github/workflows/ci-tests.yml
================================================
name: Run Tests & Linters
on:
push:
branches: "*"
pull_request:
branches: "*"
jobs:
build:
runs-on: ubuntu-latest
env:
FORCE_COLOR: true
steps:
- uses: actions/checkout@v4
- name: Setup Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- name: Install Dependencies
run: bun install --frozen-lockfile
- name: Prepare wouter-preact (copy source files)
run: cd packages/wouter-preact && npm run prepublishOnly
- name: Run test
run: bun test --coverage --coverage-reporter=lcov --coverage-reporter=text
- name: Run type check
run: bun run test-types
- name: Lint Sources with ESLint
run: bun run lint
- name: Upload Coverage to Coveralls
uses: coverallsapp/github-action@v2
with:
file: ./coverage/lcov.info
================================================
FILE: .github/workflows/size.yml
================================================
name: Size
on: [pull_request]
jobs:
size:
runs-on: ubuntu-latest
env:
CI_JOB_NUMBER: 1
steps:
- uses: actions/checkout@v3
- uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- name: Install Dependencies
run: bun install --frozen-lockfile
- name: Prepare wouter-preact (copy source files)
run: cd packages/wouter-preact && npm run prepublishOnly
- name: Symlink npm to bun
run: |
sudo ln -sf $(which bun) /usr/local/bin/npm
sudo ln -sf $(which bunx) /usr/local/bin/npx
- uses: andresz1/size-limit-action@v1
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
skip_step: install
build_script: build
================================================
FILE: .gitignore
================================================
# NPM
npm-debug.log*
node_modules/
.npm
# IDEs
.vscode/
*.code-workspace
# bundler
esm/
.cache
# OSX
.DS_Store
.AppleDouble
.LSOverride
# test coverage
coverage/
# type definitions in the project root are copied from types/ folder
# before publishing, so they should be ignored
/*.d.ts
# README is copied from the root folder
packages/wouter/README.md
packages/wouter-preact/README.md
================================================
FILE: CLAUDE.md
================================================
---
description: Use Bun instead of Node.js, npm, pnpm, or vite.
globs: "*.ts, *.tsx, *.html, *.css, *.js, *.jsx, package.json"
alwaysApply: false
---
Default to using Bun instead of Node.js.
- Use `bun ` instead of `node ` or `ts-node `
- Use `bun test` instead of `jest` or `vitest`
- Use `bun build ` instead of `webpack` or `esbuild`
- Use `bun install` instead of `npm install` or `yarn install` or `pnpm install`
- Use `bun run