|
| 1 | +# CLAUDE.md |
| 2 | + |
| 3 | +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. |
| 4 | + |
| 5 | +## Project Overview |
| 6 | + |
| 7 | +Next.js for Drupal is a monorepo providing a bridge between Next.js applications and Drupal CMS. It consists of: |
| 8 | + |
| 9 | +- **NPM package** (`packages/next-drupal`): TypeScript library for fetching Drupal content via JSON:API |
| 10 | +- **Drupal module** (`modules/next`): Drupal 10/11 module for ISR, draft mode, and revalidation |
| 11 | +- **Examples** and **starters**: Reference implementations |
| 12 | + |
| 13 | +## Development Commands |
| 14 | + |
| 15 | +### Setup |
| 16 | + |
| 17 | +```bash |
| 18 | +yarn install # Install all dependencies |
| 19 | +``` |
| 20 | + |
| 21 | +### Running Workspaces |
| 22 | + |
| 23 | +```bash |
| 24 | +yarn workspace www dev # Run documentation site (next-drupal.org) |
| 25 | +yarn workspace next-drupal dev # Watch mode for next-drupal package |
| 26 | +yarn dev # Run all workspaces in parallel |
| 27 | +yarn dev:starter # Run drupal + basic-starter in parallel |
| 28 | +``` |
| 29 | + |
| 30 | +### Testing |
| 31 | + |
| 32 | +```bash |
| 33 | +yarn test # Run next-drupal Jest tests (requires .env setup) |
| 34 | +yarn test:next # Run Drupal module PHPUnit tests |
| 35 | +yarn test:e2e:ci # Run all Cypress end-to-end tests |
| 36 | +``` |
| 37 | + |
| 38 | +**Note**: Jest tests require environment variables. Copy `.env.example` to `.env` in `packages/next-drupal/`: |
| 39 | + |
| 40 | +```bash |
| 41 | +cp packages/next-drupal/.env.example packages/next-drupal/.env |
| 42 | +``` |
| 43 | + |
| 44 | +### Linting & Formatting |
| 45 | + |
| 46 | +```bash |
| 47 | +yarn lint # ESLint for TypeScript/JavaScript |
| 48 | +yarn format # Prettier formatting |
| 49 | +yarn format:check # Check formatting without writing |
| 50 | +yarn phpcs # PHP CodeSniffer for Drupal module |
| 51 | +``` |
| 52 | + |
| 53 | +### Building |
| 54 | + |
| 55 | +```bash |
| 56 | +yarn workspace next-drupal prepare # Build next-drupal package with tsup |
| 57 | +``` |
| 58 | + |
| 59 | +## Architecture |
| 60 | + |
| 61 | +### Monorepo Structure |
| 62 | + |
| 63 | +- **Turborepo** for build orchestration |
| 64 | +- **Lerna** for versioning and publishing (independent versioning) |
| 65 | +- **Yarn workspaces** for dependency management |
| 66 | + |
| 67 | +### NPM Package (`packages/next-drupal`) |
| 68 | + |
| 69 | +The package has three main class hierarchies: |
| 70 | + |
| 71 | +1. **NextDrupalBase** (`src/next-drupal-base.ts`) |
| 72 | + |
| 73 | + - Base class providing authentication, fetching, and low-level API interactions |
| 74 | + - Handles OAuth token management (client credentials, username/password) |
| 75 | + - Provides `fetch()` wrapper with auth and error handling |
| 76 | + |
| 77 | +2. **NextDrupal** (`src/next-drupal.ts`) extends `NextDrupalBase` |
| 78 | + |
| 79 | + - Main class for JSON:API resource operations |
| 80 | + - Methods: `getResource()`, `getResourceCollection()`, `createResource()`, `updateResource()`, `deleteResource()` |
| 81 | + - Uses Jsona for JSON:API deserialization |
| 82 | + - Works with App Router and Pages Router |
| 83 | + |
| 84 | +3. **NextDrupalPages** (`src/next-drupal-pages.ts`) extends `NextDrupal` |
| 85 | + - Specialized for Next.js Pages Router |
| 86 | + - Provides: `getStaticPathsFromContext()`, `getStaticPropsFromContext()`, `translatePath()` |
| 87 | + - Includes draft mode helpers via `next-drupal/draft` |
| 88 | + |
| 89 | +**Key exports**: |
| 90 | + |
| 91 | +- Main: `NextDrupal`, `NextDrupalPages` |
| 92 | +- Draft mode: `next-drupal/draft` (for API routes) |
| 93 | +- Navigation: `next-drupal/navigation` (menu helpers) |
| 94 | + |
| 95 | +### Drupal Module (`modules/next`) |
| 96 | + |
| 97 | +Core entities and plugins: |
| 98 | + |
| 99 | +- **NextSite** entity: Configures Next.js site endpoints (base URL, preview secret) |
| 100 | +- **NextEntityTypeConfig**: Per-entity-type revalidation configuration |
| 101 | +- **Plugin system**: |
| 102 | + - SiteResolver plugins: Determine which NextSite handles entity revalidation |
| 103 | + - Revalidator plugins: Send revalidation requests to Next.js |
| 104 | +- **Event subscribers**: Trigger revalidation on entity CRUD operations |
| 105 | + |
| 106 | +Dependencies: `decoupled_router`, `simple_oauth`, `subrequests`, `pathauto` |
| 107 | + |
| 108 | +### JSON:API Integration |
| 109 | + |
| 110 | +The package interacts with Drupal's JSON:API using: |
| 111 | + |
| 112 | +- Resource types format: `{entity_type}--{bundle}` (e.g., `node--article`) |
| 113 | +- Jsona library for deserialization |
| 114 | +- Query params via `qs` library (filters, includes, sorts) |
| 115 | + |
| 116 | +## Commit Conventions |
| 117 | + |
| 118 | +This project uses [Conventional Commits](https://www.conventionalcommits.org/): |
| 119 | + |
| 120 | +``` |
| 121 | +<type>(<scope>)<!>: <subject> |
| 122 | +
|
| 123 | +<body> |
| 124 | +
|
| 125 | +<footer> |
| 126 | +``` |
| 127 | + |
| 128 | +**Types**: `feat`, `fix`, `docs`, `style`, `refactor`, `perf`, `test`, `build`, `ci`, `chore`, `revert` |
| 129 | + |
| 130 | +**Scopes**: Package/module names (`next-drupal`, `next`, `basic-starter`, `example-auth`, etc.) |
| 131 | + |
| 132 | +**Breaking changes**: Add `!` after scope and include `BREAKING CHANGE:` in footer |
| 133 | + |
| 134 | +**Examples**: |
| 135 | + |
| 136 | +``` |
| 137 | +feat(next-drupal): add support for Next.js 15 |
| 138 | +
|
| 139 | +fix(next): correct revalidation URL generation |
| 140 | +
|
| 141 | +docs(basic-starter): update environment variables |
| 142 | +``` |
| 143 | + |
| 144 | +## Testing Strategy |
| 145 | + |
| 146 | +### next-drupal Package |
| 147 | + |
| 148 | +- Jest unit tests in `packages/next-drupal/__tests__` |
| 149 | +- Tests run against live Drupal instance (requires environment variables) |
| 150 | +- Mock Next.js context objects for Pages Router tests |
| 151 | + |
| 152 | +### Drupal Module |
| 153 | + |
| 154 | +- PHPUnit tests in `modules/next/tests` |
| 155 | +- Uses `SIMPLETEST_DB=sqlite://localhost/:memory:` |
| 156 | + |
| 157 | +### E2E Tests |
| 158 | + |
| 159 | +- Cypress tests for examples |
| 160 | +- Require local Drupal instance with demo content |
| 161 | + |
| 162 | +## Workspace-Specific Notes |
| 163 | + |
| 164 | +### Examples vs Starters |
| 165 | + |
| 166 | +- **Examples** (`examples/*`): Demonstrate specific features (auth, custom cache, GraphQL, etc.) |
| 167 | +- **Starters** (`starters/*`): Production-ready templates for new projects |
| 168 | +- Each has separate git repos synced via `scripts/sync-repo.sh` |
| 169 | + |
| 170 | +### Documentation Site (`www`) |
| 171 | + |
| 172 | +- Built with Next.js |
| 173 | +- Deployed to Vercel |
| 174 | +- Separate branches for version docs: `v1.6`, `v1`, `v0` |
| 175 | + |
| 176 | +## Common Patterns |
| 177 | + |
| 178 | +### Fetching Drupal Content |
| 179 | + |
| 180 | +```typescript |
| 181 | +import { NextDrupal } from "next-drupal" |
| 182 | + |
| 183 | +const drupal = new NextDrupal(process.env.NEXT_PUBLIC_DRUPAL_BASE_URL) |
| 184 | + |
| 185 | +// Fetch single resource |
| 186 | +const node = await drupal.getResource("node--article", uuid) |
| 187 | + |
| 188 | +// Fetch collection with params |
| 189 | +const articles = await drupal.getResourceCollection("node--article", { |
| 190 | + params: { |
| 191 | + "filter[status]": 1, |
| 192 | + "fields[node--article]": "title,body", |
| 193 | + include: "field_image", |
| 194 | + sort: "-created", |
| 195 | + }, |
| 196 | +}) |
| 197 | +``` |
| 198 | + |
| 199 | +### Pages Router Integration |
| 200 | + |
| 201 | +```typescript |
| 202 | +import { NextDrupalPages } from "next-drupal" |
| 203 | + |
| 204 | +const drupal = new NextDrupalPages(...) |
| 205 | + |
| 206 | +export async function getStaticPaths() { |
| 207 | + return await drupal.getStaticPathsFromContext("node--article", context) |
| 208 | +} |
| 209 | + |
| 210 | +export async function getStaticProps(context) { |
| 211 | + const resource = await drupal.getResourceFromContext("node--article", context) |
| 212 | + return { props: { resource } } |
| 213 | +} |
| 214 | +``` |
| 215 | + |
| 216 | +## Release Process |
| 217 | + |
| 218 | +Managed via Lerna and semantic versioning. Maintainers use: |
| 219 | + |
| 220 | +- `npx lerna version --no-push` to tag releases |
| 221 | +- `npx lerna publish from-git` to publish to npm |
| 222 | +- `yarn sync:modules` to sync Drupal module to drupal.org |
| 223 | +- `yarn sync:starters:release` to sync starters to separate repos |
| 224 | + |
| 225 | +Alpha/beta releases use `--conventional-prerelease` and publish with `--dist-tag canary`. |
0 commit comments