Thank you for your interest in contributing! This document provides guidelines and instructions for contributing to @page-speed/hooks.
Be respectful, inclusive, and constructive. We're building a welcoming community for developers passionate about web performance.
- Node.js 18+
- pnpm 9+
- Git
# Clone the repository
git clone https://github.com/opensite-ai/page-speed-hooks.git
cd page-speed-hooks
# Install dependencies
pnpm install
# Start watching
pnpm dev
# Run tests
pnpm test
# Type check
pnpm type-check
# Build
pnpm build
# Check bundle sizes
pnpm sizeFound a bug? Have a feature request? Open an issue.
Please include:
- Clear description of the issue
- Steps to reproduce (for bugs)
- Expected vs. actual behavior
- Environment (browser, Node.js version, etc.)
- Code examples if applicable
Ideas for new hooks or improvements? Start a discussion.
Good enhancement candidates:
- New performance-related hooks
- Improved documentation
- Better error messages
- Performance optimizations
- Framework-specific integrations
Before starting work:
- Check existing issues and discussions to avoid duplicates
- For new features, open an issue first to discuss the approach
- Follow the coding standards below
Creating a PR:
# Create a feature branch
git checkout -b feature/your-feature-name
# Make changes
# Write/update tests
# Update documentation
# Verify everything works
pnpm type-check
pnpm test
pnpm build
pnpm size
# Commit with clear messages
git commit -m "feat: add useCLS hook for layout shift tracking"
# Push and create PR
git push origin feature/your-feature-name- Strict mode enabled
- No
anytypes without justification - Export interfaces for public APIs
- JSDoc comments for functions and interfaces
// Hooks: use{PascalCase}
export function useWebVitals(options?: WebVitalsOptions) { }
export function useLCP(options?: LCPOptions) { }
// Interfaces: {Name}{Descriptor}
export interface WebVitalsOptions { }
export interface WebVitalsState { }
// Types: {Name}{Type}
export type NavigationType = 'navigate' | 'reload' | ...
// Internal functions: camelCase with leading underscore
const _calculateRating = (value: number) => { }src/
├── feature/
│ ├── index.ts # Re-exports
│ ├── hook.ts # Implementation
│ └── performance.ts # Shared utilities
└── index.ts # Main entry point
// Comments
// 1. Document the "why", not the "what"
// ❌ Bad: Increment counter
i++
// ✅ Good: Reset measurement after LCP is finalized
hasWarnedRef.current = true
// Documentation
/**
* useWebVitals
*
* Tracks Core Web Vitals metrics.
*
* @example
* ```tsx
* const vitals = useWebVitals({
* onLCP: (metric) => console.log(metric.value)
* })
* ```
*/
// Imports
import { useEffect, useState } from 'react' // React first
import { onLCP } from 'web-vitals' // Then dependencies
import type { LCPOptions } from './types' // Then types
// Organization
// 1. Interfaces and types
// 2. Constants
// 3. Main function
// 4. Helper functions
// 5. Exportsimport { describe, it, expect, beforeEach, afterEach } from 'vitest'
import { renderHook, act } from '@testing-library/react'
import { useWebVitals } from './useWebVitals'
describe('useWebVitals', () => {
it('tracks LCP metric', () => {
const onLCP = vi.fn()
const { result } = renderHook(() =>
useWebVitals({ onLCP })
)
expect(result.current.lcp).toBeNull()
// Simulate metric
expect(onLCP).toHaveBeenCalled()
})
it('formats metric value correctly', () => {
const { result } = renderHook(() => useWebVitals())
expect(result.current.lcp).toBeOfType('number')
})
})# Watch mode
pnpm test
# Single run
pnpm test:ci
# With coverage
pnpm test -- --coverage- Aim for >80% coverage
- Test happy paths and edge cases
- Mock browser APIs appropriately
- Test error handling
Update README.md if you:
- Add a new hook (add to Hooks section)
- Change API (update Examples section)
- Fix bugs (mention in Known Issues if relevant)
All public APIs must have JSDoc:
/**
* useWebVitals
*
* Tracks all Core Web Vitals metrics in real-time.
* Implements web.dev best practices exactly.
*
* @param options - Hook configuration
* @returns Current metrics state and loading status
*
* @example
* ```tsx
* const vitals = useWebVitals({
* onLCP: (metric) => console.log('LCP:', metric.value),
* reportAllChanges: true
* })
* ```
*
* @see https://web.dev/vitals/
*/
export function useWebVitals(options?: WebVitalsOptions): WebVitalsStateUpdate CHANGELOG.md with your changes under [Unreleased]:
## [Unreleased]
### Added
- `useCLS` hook for Cumulative Layout Shift tracking
### Fixed
- LCP threshold warning logic
### Changed
- Improved error messagesWhen adding features, consider:
-
Bundle Size
- New code should be minimal
- Use tree-shaking (
"sideEffects": false) - Test with
pnpm size
-
Runtime Performance
- Hooks should have minimal overhead
- Use refs to avoid unnecessary renders
- Avoid expensive calculations in render
-
Memory Usage
- Clean up observers and listeners
- Use weak refs where possible
- Test for memory leaks
-
Automated Checks
- TypeScript compilation (
pnpm type-check) - Tests pass (
pnpm test:ci) - Bundle size within limits (
pnpm size)
- TypeScript compilation (
-
Code Review
- Code follows standards
- Changes are well-documented
- No breaking changes (unless major version)
-
Approval
- At least one maintainer approval
- All conversations resolved
- CI passing
Follow Conventional Commits:
<type>(<scope>): <subject>
<body>
<footer>
Types:
feat:New featurefix:Bug fixdocs:Documentationtest:Testschore:Build, deps, etc.perf:Performance improvement
Examples:
feat(web-vitals): add useCLS hook for layout shift tracking
fix(lcp): correct threshold comparison logic
docs(readme): add Next.js integration example
perf: reduce bundle size by 15%
- Create feature directory:
src/features/newFeature/ - Add files:
types.ts- Interfaces and typeshook.ts- Implementationindex.ts- Exports
- Add tests in
hook.test.ts - Update main
src/index.tsto export - Update
tsup.config.tsif new entry point needed - Update
.size-limit.jsonwith new hook size limits - Document in README.md
- Add to CHANGELOG.md
- Write a test that reproduces the bug
- Fix the bug
- Verify test passes
- Update documentation if needed
- Note in CHANGELOG.md
- Measure current performance:
pnpm size - Make changes
- Verify improvement:
pnpm size - Update CHANGELOG.md with results
- Test with new version
- Update package.json
- Run
pnpm install - Run full test suite:
pnpm test:ci - Update CHANGELOG.md
- Questions? Start a discussion
- Bug reports? Open an issue
- Need guidance? Comment on existing PR/issue
Contributors are recognized in:
package.jsoncontributors field- Release notes
- GitHub contributors list
By contributing, you agree that your contributions will be licensed under the MIT License.
Feel free to ask! We're here to help you contribute successfully.
Thank you for contributing to @page-speed/hooks! 🚀