|
1 | | -# Development |
| 1 | +# CoW Protocol Front-End • Contribution Guide |
2 | 2 |
|
3 | | -## Install Dependencies |
| 3 | +Welcome! This document is the canonical set of rules every contributor **and every code assistant** must obey. |
| 4 | +Make sure you follow them for a speedy review. |
| 5 | + |
| 6 | +--- |
| 7 | + |
| 8 | +## 1. Development Quick-Start |
| 9 | + |
| 10 | +### Install dependencies |
4 | 11 |
|
5 | 12 | ```bash |
6 | 13 | yarn install |
7 | 14 | ``` |
8 | 15 |
|
9 | | -## Generate locale files |
| 16 | +### Generate locale files |
10 | 17 |
|
11 | | -``` |
| 18 | +```bash |
12 | 19 | yarn i18n |
13 | 20 | ``` |
14 | 21 |
|
15 | | -## Run the interface |
| 22 | +### Run the interface |
16 | 23 |
|
17 | 24 | ```bash |
18 | 25 | yarn start |
19 | 26 | ``` |
20 | 27 |
|
21 | | -# Contributing |
| 28 | +--- |
| 29 | + |
| 30 | +## 2. Finding a First Issue |
| 31 | + |
| 32 | +Start with issues labeled **Help Wanted**. |
| 33 | + |
| 34 | +--- |
| 35 | + |
| 36 | +## 3. Pull Requests |
| 37 | + |
| 38 | +| Rule | Requirement | |
| 39 | +| -------------- | ---------------------------------------------------------------------------------- | |
| 40 | +| Target branch | Open all PRs against develop | |
| 41 | +| PR size | ≤ ≈400 LOC; chain "waterfall" PRs for larger work | |
| 42 | +| Commit style | Conventional Commits; PR title == squash message | |
| 43 | +| Approvals | Two reviewers (frontend, qa) required | |
| 44 | +| Ownership | Author assigns themselves, tags reviewers, keeps ≤ 3 open PRs, closes stale drafts | |
| 45 | +| CI | All checks must pass before review | |
| 46 | +| Merge Strategy | Squash-merge to develop | |
| 47 | + |
| 48 | +### Additional PR Guidelines |
| 49 | + |
| 50 | +- Start from an issue from the sprint and link it in the PR when possible |
| 51 | +- Every feature should go in a separate branch and pushed on its own PR |
| 52 | +- If there are 2 approvals but some reviewer has pending comments, address them first before merging |
| 53 | +- If your PR is already big and has no major blockers, it's ok to merge the features as they are and address the points raised in a follow up PR |
| 54 | +- Keep PRs short when possible - you want reviewers to understand what you are trying to do |
| 55 | +- For big features, break into smaller chunks and do "waterfall PRs" (pointing the second PR to the first PR's branch, and so on) |
| 56 | +- Include a detailed description of what your PR is about in the summary |
| 57 | +- Use screenshots when relevant |
| 58 | +- Always include testing steps to your PR |
| 59 | +- Make sure your PR builds successfully and keep it up to date with the source branch |
| 60 | + |
| 61 | +--- |
| 62 | + |
| 63 | +## 4. Repository Architecture |
| 64 | + |
| 65 | +**Monorepo Structure Principles:** |
| 66 | + |
| 67 | +- `apps/` - Individual applications (cowswap-frontend, cow-fi, explorer, widget-configurator, etc.) |
| 68 | +- `libs/` - Shared logic and utilities across applications |
| 69 | +- `tools/` - Build and development utilities |
| 70 | +- `testing/` - Integration test helpers |
| 71 | + |
| 72 | +**Within cowswap-frontend:** |
| 73 | + |
| 74 | +- `common/` - Shared utilities and components (MUST NOT depend on `modules/`) |
| 75 | +- `modules/` - Feature-specific code organized by domain |
| 76 | +- `pages/` - React Router page components |
| 77 | +- `api/` - Service layer and API wrappers |
| 78 | +- `types/` - Shared TypeScript type definitions |
| 79 | + |
| 80 | +**Critical Architectural Rule:** The `common/` directory is leaf-only and MUST NOT depend on `modules/`. This ensures clean dependency flow and prevents circular dependencies. |
| 81 | + |
| 82 | +--- |
| 83 | + |
| 84 | +## 5. Code Quality Rules |
| 85 | + |
| 86 | +### TypeScript |
| 87 | + |
| 88 | +- `strictNullChecks`, explicit types everywhere |
| 89 | +- **TYPE EVERYTHING!!!** We prefer to add type definitions for most things in TypeScript |
| 90 | +- Never use `any`; if unavoidable use `unknown` and add `// TODO` - `any` is bad and the linter will usually complain |
| 91 | +- Prefer optional-chaining (`obj?.field`) over `&&` ladders (e.g. use `order?.bridgeDetails` instead of `order && order.bridgeDetails`) |
| 92 | +- Encode variant data as `enum + Record<Enum, T>` so the compiler enforces exhaustiveness - TypeScript will error if you omit an enum key |
| 93 | +- Explicit function return types required (`@typescript-eslint/explicit-function-return-type`) |
| 94 | + |
| 95 | +### React |
| 96 | + |
| 97 | +- Do not declare components inside another component's render |
| 98 | +- Favour composition and named function components |
| 99 | +- Use `const` only when a type annotation is needed |
| 100 | +- Split large components into pure sub-components under `modules/<feature>/pure/` |
| 101 | +- Prefer composition over configuration: split large components into smaller pure subcomponents (e.g. `pure/contents/*`) and compose them instead of adding config props |
22 | 102 |
|
23 | | -Thank you for your interest in contributing to the CoW Swap interface! 🐮 |
| 103 | +### General Code Quality |
24 | 104 |
|
25 | | -## Finding a first issue |
| 105 | +- Shorter functions are better than longer functions |
| 106 | +- Abide by the structure of the respective projects |
| 107 | +- Use Storybook when coding UI in a project that uses Storybook, Cosmos where Cosmos is used |
| 108 | +- Code should be auto-formatted with rules defined in the project (ESLint) |
| 109 | +- You are free to use whatever editor you fancy (VSCode, Intellij, vim, emacs), preferably with format on save (Prettier plugin) |
26 | 110 |
|
27 | | -Start with issues with the label |
28 | | -[`Help wanted`](https://github.com/cowprotocol/cowswap/issues?q=is%3Aopen+is%3Aissue+label%3A%22Help_Wanted%22+). |
| 111 | +**Keep functions small & prevent unnecessary re-renders.** |
29 | 112 |
|
30 | | -## Pull requests |
| 113 | +--- |
31 | 114 |
|
32 | | -**Please open all pull requests against the `develop` branch.** |
33 | | -CI checks will run against all PRs. |
| 115 | +## 6. Performance & Memoisation (React 19) |
34 | 116 |
|
35 | | -<!-- # Translations |
36 | | -TODO: read and re-enable |
37 | | -Help CoW Swap reach a global audience! |
| 117 | +| When to memoise | When not to memoise | |
| 118 | +| ------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | |
| 119 | +| `useMemo` for heavyweight calculations rerunning on every render | Skip for trivial expressions or seldom-run code | |
| 120 | +| `useCallback` only when ref-equality matters (deps of useEffect, props of React.memo) | Don't wrap every callback "just in case" | |
| 121 | +| Wrap largely-static presentational components with React.memo | Avoid memo layers in deep hot trees where the comparison cost outweighs savings | |
38 | 122 |
|
39 | | -CoW Swap uses [Crowdin](https://crowdin.com/project/cowswap) |
40 | | -for managing translations. Whenever a new string is added to the project, |
41 | | -it gets uploaded to Crowdin for translation by [this workflow](./.github/workflows/crowdin.yaml). |
| 123 | +Additional Guidelines: |
42 | 124 |
|
43 | | -You can contribute by joining Crowdin to proofread existing translations [here](https://crowdin.com/project/uniswap-interface/invite?d=93i5n413q403t4g473p443o4c3t2g3s21343u2c3n403l4b3v2735353i4g4k4l4g453j4g4o4j4e4k4b323l4a3h463s4g453q443m4e3t2b303s2a35353l403o443v293e303k4g4n4r4g483i4g4r4j4e4o473i5n4a3t463t4o4) |
| 125 | +- Measure with DevTools/performance APIs before adding memoization |
| 126 | +- Avoid memoizing inline objects/arrays used infrequently |
| 127 | +- Don't preemptively memoize every value or callback—memo itself costs CPU & memory |
| 128 | +- Skip memoization in deeply nested render paths where overhead outweighs benefit |
| 129 | +- Avoid mixing memoization with dynamic patterns the React Compiler may optimize in the future |
44 | 130 |
|
45 | | -Or, ask to join us as a translator in the Discord! |
| 131 | +⚠️ **Antipattern**: Creating a child component inside a parent's render — causes remount, state reset, effect re-fire, focus loss. Always declare subcomponents outside or extract them. |
| 132 | + |
| 133 | +--- |
| 134 | + |
| 135 | +## 7. Styling & Formatting |
| 136 | + |
| 137 | +- ESLint + Prettier must pass; camelCase everywhere |
| 138 | +- Import order: |
| 139 | + 1. Core (react, jotai…) |
| 140 | + 2. External (@cowprotocol/_, @uniswap/_, …) |
| 141 | + 3. Internal absolute aliases (api/, common/, …) |
| 142 | + 4. Relative paths |
| 143 | +- Forbidden imports: |
| 144 | + - `@ethersproject/*` (use shared wrapper) |
| 145 | + - `styled-components` (use the macro variant) |
| 146 | + - `dist/` file paths |
| 147 | + - react-router's `useNavigate` (use common/hooks/useNavigate) |
| 148 | + |
| 149 | +--- |
| 150 | + |
| 151 | +## 8. Testing |
| 152 | + |
| 153 | +- Unit tests / integration tests required when applicable |
| 154 | +- Jest unit tests for logic |
| 155 | +- Storybook stories/Cosmos + interaction tests for every UI component |
| 156 | +- Include integration tests |
| 157 | +- Full CI must be green before review |
| 158 | +- Make sure to TEST YOUR OWN PRs before requesting a review |
| 159 | + |
| 160 | +--- |
| 161 | + |
| 162 | +## 9. Interaction Contract |
| 163 | + |
| 164 | +1. Ask clarifying questions when requirements are ambiguous |
| 165 | +2. Output only ready-to-paste code, using repo-root-relative paths |
| 166 | +3. Keep changes minimal; avoid introducing extra re-renders |
| 167 | +4. Preserve existing patterns and coding standards |
| 168 | +5. Focus on single-responsibility changes |
| 169 | + |
| 170 | +--- |
| 171 | + |
| 172 | +## 10. Development Communication |
| 173 | + |
| 174 | +- Use descriptive commit messages, inline comments, and rich PR descriptions (expected behaviour & QA scope) |
| 175 | +- Plan work up-front to keep each PR scoped to a single feature/fix |
| 176 | + |
| 177 | +- Provide clear context about feature behavior and QA scope |
| 178 | +- If you are stuck on anything, don't hesitate to reach out |
| 179 | + |
| 180 | +--- |
| 181 | + |
| 182 | +--- |
| 183 | + |
| 184 | +<!-- |
| 185 | +## Translations |
| 186 | +TODO: Re-enable when Crowdin flow is restored. |
| 187 | +Help CoW Protocol reach a global audience! See Crowdin workflow in `.github/workflows/crowdin.yaml`. |
46 | 188 | --> |
| 189 | + |
| 190 | +Thank you for helping keep CoW Protocol fast, stable, and enjoyable to hack on! |
| 191 | + |
| 192 | +**Tip:** If you use Cursor or a similar assistant, set up proper rule files using the modern `.cursor/rules/` directory structure: |
| 193 | + |
| 194 | +Create `.cursor/rules/frontend-guidelines.mdc`: |
| 195 | + |
| 196 | +```markdown |
| 197 | +--- |
| 198 | +description: CoW Protocol frontend development guidelines |
| 199 | +globs: ['apps/**', 'libs/**'] |
| 200 | +alwaysApply: true |
| 201 | +--- |
| 202 | + |
| 203 | +# CoW Protocol Frontend Guidelines |
| 204 | + |
| 205 | +Follow ALL rules defined in CONTRIBUTING.md exactly. |
| 206 | + |
| 207 | +@CONTRIBUTING.md |
| 208 | +``` |
| 209 | + |
| 210 | +This ensures both human contributors and AI assistants adhere to consistent coding standards in this repository. |
0 commit comments