|
| 1 | +# PostHog JS SDK Development Guide |
| 2 | + |
| 3 | +## Overview |
| 4 | + |
| 5 | +This is a pnpm monorepo containing multiple PostHog JavaScript SDKs and development tooling. The repository uses Turbo for build orchestration and supports local development through tarball-based testing. |
| 6 | + |
| 7 | +**Key Information:** |
| 8 | + |
| 9 | +- Node Version: `v22.17.1` (see `.nvmrc`) |
| 10 | +- Package Manager: `[email protected]` |
| 11 | +- TypeScript Version: `5.8.2` |
| 12 | +- Main Branch: `main` |
| 13 | + |
| 14 | +## Folder Structure |
| 15 | + |
| 16 | +- `./packages` - All JS SDKs that are distributed as npm packages (9 packages) |
| 17 | +- `./playground` - Projects to test packages locally during development |
| 18 | +- `./examples` - Simple example projects demonstrating how to install and use our SDKs |
| 19 | +- `./target` - Generated tarballs for SDK packages (created by `pnpm package`) |
| 20 | +- `./tooling` - Shared development packages (ESLint plugin, Rollup utils, TSConfig base) |
| 21 | +- `./.github` - CI/CD workflows and custom GitHub Actions |
| 22 | + |
| 23 | +## SDK Packages |
| 24 | + |
| 25 | +The repository contains the following SDK packages in `./packages/`: |
| 26 | + |
| 27 | +| Package | Name | Description | |
| 28 | +| ---------------- | ------------------------ | ----------------------------------------------- | |
| 29 | +| `browser/` | `posthog-js` | Main browser SDK for capturing events and usage | |
| 30 | +| `web/` | `posthog-js-lite` | Lightweight browser SDK | |
| 31 | +| `core/` | `@posthog/core` | Shared core functionality used by multiple SDKs | |
| 32 | +| `node/` | `posthog-node` | Node.js backend SDK (requires Node >= 20) | |
| 33 | +| `react/` | `@posthog/react` | React components and hooks | |
| 34 | +| `react-native/` | `posthog-react-native` | React Native mobile SDK | |
| 35 | +| `nuxt/` | `@posthog/nuxt` | Nuxt framework module | |
| 36 | +| `nextjs-config/` | `@posthog/nextjs-config` | Next.js configuration helper | |
| 37 | +| `ai/` | `@posthog/ai` | AI integrations for Node.js | |
| 38 | + |
| 39 | +## Workspace |
| 40 | + |
| 41 | +- This repository is structured as a pnpm workspace and each SDK and tooling package is a member of this global workspace. |
| 42 | +- Example and playground projects are independent pnpm workspaces. You can install their dependencies by running `pnpm install` inside the specific project folder. All dependencies and sub-dependencies to PostHog SDKs will be overwritten using a pnpmfile. |
| 43 | + |
| 44 | +## Environment Setup |
| 45 | + |
| 46 | +```bash |
| 47 | +# Use the correct Node version |
| 48 | +nvm use |
| 49 | + |
| 50 | +# Install all workspace dependencies |
| 51 | +pnpm install |
| 52 | +``` |
| 53 | + |
| 54 | +## Commands |
| 55 | + |
| 56 | +### Root-Level Scripts |
| 57 | + |
| 58 | +Run these from the repository root: |
| 59 | + |
| 60 | +```bash |
| 61 | +# Build all packages (respects dependency order) |
| 62 | +pnpm build |
| 63 | + |
| 64 | +# Watch mode for development |
| 65 | +pnpm dev |
| 66 | + |
| 67 | +# Run all tests across packages |
| 68 | +pnpm test |
| 69 | + |
| 70 | +# Run unit tests only |
| 71 | +pnpm test:unit |
| 72 | + |
| 73 | +# Lint all packages |
| 74 | +pnpm lint |
| 75 | + |
| 76 | +# Auto-fix linting issues |
| 77 | +pnpm lint:fix |
| 78 | + |
| 79 | +# Create tarballs for all packages |
| 80 | +pnpm package |
| 81 | + |
| 82 | +# Watch mode - auto-regenerate tarballs on changes |
| 83 | +pnpm package:watch |
| 84 | + |
| 85 | +# Generate API reference documentation |
| 86 | +pnpm generate-references |
| 87 | + |
| 88 | +# Clean all build artifacts |
| 89 | +pnpm clean |
| 90 | + |
| 91 | +# Clean all node_modules (workspace-wide) |
| 92 | +pnpm clean:dep |
| 93 | +``` |
| 94 | + |
| 95 | +### Package Scripts |
| 96 | + |
| 97 | +All SDK packages have the following scripts: |
| 98 | + |
| 99 | +- `clean` - Remove build artifacts |
| 100 | +- `lint` - Lint all files for this package |
| 101 | +- `lint:fix` - Fix linting issues |
| 102 | +- `build` - Transpile, minify and/or bundle source code from ./src to ./dist |
| 103 | +- `dev` - Build and watch for changes |
| 104 | +- `test:unit` - Run unit tests |
| 105 | +- `test:functional` - Run functional/integration tests (if applicable) |
| 106 | +- `package` - Create a tarball of this package that can be installed inside an example or playground project |
| 107 | + |
| 108 | +### Using Turbo to Target Specific Packages |
| 109 | + |
| 110 | +You can run commands using the `turbo` CLI and target specific packages. Useful examples: |
| 111 | + |
| 112 | +```bash |
| 113 | +# Create tarballs for all packages |
| 114 | +pnpm turbo package |
| 115 | + |
| 116 | +# Run unit tests for posthog-js only |
| 117 | +pnpm turbo --filter=posthog-js test:unit |
| 118 | + |
| 119 | +# Build posthog-react-native and its dependencies |
| 120 | +pnpm turbo --filter=posthog-react-native build |
| 121 | + |
| 122 | +# Lint a specific package |
| 123 | +pnpm turbo --filter=@posthog/react lint:fix |
| 124 | +``` |
| 125 | + |
| 126 | +## Running an Example or Playground Project with Local Changes |
| 127 | + |
| 128 | +The recommended workflow for testing local changes uses tarballs, which most realistically simulates how packages are installed from npm: |
| 129 | + |
| 130 | +### One-Time Setup |
| 131 | + |
| 132 | +1. Run `pnpm turbo package` inside the root folder to generate tarballs in `./target` |
| 133 | +2. Navigate to the example/playground project: `cd examples/example-nextjs` |
| 134 | +3. Run `pnpm install` (remove `pnpm-lock.yaml` if it exists) to install local tarballs |
| 135 | +4. Run `pnpm dev` or `pnpm start` to start the project |
| 136 | + |
| 137 | +### Development Workflow (Recommended) |
| 138 | + |
| 139 | +1. **Terminal 1** (root): Run `pnpm package:watch` - auto-regenerates tarballs on changes |
| 140 | +2. **Terminal 2** (example project): Navigate to example folder |
| 141 | +3. Make changes to SDK source code - tarballs update automatically |
| 142 | +4. Re-run `pnpm install` in the example project to pick up new tarballs |
| 143 | +5. Restart the example project |
| 144 | + |
| 145 | +## Build Configuration |
| 146 | + |
| 147 | +Turbo handles build orchestration and ensures packages are built in the correct dependency order. |
| 148 | + |
| 149 | +## Code Style and Linting |
| 150 | + |
| 151 | +### ESLint |
| 152 | + |
| 153 | +- Custom `eslint-plugin-posthog-js` for repository-specific rules |
| 154 | +- TypeScript support |
| 155 | +- React support |
| 156 | +- Prettier integration |
| 157 | + |
| 158 | +### Automatic Formatting |
| 159 | + |
| 160 | +Pre-commit hooks (via lint-staged) automatically format code on commit: |
| 161 | + |
| 162 | +- TypeScript/JavaScript files: ESLint + Prettier |
| 163 | +- JSON/Markdown files: Prettier |
| 164 | + |
| 165 | +## Release Process |
| 166 | + |
| 167 | +This repository uses [Changesets](https://github.com/changesets/changesets) for version management and publishing. |
| 168 | + |
| 169 | +### Creating a Changeset |
| 170 | + |
| 171 | +Before submitting a PR with changes that should be released: |
| 172 | + |
| 173 | +```bash |
| 174 | +# Interactive CLI to create a changeset |
| 175 | +pnpm changeset |
| 176 | +``` |
| 177 | + |
| 178 | +This will: |
| 179 | + |
| 180 | +1. Prompt you to select which packages are affected |
| 181 | +2. Ask for the version bump type (major/minor/patch) |
| 182 | +3. Request a description of the change |
| 183 | +4. Create a file in `.changesets/` directory |
| 184 | + |
| 185 | +### Publishing |
| 186 | + |
| 187 | +1. Add the `release` label to your PR |
| 188 | +2. When the PR is merged to `main`, the `release.yml` GitHub Action will: |
| 189 | + - Update package versions |
| 190 | + - Update CHANGELOG files |
| 191 | + - Publish to npm |
| 192 | + - Create GitHub releases |
| 193 | + |
| 194 | +## CI/CD |
| 195 | + |
| 196 | +### Key GitHub Actions Workflows |
| 197 | + |
| 198 | +| Workflow | Purpose | Trigger | |
| 199 | +| ------------------------- | ------------------------------------------ | ----------------- | |
| 200 | +| `library-ci.yml` | Main testing pipeline (unit + E2E tests) | PR + Push to main | |
| 201 | +| `release.yml` | Publishes to npm and creates releases | Push to main | |
| 202 | +| `integration.yml` | Playwright tests across browsers | PR | |
| 203 | +| `lint-pr.yml` | Validates PR titles (Conventional Commits) | PR events | |
| 204 | +| `es-check.yml` | Validates ES5/ES6 bundle compatibility | PR | |
| 205 | +| `bundled-size.yaml` | Monitors bundle size changes | PR | |
| 206 | +| `generate-references.yml` | Generates API documentation | Push to main | |
| 207 | + |
| 208 | +### PR Requirements |
| 209 | + |
| 210 | +- PR titles must follow [Conventional Commits](https://www.conventionalcommits.org/) format |
| 211 | +- Examples: `feat:`, `fix:`, `chore:`, `docs:` |
| 212 | +- Validated by `lint-pr.yml` workflow |
| 213 | + |
| 214 | +## Important Files for Agents |
| 215 | + |
| 216 | +### Configuration Files |
| 217 | + |
| 218 | +- `package.json` - Root workspace scripts and dependencies |
| 219 | +- `pnpm-workspace.yaml` - Workspace definition and version catalogs |
| 220 | +- `turbo.json` - Build orchestration and task caching |
| 221 | +- `.nvmrc` - Node version specification |
| 222 | +- `.eslintrc.cjs` - ESLint configuration |
| 223 | +- `.prettierrc` - Code formatting rules |
| 224 | + |
| 225 | +### Documentation |
| 226 | + |
| 227 | +- `CONTRIBUTING.md` - Contribution guidelines |
| 228 | +- `AGENTS.md` - This file - agent development guide |
| 229 | +- `RELEASING.md` - Detailed release process |
| 230 | +- `README.md` - Project overview |
| 231 | + |
| 232 | +## Troubleshooting |
| 233 | + |
| 234 | +### Build Issues |
| 235 | + |
| 236 | +```bash |
| 237 | +# Clean all build artifacts |
| 238 | +pnpm clean |
| 239 | + |
| 240 | +# Clean all node_modules |
| 241 | +pnpm clean:dep |
| 242 | + |
| 243 | +# Reinstall dependencies |
| 244 | +pnpm install |
| 245 | + |
| 246 | +# Rebuild everything |
| 247 | +pnpm build |
| 248 | +``` |
| 249 | + |
| 250 | +### Tarball Issues |
| 251 | + |
| 252 | +```bash |
| 253 | +# Regenerate all tarballs |
| 254 | +pnpm package |
| 255 | + |
| 256 | +# In example project, force reinstall |
| 257 | +rm -rf node_modules pnpm-lock.yaml |
| 258 | +pnpm install |
| 259 | +``` |
| 260 | + |
| 261 | +### Test Failures |
| 262 | + |
| 263 | +```bash |
| 264 | +# Run tests with verbose output |
| 265 | +pnpm turbo --filter=<package-name> test:unit -- --verbose |
| 266 | + |
| 267 | +# Update snapshots if needed |
| 268 | +pnpm turbo --filter=<package-name> test:unit -- -u |
| 269 | +``` |
| 270 | + |
| 271 | +## Additional Resources |
| 272 | + |
| 273 | +- [PostHog Documentation](https://posthog.com/docs) |
| 274 | +- [Contributing Guide](./CONTRIBUTING.md) |
| 275 | +- [Release Process](./RELEASING.md) |
| 276 | +- [Issue Tracker](https://github.com/PostHog/posthog-js/issues) |
0 commit comments