Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
201 changes: 62 additions & 139 deletions docs/development/BUILD.md
Original file line number Diff line number Diff line change
@@ -1,191 +1,114 @@
# Build System & Tooling
# Build System & Architecture

This document explains the build system, package manager, and tooling choices for `@react-three/fiber`.

## Table of Contents

- [Package Manager: pnpm](#package-manager-pnpm)
- [Build System: Unbuild](#build-system-unbuild)
- [Migration History](#migration-history)
- [Future Considerations](#future-considerations)
This document explains the build system, package manager, and tooling architecture for `@react-three/fiber`.

---

## Package Manager: pnpm

### Current Setup

We use **pnpm**, providing excellent performance, efficient disk usage, and a strict dependency resolution model that's ideal for monorepos.

**Configuration:** [`pnpm-workspace.yaml`](../pnpm-workspace.yaml)

### Why pnpm?
We use **pnpm** for its performance, strict dependency resolution, and first-class monorepo support.

**Benefits:**
**Configuration:** `pnpm-workspace.yaml`

- ✅ **Superior performance** - Faster installs and more efficient caching than Yarn or npm.
- ✅ **Content-addressable storage** - Saves disk space by sharing dependencies across projects via hard links.
- ✅ **Strict dependency resolution** - Prevents "phantom dependencies" (packages using dependencies they don't explicitly declare).
- ✅ **First-class monorepo support** - Excellent workspace management and filtering capabilities.
- ✅ **Deterministic** - Highly reliable lockfile and installation process.
//\* Why pnpm? -------------------------------------------

**Migration from Yarn:**

- Migrated in early 2026 to improve build stability and CI performance.
- Replaced `.yarnrc.yml` and `yarn.lock` with `pnpm-workspace.yaml` and `pnpm-lock.yaml`.
- Normalized all scripts to use `pnpm` workspace commands.
- **Content-addressable storage** — Saves disk space via hard links
- **Strict resolution** — Prevents phantom dependencies
- **Deterministic** — Reliable lockfile and installation

---

## Build System: Unbuild

### Current Setup

We use **[unbuild](https://github.com/unjs/unbuild)** for building all packages.
We use **[Unbuild](https://github.com/unjs/unbuild)** for building all packages.

**Configuration:** [`packages/fiber/build.config.ts`](../packages/fiber/build.config.ts)
**Configuration:** `packages/fiber/build.config.ts`

### Why Unbuild?
//\* Why Unbuild? ----------------------------------------

Unbuild provides per-entry-point build configuration, which is critical for our THREE.js import strategy.

**Key Features:**
//\* Per-Entry Alias Resolution --------------------------

1. **Per-Entry Alias Resolution** - Each entry point can resolve imports differently:
Each entry point resolves imports differently:

```typescript
// All source files import from #three
import { WebGLRenderer } from '#three'
```typescript
// All source files import from #three
import { WebGLRenderer } from '#three'

// During build, #three resolves differently:
// - Default entry: src/three/index.ts (WebGL + WebGPU)
// - Legacy entry: src/three/legacy.ts (WebGL only)
// - WebGPU entry: src/three/webgpu.ts (WebGPU only)
```

// During build, #three resolves differently:
// - Default entry: src/three/index.ts (WebGL + WebGPU)
// - Legacy entry: src/three/legacy.ts (WebGL only)
// - WebGPU entry: src/three/webgpu.ts (WebGPU only)
```
| Entry | `#three` resolves to | Result |
| :------ | :-------------------- | :------------- |
| Default | `src/three/index.ts` | WebGL + WebGPU |
| Legacy | `src/three/legacy.ts` | WebGL only |
| WebGPU | `src/three/webgpu.ts` | WebGPU only |

2. **Stub Mode for Development** - `unbuild --stub` creates lightweight stubs:
This is configured in `build.config.ts` using a custom Rollup alias plugin.

```javascript
// dist/index.mjs (stub)
import * as module from '../src/index.tsx'
export * from '../src/index.tsx'
export default module.default
```
//\* Stub Mode for Development ---------------------------

This means code changes are reflected immediately without rebuilding.
`unbuild --stub` creates lightweight stubs that redirect to source:

3. **No Shared Chunks** - Each entry is a standalone bundle, preventing the shared chunk issues we had with Preconstruct.
```javascript
// dist/index.mjs (stub)
import * as module from '../src/index.tsx'
export * from '../src/index.tsx'
export default module.default
```

4. **Dual CJS/ESM Support** - Native `.mjs` and `.cjs` outputs that are fully compliant with modern Node.js standards.
Code changes reflect immediately without rebuilding.

### Build Outputs
//\* Build Outputs ---------------------------------------

```
```text
packages/fiber/dist/
├── index.cjs # Default entry (CommonJS)
├── index.mjs # Default entry (ESM)
├── index.cjs # Default (CommonJS)
├── index.mjs # Default (ESM)
├── legacy.cjs # Legacy/WebGL-only (CommonJS)
├── legacy.mjs # Legacy/WebGL-only (ESM)
└── webgpu/
├── index.cjs # WebGPU-only (CommonJS)
└── index.mjs # WebGPU-only (ESM)
```

### Development Workflow

```bash
# Install and stub (automatic)
pnpm install

# Manual stub generation
pnpm stub
# or
pnpm dev
# or
pnpm build --stub
---

# Production build
pnpm build
## Adding a New Entry Point

# Verify bundle integrity
pnpm verify-bundles
```
To add a specialized bundle (e.g., a new rendering backend):

See [DEVELOPMENT](./DEVELOPMENT.md) for detailed development workflows.
1. **Create Entry File** — `src/my-entry.tsx` (export from `./core`, re-export build flags from `#three`)
2. **Create THREE Variant** — `src/three/my-variant.ts` (define included THREE.js exports)
3. **Configure Unbuild** — Add entry to `build.config.ts`
4. **Update exports** — Add sub-path to `package.json` exports field
5. **Audit** — Add to `scripts/verify-bundles.js` and `packages/fiber/tests/bundles.test.ts`

---

## Migration History

### From Jest to Vitest (v10.0.0)

**Date:** Early 2026

**Reason:** Jest had significant overhead in JSDOM environments, especially with React 19 and modern ESM. Vitest provides a faster, native ESM experience with better HMR and developer experience.

**Migration Impact:**

- ✅ **Performance**: Full suite runs ~2x faster.
- ✅ **Native ESM**: No more complex Babel transformations for tests.
- ✅ **React 19 Compatibility**: Simplified `act` synchronization and event simulation in JSDOM.
//\* Jest → Vitest (v10) ---------------------------------

### From Yarn to pnpm (v10.0.0)
Vitest provides faster native ESM testing with better React 19 compatibility.

**Date:** Early 2026
- Full suite runs ~2x faster
- No complex Babel transformations
- Simplified `act` synchronization in JSDOM

**Reason:** pnpm's strictness and efficiency make it the preferred choice for modern React monorepos, especially as we scale with WebGPU and multiple entry points.
//\* Yarn → pnpm (v10) -----------------------------------

### From Preconstruct to Unbuild (v10.0.0)
pnpm's strictness and efficiency make it preferred for modern React monorepos.

**Date:** Late 2025

**Reason:** Preconstruct couldn't support per-entry alias resolution, which is essential for our THREE.js import strategy.

**Migration Impact:**

- ✅ Simpler project structure (no stub folders)
- ✅ Better tree-shaking and bundle optimization
- ✅ Per-entry THREE.js import control
- ✅ Faster development with better stub support
- ✅ More predictable builds

**CI/CD:** This project uses GitHub Actions (`.github/workflows/test.yml`) which has been updated for pnpm and Vitest.

## 🧩 Architecture Details

### How Alias Resolution Works

The key feature of our build system is **per-entry-point alias resolution**. All source files import from `#three`:

```typescript
// src/core/renderer.tsx
import { WebGLRenderer, WebGPURenderer } from '#three'
```

During build, `#three` resolves differently for each entry:

| Entry | `#three` resolves to | Result |
| :---------- | :-------------------- | :------------------ |
| **Default** | `src/three/index.ts` | Both WebGL + WebGPU |
| **Legacy** | `src/three/legacy.ts` | WebGL only |
| **WebGPU** | `src/three/webgpu.ts` | WebGPU only |

This is configured in `packages/fiber/build.config.ts` using a custom Rollup alias plugin.

---

## 🆕 Adding a New Entry Point

If you need to add a specialized bundle (e.g., for a new rendering backend):

1. **Create Entry File**: Create `src/my-entry.tsx`. It usually just exports everything from `./core` and re-exports specific build flags from `#three`.
2. **Create THREE Variant**: Create `src/three/my-variant.ts` to define which parts of the Three.js ecosystem are included.
3. **Configure Unbuild**: Add a new entry to `build.config.ts`.
4. **Update exports**: Add the new sub-path to `package.json`'s `exports` field.
5. **Audit**: Add the new file to `scripts/verify-bundles.js` and add a corresponding test in `packages/fiber/tests/bundles.test.ts`.

---
//\* Preconstruct → Unbuild (v10) ------------------------

## 🚀 Release Strategy
Preconstruct couldn't support per-entry alias resolution for our THREE.js import strategy.

For the current Alpha Stage procedures, see the **[Alpha Release Guide](./ALPHA-RELEASE.md)**.
- Simpler project structure (no stub folders)
- Better tree-shaking and bundle optimization
- Per-entry THREE.js import control
- Faster development with better stub support
85 changes: 23 additions & 62 deletions docs/development/CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,76 +1,37 @@
# Contributing to `@react-three/fiber`
# Contributing

Thank you for your interest in contributing! This document outlines the standards and initial setup required to work on the project.
Thank you for your interest in contributing to `@react-three/fiber`. This document covers the standards and conventions we follow.

## 📜 Standards & Conventions
## Commit Conventions

### Semantic Commits
We use [Conventional Commits](https://conventionalcommits.org) for automated releases:

This project follows [Conventional Commits](https://conventionalcommits.org). This is required for our automated release process.
- `feat:` — New features
- `fix:` — Bug fixes
- `chore:` — Maintenance tasks
- `docs:` — Documentation updates

- `feat:` for new features
- `fix:` for bug fixes
- `chore:` for maintenance
- `docs:` for documentation updates
## Versioning

### Versioning
All packages follow [Semantic Versioning (SemVer)](https://semver.org).

We use [Semantic Versioning (SemVer)](https://semver.org) for all packages.
## Changesets

---
Every code change requires a changeset. This powers our automated release process.

## 🛠️ Getting Started
```bash
pnpm changeset:add
```

### Prerequisites
You'll be prompted to select affected packages, bump type (major/minor/patch), and write a summary.

- **Node.js**: v22 or higher
- **pnpm**: v9 or higher (Required for workspace management)
## What Reviewers Look For

### Initial Setup
- **Tests** — All changes should include appropriate test coverage
- **Types** — TypeScript definitions must be accurate and complete
- **Docs** — Update documentation if behavior changes
- **Scope** — Keep PRs focused; split large changes into smaller PRs

1. **Clone the repository**:
```bash
git clone https://github.com/pmndrs/react-three-fiber.git
cd react-three-fiber
```
2. **Install dependencies**:
```bash
pnpm install
```
> **Note**: This automatically generates development stubs. See [BUILD](./BUILD.md) for details.
## Ready to Code?

---

## 💻 Development Workflow

For a detailed guide on how to make changes, add features, and use the development environment, see the **[Development Guide](./DEVELOPMENT.md)**.

### Quick Commands

- **Run examples**: `pnpm examples`
- **Run tests**: `pnpm test`
- **Create a changeset**: `pnpm changeset:add` (Required for all code changes)

---

## 🧪 Testing Requirements

All contributions must include appropriate tests. We use **Vitest** for unit and integration testing.

- **Detailed testing guide**: **[Testing Guide](./TESTING.md)**
- **Update snapshots**: `pnpm vitest -u`

---

## 🚀 Release Process

We use [Changesets](https://github.com/atlassian/changesets) for versioning and publishing.

- For stable releases, see the `Publishing` section in the core documentation.
- For alpha releases (v10), follow the **[Alpha Release Guide](./ALPHA-RELEASE.md)**.

---

## Need Help?

If you're unsure about anything, please open a [GitHub Discussion](https://github.com/pmndrs/react-three-fiber/discussions) or join our Discord.
See the **[Development Guide](./DEVELOPMENT.md)** for workflow, project structure, and links to technical docs.
Loading
Loading