Skip to content

chore: 3.0 foundation (yarn 4, r3f v10 stack, rollup build, CI, alpha prerelease) - #787

Open
DennisSmolek wants to merge 7 commits into
nextfrom
feat/3.0-foundation
Open

DennisSmolek wants to merge 7 commits into
nextfrom
feat/3.0-foundation

Conversation

@DennisSmolek

Copy link
Copy Markdown
Member

Foundation workstream for 3.0. It moves the tooling and dependency stack, so the other 3.0 branches (bug fixes, docs, character controller, soft bodies, core stepping) can build on it. Library src changes are kept to what the new stack needs to compile and test.

What changed

Package manager

  • Yarn 4.18.1 through Corepack (packageManager), with nodeLinker: node-modules.
  • Root tooling moved from dependencies to devDependencies. @manypkg/cli, preconstruct and babel are removed.
  • The demo and addons depend on the workspace packages through workspace:*.
  • engines.node >=22. .nvmrc is v22.22.2 because jsdom 30 needs at least 22.22.2.

Stack

  • @react-three/fiber and @react-three/test-renderer 10.0.0-canary.a056612 (scheduler 0.3, fixed step)
  • three / @types/three 0.186
  • react / react-dom 19.2.8
  • drei 11.0.0-alpha.7 (demo only)
  • vitest 5 with jsdom 30, TypeScript 5.9
  • Peer dependencies: fiber >=10.0.0-0, react >=19.0 <19.3, three >=0.185.0. The addons package peers on @react-three/rapier ^3.0.0-0.
  • three-stdlib is bumped to ^2.36.1, because 2.35 imports LuminanceFormat, which three has removed. It is removed entirely in the bug-fix workstream.

Build

  • rollup + esbuild + rollup-plugin-dts replace preconstruct, mirroring react-three-jolt.
  • Output is dual ESM/CJS (dist/index.{mjs,cjs}, .d.{ts,mts,cts}). Each package gets an exports map, sideEffects: false, engines, a narrowed files list and repository metadata.
  • The config is shared in scripts/rollup-library.mjs, and entry points are derived from the exports map. Adding @react-three/rapier/soft-bodies therefore only needs src/soft-bodies/index.ts plus an exports, files and typesVersions entry.
  • Relative imports of another entry are rewritten to the package specifier, so core is never bundled twice.
  • yarn check:packages runs publint --strict and attw --pack on each package.
  • vitest, the root tsc and the demo resolve the workspace packages from src (aliases and tsconfig paths), so none of them needs a build first.

Minimal source and test changes

  • utils.ts: type-only narrowing for v10's readonly-tuple math types.
  • Tests:
    • They now await create() instead of racing it against mount callbacks. On v10, the overlapping act() scopes left updates unflushed.
    • They expect the extra zero-delta priming frame from advanceFrames.
    • The physics snapshot was re-baselined.

Demo (minimal)

  • state.clock became state.elapsed.
  • <Canvas shadows> became gl={{ shadows: true }}, which keeps the WebGL renderer.
  • drei Text now comes from @react-three/drei/legacy.
  • OrbitControls types come from three/addons.
  • The deep imports of library internals were removed.
  • r3f-perf was replaced by drei <Stats>. r3f-perf pins drei 9 and an old three-stdlib, which breaks the build on three 0.186.

