|
| 1 | +# Contributing to npmx.dev |
| 2 | + |
| 3 | +Thank you for your interest in contributing! ❤️ This document provides guidelines and instructions for contributing. |
| 4 | + |
| 5 | +> [!IMPORTANT] |
| 6 | +> Please be respectful and constructive in all interactions. We aim to maintain a welcoming environment for all contributors. |
| 7 | +> [👉 Read more](./CODE_OF_CONDUCT.md) |
| 8 | +
|
| 9 | +## Goals |
| 10 | + |
| 11 | +We want to create 'a fast, modern browser for the npm registry for power users.' This means, among other things: |
| 12 | + |
| 13 | +- We don't aim to replace the [npmjs.com](https://www.npmjs.com/) registry, just provide a better UI and DX. |
| 14 | +- Layout shift, flakiness, slowness is The Worst. We need to continually iterate to create the most performant, best DX for power users. |
| 15 | +- We want to provide information in the best way. We don't want noise, cluttered display, or confusing UI. If in doubt: choose simplicity. |
| 16 | + |
| 17 | +## Getting started |
| 18 | + |
| 19 | +### Prerequisites |
| 20 | + |
| 21 | +- [Node.js](https://nodejs.org/) (LTS version recommended) |
| 22 | +- [pnpm](https://pnpm.io/) v10.28.1 or later |
| 23 | + |
| 24 | +### Setup |
| 25 | + |
| 26 | +1. fork and clone the repository |
| 27 | +2. install dependencies: |
| 28 | + |
| 29 | + ```bash |
| 30 | + pnpm install |
| 31 | + ``` |
| 32 | + |
| 33 | +3. start the development server: |
| 34 | + |
| 35 | + ```bash |
| 36 | + pnpm dev |
| 37 | + ``` |
| 38 | + |
| 39 | +4. (optional) if you want to test the admin UI/flow, you can run the local connector: |
| 40 | + |
| 41 | + ```bash |
| 42 | + pnpm npmx-connector |
| 43 | + ``` |
| 44 | + |
| 45 | +## Development workflow |
| 46 | + |
| 47 | +### Available commands |
| 48 | + |
| 49 | +```bash |
| 50 | +# Development |
| 51 | +pnpm dev # Start development server |
| 52 | +pnpm build # Production build |
| 53 | +pnpm preview # Preview production build |
| 54 | + |
| 55 | +# Code Quality |
| 56 | +pnpm lint # Run linter (oxlint + oxfmt) |
| 57 | +pnpm lint:fix # Auto-fix lint issues |
| 58 | +pnpm test:types # TypeScript type checking |
| 59 | + |
| 60 | +# Testing |
| 61 | +pnpm test # Run all Vitest tests |
| 62 | +pnpm test:unit # Unit tests only |
| 63 | +pnpm test:nuxt # Nuxt component tests |
| 64 | +pnpm test:browser # Playwright E2E tests |
| 65 | +``` |
| 66 | + |
| 67 | +### Project structure |
| 68 | + |
| 69 | +``` |
| 70 | +app/ # Nuxt 4 app directory |
| 71 | +├── components/ # Vue components (PascalCase.vue) |
| 72 | +├── composables/ # Vue composables (useFeature.ts) |
| 73 | +├── pages/ # File-based routing |
| 74 | +├── plugins/ # Nuxt plugins |
| 75 | +├── app.vue # Root component |
| 76 | +└── error.vue # Error page |
| 77 | +
|
| 78 | +server/ # Nitro server |
| 79 | +├── api/ # API routes |
| 80 | +└── utils/ # Server utilities |
| 81 | +
|
| 82 | +shared/ # Shared between app and server |
| 83 | +└── types/ # TypeScript type definitions |
| 84 | +
|
| 85 | +cli/ # Local connector CLI (separate workspace) |
| 86 | +test/ # Vitest tests |
| 87 | +├── unit/ # Unit tests (*.spec.ts) |
| 88 | +└── nuxt/ # Nuxt component tests |
| 89 | +tests/ # Playwright E2E tests |
| 90 | +``` |
| 91 | + |
| 92 | +> [!TIP] |
| 93 | +> For more about the meaning of these directories, check out the docs on the [Nuxt directory structure](https://nuxt.com/docs/4.x/directory-structure). |
| 94 | +
|
| 95 | +## Code style |
| 96 | + |
| 97 | +### Typescript |
| 98 | + |
| 99 | +- We care about good types – never cast things to `any` 💪 |
| 100 | +- Validate rather than just assert |
| 101 | + |
| 102 | +### Import order |
| 103 | + |
| 104 | +1. Type imports first (`import type { ... }`) |
| 105 | +2. External packages |
| 106 | +3. Internal aliases (`#shared/types`, `#server/`, etc.) |
| 107 | +4. No blank lines between groups |
| 108 | + |
| 109 | +```typescript |
| 110 | +import type { Packument, NpmSearchResponse } from '#shared/types' |
| 111 | +import type { Tokens } from 'marked' |
| 112 | +import { marked } from 'marked' |
| 113 | +import { hasProtocol } from 'ufo' |
| 114 | +``` |
| 115 | + |
| 116 | +### Naming conventions |
| 117 | + |
| 118 | +| Type | Convention | Example | |
| 119 | +| ---------------- | ------------------------ | ------------------------------ | |
| 120 | +| Vue components | PascalCase | `MarkdownText.vue` | |
| 121 | +| Pages | kebab-case | `search.vue`, `[...name].vue` | |
| 122 | +| Composables | camelCase + `use` prefix | `useNpmRegistry.ts` | |
| 123 | +| Server routes | kebab-case + method | `search.get.ts` | |
| 124 | +| Functions | camelCase | `fetchPackage`, `formatDate` | |
| 125 | +| Constants | SCREAMING_SNAKE_CASE | `NPM_REGISTRY`, `ALLOWED_TAGS` | |
| 126 | +| Types/Interfaces | PascalCase | `NpmSearchResponse` | |
| 127 | + |
| 128 | +### Vue components |
| 129 | + |
| 130 | +- Use Composition API with `<script setup lang="ts">` |
| 131 | +- Define props with TypeScript: `defineProps<{ text: string }>()` |
| 132 | +- Keep functions under 50 lines |
| 133 | +- Accessibility is a first-class consideration – always consider ARIA attributes and keyboard navigation |
| 134 | + |
| 135 | +```vue |
| 136 | +<script setup lang="ts"> |
| 137 | +import type { PackumentVersion } from '#shared/types' |
| 138 | +
|
| 139 | +const props = defineProps<{ |
| 140 | + version: PackumentVersion |
| 141 | +}>() |
| 142 | +</script> |
| 143 | +``` |
| 144 | + |
| 145 | +Ideally, extract utilities into separate files so they can be unit tested. 🙏 |
| 146 | + |
| 147 | +## Testing |
| 148 | + |
| 149 | +### Unit tests |
| 150 | + |
| 151 | +Write unit tests for core functionality using Vitest: |
| 152 | + |
| 153 | +```typescript |
| 154 | +import { describe, it, expect } from 'vitest' |
| 155 | + |
| 156 | +describe('featureName', () => { |
| 157 | + it('should handle expected case', () => { |
| 158 | + expect(result).toBe(expected) |
| 159 | + }) |
| 160 | +}) |
| 161 | +``` |
| 162 | + |
| 163 | +> [!TIP] |
| 164 | +> If you need access to the Nuxt context in your unit or component test, place your test in the `test/nuxt/` directory and run with `pnpm test:nuxt` |
| 165 | +
|
| 166 | +### E2e tests |
| 167 | + |
| 168 | +Write end-to-end tests using Playwright: |
| 169 | + |
| 170 | +```bash |
| 171 | +pnpm test:browser # Run tests |
| 172 | +pnpm test:browser:ui # Run with Playwright UI |
| 173 | +``` |
| 174 | + |
| 175 | +Make sure to read about [Playwright best practices](https://playwright.dev/docs/best-practices) and don't rely on classes/IDs but try to follow user-replicable behaviour (like selecting an element based on text content instead). |
| 176 | + |
| 177 | +## Submitting changes |
| 178 | + |
| 179 | +### Before submitting |
| 180 | + |
| 181 | +1. Ensure your code follows the style guidelines |
| 182 | +2. Run linting: `pnpm lint:fix` |
| 183 | +3. Run type checking: `pnpm test:types` |
| 184 | +4. Run tests: `pnpm test` |
| 185 | +5. Write or update tests for your changes |
| 186 | + |
| 187 | +### Pull request process |
| 188 | + |
| 189 | +1. Create a feature branch from `main` |
| 190 | +2. Make your changes with clear, descriptive commits |
| 191 | +3. Push your branch and open a pull request |
| 192 | +4. Ensure CI checks pass (lint, type check, tests) |
| 193 | +5. Request review from maintainers |
| 194 | + |
| 195 | +### Commit messages |
| 196 | + |
| 197 | +Write clear, concise commit messages that explain the "why" behind changes: |
| 198 | + |
| 199 | +- `fix: resolve search pagination issue` |
| 200 | +- `feat: add package version comparison` |
| 201 | +- `docs: update installation instructions` |
| 202 | + |
| 203 | +## Pre-commit hooks |
| 204 | + |
| 205 | +The project uses `lint-staged` with `simple-git-hooks` to automatically lint files on commit. |
| 206 | + |
| 207 | +## Using AI |
| 208 | + |
| 209 | +You're welcome to use AI tools to help you contribute. But there are two important ground rules: |
| 210 | + |
| 211 | +### 1. Never let an LLM speak for you |
| 212 | + |
| 213 | +When you write a comment, issue, or PR description, use your own words. Grammar and spelling don't matter – real connection does. AI-generated summaries tend to be long-winded, dense, and often inaccurate. Simplicity is an art. The goal is not to sound impressive, but to communicate clearly. |
| 214 | + |
| 215 | +### 2. Never let an LLM think for you |
| 216 | + |
| 217 | +Feel free to use AI to write code, tests, or point you in the right direction. But always understand what it's written before contributing it. Take personal responsibility for your contributions. Don't say "ChatGPT says..." – tell us what _you_ think. |
| 218 | + |
| 219 | +For more context, see [Using AI in open source](https://roe.dev/blog/using-ai-in-open-source). |
| 220 | + |
| 221 | +## Questions? |
| 222 | + |
| 223 | +If you have questions or need help, feel free to open an issue for discussion or join our [Discord server](https://chat.npmx.dev). |
| 224 | + |
| 225 | +## License |
| 226 | + |
| 227 | +By contributing to npmx.dev, you agree that your contributions will be licensed under the [MIT License](LICENSE). |
0 commit comments