This guide covers day-to-day development workflows, debugging techniques, and practical tips for working on DevPockit.
- Local Development Setup
- Development Workflow
- Common Development Tasks
- Adding a New Tool
- Debugging
- Code Style Guide
- Testing Guide
- Troubleshooting
-
Clone and Install:
git clone https://github.com/hypkey/devpockit.git cd devpockit pnpm install -
Start Development Server:
pnpm dev
The app will be available at
http://localhost:3000 -
HTTPS Development (optional):
pnpm dev:https
Uses self-signed certificates from
certificates/directory
# Development
pnpm dev # Start dev server (port 3000)
pnpm dev:https # Start with HTTPS
# Code Quality
pnpm lint # Run ESLint
pnpm lint:fix # Fix ESLint issues
pnpm type-check # TypeScript type checking
pnpm format # Format with Prettier
# Testing
pnpm test # Run tests
pnpm test:watch # Watch mode
pnpm test:coverage # Coverage report
# Building
pnpm build # Production build
pnpm start # Start production server
pnpm export # Static export (for GitHub Pages)
# Verification
pnpm build:test # Full test suite before build
pnpm build:verify # Verify build outputEnvironment variables are optional for local development. If needed:
# .env.local
NEXT_PUBLIC_APP_NAME=DevPockit
NEXT_PUBLIC_APP_VERSION=0.1.0-
Start Development Server:
pnpm dev
-
Make Changes: Edit files in
src/ -
Hot Reload: Changes automatically reload in browser
-
Check Code Quality:
pnpm lint pnpm type-check
-
Run Tests (if applicable):
pnpm test:watch
-
Build Verification (before committing):
pnpm build:test
- Next.js: Hot Module Replacement (HMR) enabled by default
- TypeScript: Type checking in editor and on build
- ESLint: Real-time linting in editor (if configured)
Recommended VS Code extensions:
- ESLint
- Prettier
- TypeScript and JavaScript Language Features
- Tailwind CSS IntelliSense
# Production dependency
pnpm add package-name
# Development dependency
pnpm add -D package-name
# Update lockfile
pnpm install# Update all dependencies
pnpm update
# Update specific package
pnpm update package-name
# Check for outdated packages
pnpm outdatednpx shadcn-ui@latest add button
npx shadcn-ui@latest add card
# Components added to src/components/ui/-
Create file in
src/hooks/:// src/hooks/useYourHook.ts import { useState, useEffect } from 'react'; export function useYourHook() { const [state, setState] = useState(); // Hook logic return { state }; }
-
Export from
src/hooks/index.ts(if using barrel exports)
Edit src/app/globals.css:
- Tailwind directives
- CSS variables for theming
- Global styles
Follow the Tool Implementation Pattern from the architecture docs.
// src/libs/your-tool.ts
export function processYourTool(input: string, options: ToolOptions): string {
// Pure function implementation
// No React dependencies
return result;
}Testing the Logic:
// __tests__/libs/your-tool.test.ts
import { processYourTool } from '@/libs/your-tool';
describe('processYourTool', () => {
it('should process input correctly', () => {
const result = processYourTool('input', {});
expect(result).toBe('expected');
});
});// src/config/your-tool-config.ts
export const YOUR_TOOL_OPTIONS = {
option1: true,
option2: 'default',
};
export const YOUR_TOOL_EXAMPLES = {
example1: 'sample input',
example2: 'another sample',
};// src/components/tools/YourTool.tsx
'use client';
import { useState } from 'react';
import { processYourTool } from '@/libs/your-tool';
import { YOUR_TOOL_OPTIONS, YOUR_TOOL_EXAMPLES } from '@/config/your-tool-config';
export function YourTool() {
const [input, setInput] = useState('');
const [output, setOutput] = useState('');
const [options, setOptions] = useState(YOUR_TOOL_OPTIONS);
const handleProcess = () => {
try {
const result = processYourTool(input, options);
setOutput(result);
} catch (error) {
// Error handling
}
};
return (
<div className="space-y-4">
{/* Input section */}
{/* Options section */}
{/* Output section */}
</div>
);
}Add to src/libs/tools-data.ts:
{
id: 'your-tool',
name: 'Your Tool',
description: 'Tool description',
category: 'utilities', // or appropriate category
icon: '🔧',
isPopular: false,
path: '/tools/utilities/your-tool',
component: 'YourTool',
supportsDesktop: true,
supportsMobile: true,
}Add to src/libs/tool-components.ts:
'YourTool': () => import('@/components/tools/YourTool').then(m => m.YourTool),- Start dev server:
pnpm dev - Navigate to
/tools/utilities/your-tool - Test functionality
- Write unit tests
- Add to README.md tools list
- Update CHANGELOG.md
- Add usage examples if needed
- Open DevTools:
F12orCmd+Option+I(Mac) /Ctrl+Shift+I(Windows/Linux) - Console Tab: Check for errors and warnings
- Network Tab: Monitor API calls (if any)
- React DevTools: Install browser extension for React debugging
# Check TypeScript errors
pnpm type-check
# Common fixes:
# - Check import paths (@/ aliases)
# - Verify type definitions
# - Check tsconfig.json paths# See all linting errors
pnpm lint
# Auto-fix what's possible
pnpm lint:fix
# Common issues:
# - Unused variables
# - Missing dependencies in useEffect
# - Console.log statements- Build Errors: Check
next.config.jsconfiguration - Route Errors: Verify file structure matches App Router conventions
- Import Errors: Check path aliases in
tsconfig.json
// Add console.log for debugging
console.log('Component state:', state);
// Use React DevTools Profiler
// Use breakpoints in browser DevTools
// Check component props
console.log('Props:', props);- Check Tool Logic: Test pure functions independently
- Check Component State: Use React DevTools
- Check Configuration: Verify config imports
- Check Routing: Verify tool is registered correctly
// ✅ Good: Explicit types
function formatJson(input: string): string {
return JSON.stringify(JSON.parse(input), null, 2);
}
// ✅ Good: Interface for objects
interface ToolOptions {
minify: boolean;
indent: number;
}
// ⚠️ Acceptable: any when necessary
function processDynamic(data: any): any {
// Use when type is truly unknown
}// ✅ Good: Functional component with hooks
export function ToolComponent() {
const [state, setState] = useState('');
return <div>{state}</div>;
}
// ✅ Good: Props interface
interface ToolProps {
onResult: (result: string) => void;
}
export function Tool({ onResult }: ToolProps) {
// Component
}- Components: PascalCase (
JsonFormatter.tsx) - UI Components: kebab-case (
button.tsx) - Hooks: camelCase (
useMonacoEditor.ts) - Utils/Config: kebab-case (
json-formatter.ts)
// 1. External dependencies
import { useState } from 'react';
import { Button } from '@/components/ui/button';
// 2. Internal absolute imports
import { formatJson } from '@/libs/json-formatter';
// 3. Relative imports
import './styles.css';
// 4. Type imports
import type { ToolResult } from '@/types/tools';// ✅ Good: Explain "why"
// Using Map for O(1) lookup performance
const cache = new Map();
// ✅ Good: JSDoc for public APIs
/**
* Formats JSON with optional minification.
* @param input - JSON string to format
* @param minify - Whether to minify output
*/
export function formatJson(input: string, minify: boolean): string {
// Implementation
}
// ❌ Bad: Explain "what" (obvious from code)
// Set the state to the input value
setState(input);// __tests__/libs/json-formatter.test.ts
import { formatJson } from '@/libs/json-formatter';
describe('formatJson', () => {
it('should format valid JSON', () => {
const input = '{"name":"test"}';
const result = formatJson(input, false);
expect(result).toContain('"name"');
});
it('should handle invalid JSON', () => {
expect(() => formatJson('invalid', false)).toThrow();
});
});// __tests__/components/tools/JsonFormatter.test.tsx
import { render, screen } from '@testing-library/react';
import { JsonFormatter } from '@/components/tools/JsonFormatter';
describe('JsonFormatter', () => {
it('renders input field', () => {
render(<JsonFormatter />);
expect(screen.getByPlaceholderText(/json/i)).toBeInTheDocument();
});
});# Run all tests
pnpm test
# Watch mode (rerun on changes)
pnpm test:watch
# Coverage report
pnpm test:coverage
# Run specific test file
pnpm test json-formatter.test.ts
# Run tests matching pattern
pnpm test --testNamePattern="format"- Target: 80%+ coverage
- Focus: Test business logic and critical paths
- Report: Generated in
coverage/directory
# Find process using port 3000
lsof -ti:3000
# Kill process
lsof -ti:3000 | xargs kill -9
# Or use different port
PORT=3001 pnpm dev# Clear Next.js cache
rm -rf .next
# Restart TypeScript server (in VS Code: Cmd+Shift+P > "TypeScript: Restart TS Server")
# Verify tsconfig.json paths
pnpm type-check# Clear all caches
rm -rf .next node_modules
# Reinstall dependencies
pnpm install
# Rebuild
pnpm build- Check import path (use
@/aliases) - Verify file exists
- Check
tsconfig.jsonpaths configuration - Restart dev server
# Rebuild Tailwind
pnpm build
# Check Tailwind config
npx tailwindcss --help
# Verify Tailwind is processing
# Check for Tailwind classes in browser DevTools- Check file is saved
- Check for syntax errors (prevents HMR)
- Restart dev server
- Clear browser cache
# Verify static export config
# Check next.config.js has output: 'export'
# Test static build
pnpm build
pnpm serve:build # Serves out/ directory
# Check for dynamic routes (not allowed in static export)- Use Turbopack (if available): Faster builds
- Disable source maps in production builds
- Monitor bundle size: Use
@next/bundle-analyzer
- Tools are automatically code-split (dynamic imports)
- Large dependencies should be lazy-loaded
- Use
React.lazy()for heavy components
- Components use
React.memowhen appropriate - Expensive calculations use
useMemo - Event handlers use
useCallbackwhen needed - Images optimized (if using Next.js Image)
- No unnecessary re-renders
- Keep components small and focused
- Extract reusable logic to hooks
- Separate concerns (logic, config, UI)
- Use TypeScript for type safety
- Create feature branches
- Write descriptive commit messages
- Test before committing
- Keep commits focused and atomic
- Document complex logic
- Add JSDoc to public APIs
- Update README for user-facing changes
- Update CHANGELOG for releases
For more information: