[v10 alpha.5] /legacy import and browser build fail on WebGPU-only exports from plain three
Problem
The published @react-three/[email protected] /legacy entry cannot be loaded as ESM or bundled in the checked minimal browser application. It statically imports MeshBasicNodeMaterial, Node, and NodeUpdateType from plain three, which does not export those symbols.
This fails before renderer initialization. Importing only Canvas is enough; no occlusion handler, node material, or WebGPU configuration is required.
Verified environment
@react-three/fiber:10.0.0-alpha.5(actual npm package, not source aliases or development stubs)three:0.185.1react/react-dom:19.2.3- Node:
22.22.2 - Browser bundle reproduction: esbuild
0.25.12, browser platform, ESM output - Source inspected: restored v10 at
d91831d84202233c9c994dea2c5d26afe857dadc; alpha.5 tag is27df622f4990778db05fbca0b77ad5a61165169a
The restored branch differs from alpha.5 only in prop-immutability documentation. This is not evidence that the recovery merge introduced the failure. The first affected version has not been established.
Minimal reproduction
In a fresh directory:
npm init -y
npm install --ignore-scripts --save-exact @react-three/[email protected] [email protected] [email protected] [email protected]
npm install --ignore-scripts --save-dev --save-exact [email protected]
node --input-type=module -e "import { Canvas } from '@react-three/fiber/legacy'; console.log(typeof Canvas)"The direct import fails with:
SyntaxError: The requested module 'three' does not provide an export named 'MeshBasicNodeMaterial'For the browser build, create legacy-entry.mjs:
import { Canvas } from '@react-three/fiber/legacy'
console.log(Canvas)Then run:
npx esbuild legacy-entry.mjs --bundle --platform=browser --format=esm --outfile=out.mjsThe bundler reports all three missing exports:
No matching export in "node_modules/three/build/three.module.js" for import "MeshBasicNodeMaterial"
No matching export in "node_modules/three/build/three.module.js" for import "Node"
No matching export in "node_modules/three/build/three.module.js" for import "NodeUpdateType"Each originates at line 2 of the published node_modules/@react-three/fiber/dist/legacy.mjs.
Expected behavior
The legacy entry should load and bundle for an ordinary WebGLRenderer application without requiring the newer renderer/node distribution. WebGPU-only occlusion support must not prevent importing the legacy Canvas.
Source trace
The shared visibility implementation imports * as THREE through #three and references:
THREE.NodeandTHREE.NodeUpdateType.OBJECTincreateOcclusionObserverNode().THREE.MeshBasicNodeMaterialinsetupOcclusion().
The legacy Three barrel re-exports plain three. The emitted legacy package contains named imports for these three symbols. Checking renderer.isOccluded at runtime cannot protect ESM linking, which happens before that check runs.
There is also a dynamic import('three/tsl') in the emitted visibility code. Its reachability and exclusion from the legacy dependency graph should be considered when fixing the boundary; simply supplying the missing symbols by importing the newer distribution would undermine the purpose of /legacy.
Comparison and temporary migration route
| Entry | Direct ESM import | Minimal browser bundle |
|---|---|---|
@react-three/fiber |
Pass | Pass |
@react-three/fiber/legacy |
Fail | Fail |
@react-three/fiber/webgpu |
Pass | Pass |
The root entry remains an interim route for alpha.5 applications staying on WebGLRenderer, since that is its default. It retains the compatibility entry's broader imports. These checks establish import/build behavior, not full application or GPU validation.
A separate strict TypeScript fixture using only /legacy passes with skipLibCheck: false, so declaration checking alone does not catch this failure. Mixed-entry/test-renderer declaration failures found during the same audit are separate problems and outside this issue.
Fix and regression coverage
- Isolate or compile out the WebGPU-only occlusion implementation for the legacy build while retaining appropriate legacy visibility behavior.
- Verify the real built/packed package, not a source-alias or stubbed workspace, with both direct ESM imports and a minimal browser bundle.
- Add regression coverage for the public
Canvasimport from each entry, including checking that the legacy fix does not pull inthree/webgpuor TSL. - Preserve existing frustum visibility behavior on legacy and occlusion behavior on the newer renderer.
The current bundle verifier checks import paths and artifact properties. A check can accept the correct module path while missing invalid named exports from that module; a consumer import/build smoke test would cover that gap.
Source: pmndrs/react-three-fiber