Lint and format

  • ESLint 9 flat config and Prettier 3 (.prettierrc keeps the repo's existing style options), with lint, format and format:check scripts.
  • The codebase is not reformatted or lint-fixed. Current baseline: 29 lint errors, 126 warnings, and 4 files that differ under Prettier.
  • The pre-commit hook now runs yarn typecheck instead of the full CI.

CI and release

  • ci.yml replaces test.yml and runs typecheck, test, build with publint/attw, and the demo build. Lint/format is a non-blocking job for now.
  • Runs on PRs and pushes to main and next, with concurrency and permissions blocks.
  • A shared .github/actions/setup action enables Corepack, sets up the yarn cache and installs.
  • Actions are on their current majors (checkout/setup-node v7, configure-pages v6, upload-pages-artifact v5, deploy-pages v5). This supersedes chore(.github/workflows): update actions version #733.
  • The release workflow mirrors jolt and runs on main and next.
  • @changesets/cli 3, and changeset pre enter alpha has been run (.changeset/pre.json).
  • Added a major changeset for core and addons.
  • Dependabot now covers the root workspace and github-actions.
  • Added DEVELOPMENT.md.

Decided differently from the plan

  • Prettier style: I kept the repo's style (2 spaces, double quotes) rather than jolt's (4 spaces, single quotes). This keeps the deferred reformat at 4 files instead of every line. Switching is a one-line change.
  • changesets/action: stays on @v1, as in jolt. v2 drops the NPM_TOKEN/.npmrc handling, which would change the npm auth setup.

Risks

  • Snapshot re-baseline: the values changed by about 1e-14. The test renderer's advanceFrames now drives the scheduler with millisecond timestamps, so per-frame deltas are not exactly 1/60. The accumulator therefore carries a tiny residual, and the interpolated positions differ in the last digits.
  • useFrame call counts: advanceFrames(n) now runs n+1 frames because of a priming step(0) frame. useFrame callbacks see n+1 calls, while physics still steps n times.
  • Canary pin: r3f is pinned to a canary until alpha.6 ships.
  • Demo not run: the demo builds, but I did not test it in a browser (shadows via gl, <Stats>, drei 11).
  • Release workflow on next: it can only be verified once this merges.

Verification (fresh yarn install --immutable)

  • yarn build ✅
  • yarn typecheck ✅
  • yarn workspace demo typecheck ✅
  • yarn test: 38/38 ✅
  • yarn check:packages (publint + attw, all resolution modes green) ✅
  • yarn demo:build ✅
  • yarn changeset version dry run gives @react-three/rapier 3.0.0-alpha.0 (reverted)
  • yarn lint and yarn format:check fail on the existing baseline, as expected

🤖 Generated with Claude Code

DennisSmolek and others added 7 commits October 10, 2026 12:09
- packageManager yarn@4.18.1, nodeLinker node-modules (.yarnrc.yml)
- move root tooling from dependencies to devDependencies
- drop @manypkg/cli (only used by the `ci` script)
- demo/addons depend on workspace packages via workspace:*
- engines.node >=22, ignore .yarn state but keep releases/plugins/patches

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- @react-three/fiber + test-renderer 10.0.0-canary.a056612 (scheduler 0.3, fixed step),
  three/@types/three 0.186, react/react-dom 19.2.8, drei 11.0.0-alpha.7 (demo)
- peerDependencies: fiber >=10.0.0-0, react >=19.0 <19.3, three >=0.185.0;
  rapier-addons peers on @react-three/rapier ^3.0.0-0
- three-stdlib ^2.36.1 (2.35 imports LuminanceFormat, removed from three)
- vitest 5 + jsdom 30, typescript 5.9; vitest.config.mts replaces vite.config.mts and
  resolves workspace packages from src (no build needed); root tsconfig uses
  moduleResolution Bundler with matching `paths`
- utils.ts: type-only narrowing for fiber v10's readonly-tuple math types
- tests: await `create()` instead of racing it against mount callbacks (overlapping act
  scopes), expect the extra zero-delta priming frame from advanceFrames, re-baseline the
  physics snapshot (float noise from scheduler ms timing, see PR)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Mirrors react-three-jolt's build: `tsc -p tsconfig.build.json` emits per-file declarations,
rollup bundles each entry to dist/<name>.{mjs,cjs} with esbuild and rolls declarations up
into dist/<name>.{d.ts,d.mts,d.cts}.

- shared config in scripts/rollup-library.mjs; entry points are derived from each
  package's `exports` map, so a subpath entry (e.g. `./soft-bodies` -> src/soft-bodies/index.ts)
  only needs an `exports` + `files` entry. Relative imports of another entry are rewritten to
  the published specifier so core is never inlined twice.
- package.json: `exports` map (import/require with types), `type`, `sideEffects: false`,
  `engines`, narrowed `files`, repository/bugs/homepage/license metadata
- deps, peers and their subpaths are external
- `check:package` (publint --strict + attw --pack) per package, `yarn check:packages` at root
- drop babel config and the preconstruct dev postinstall

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Minimal fixes only; the demo migration proper (WebGPU, routing, perf overlay) is separate work.

- resolve @react-three/rapier(-addons) from workspace sources via vite aliases + tsconfig
  paths (keeps the old `preconstruct dev` behaviour: no build needed, HMR on library code)
- moduleResolution Bundler (exports maps of fiber v10 / drei 11 / three)
- `state.clock` is gone in v10: use `state.elapsed`
- `<Canvas shadows>` -> `gl={{ shadows: true }}` (keeps the default WebGL renderer)
- drei 11: `Text` comes from `@react-three/drei/legacy`; drop unused `useCamera`
- OrbitControls type from three/addons instead of three-stdlib
- SpringExample: stop deep-importing library internals (blocked by the exports map)
- replace r3f-perf (pins drei 9 / an old three-stdlib that breaks on three 0.186) with drei
  <Stats>

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- eslint.config.mjs mirrors react-three-jolt (js + typescript-eslint recommended, react,
  react-hooks rules-of-hooks/exhaustive-deps, jsx-a11y, eslint-config-prettier last);
  automatic JSX runtime everywhere
- prettier 3 with the repo's existing style options moved to .prettierrc, so the deferred
  reformat stays small (6 files differ today)
- `lint`, `format`, `format:check` scripts. The codebase is NOT reformatted or lint-fixed
  here (baseline: 29 errors / 126 warnings); that lands at the end of the 3.0 integration.
- pre-commit hook runs `yarn typecheck` instead of the full CI

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- ci.yml (replaces test.yml): typecheck, test, build + publint/attw, demo build, and a
  non-blocking lint/format job; runs on PRs and pushes to main and next, with concurrency
  cancellation and read-only permissions
- shared .github/actions/setup composite: corepack (yarn 4) + setup-node with yarn cache +
  `yarn install --immutable`
- current action majors: checkout v7, setup-node v7, configure-pages v6,
  upload-pages-artifact v5, deploy-pages v5 (supersedes #733)
- release.yml mirrors react-three-jolt: runs on main and next, owner guard, permissions
  (contents/pull-requests write, id-token for provenance), yarn 4 publish env;
  `changeset:version` / `changeset:publish` scripts (publish builds and tests first)
- @changesets/cli 3; `yarn changeset pre enter alpha` (.changeset/pre.json), so `next`
  releases 3.0.0-alpha.n under the `alpha` dist-tag; `prerelease:enter`/`prerelease:exit`
  scripts replace the canary ones
- changeset for the r3f v10 stack / package format (core + addons, major)
- dependabot: root workspace + github-actions ecosystem, ignore majors of the r3f stack
- .nvmrc v22.22.2 (jsdom 30 needs >=22.22.2), demo `typecheck` script

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@changeset-bot

changeset-bot Bot commented Oct 10, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: a4a0c34

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 2 packages
Name Type
@react-three/rapier Major
@react-three/rapier-addons Major

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant