@react-native/babel-preset applies transform-destructuring unconditionally under Hermes — semantic divergence breaks three.js TSL (crashes every InstancedMesh on WebGPU)
Chưa có ai nhận issue này.
- Ngôn ngữ chính
- C++
- Star
- 127k
- Fork
- 25.3k
- Merge trung bình
- 1 ngày 23 giờ
- Pull request đã merge (30 ngày)
- 4
Mô tả
Description
@react-native/babel-preset pushes @babel/plugin-transform-destructuring unconditionally — including for Hermes targets (packages/react-native-babel-preset/src/configs/main.js, the always-on plugin list; verified in 0.81.4 at src/configs/main.js:122). Hermes supports array/object destructuring natively, so for Hermes builds the transform is (a) redundant bytecode and (b) a semantic hazard, because downleveled destructuring is not perfectly equivalent to native destructuring.
The concrete divergence: native array destructuring always goes through the iterator protocol, while Babel's _slicedToArray helper short-circuits via _arrayWithHoles — if (Array.isArray(r)) return r; — and then indexes positionally. For a Proxy over an array (Array.isArray pierces to the target) whose get trap serves a custom Symbol.iterator but does not answer positional reads, the two compile outputs produce different values: iterator yields the real elements, indexing yields undefined.
That exotic-sounding object is shipping in one of the most popular 3D libraries: three.js's TSL shader system passes Fn arguments through exactly such a Proxy, and three's own sources destructure it (src/nodes/accessors/Instance.js: Fn( ( [ instancedMesh ] ) => { const { instanceMatrix, instanceColor } = instancedMesh; ... } )). Metro rewrites three's code with this transform, so on device the body receives undefined and every React Native app using three.js WebGPU (react-native-webgpu, Dawn/Vulkan) with an InstancedMesh crashes on the first rendered frame:
TypeError: Cannot read property 'instanceMatrix' of undefined
at ... setupOutput / getOutputNode / build / flowNodeFromShaderStage / ... / render
The same pattern arms skinning(), batch() and morphReference() — i.e. skinned meshes, batched meshes and morph targets are equally affected. Nothing surfaces in Node/browser tests because those run untransformed code; the failure exists only in the Metro-bundled app.
Ask
Consider making transform-destructuring conditional on the engine target (skipped for Hermes, as several other transforms already are engine-aware), or documenting why it must stay unconditional. Cross-filed with the two neighboring projects, since each owns a slice of the collision:
- three.js (Proxy should honor positional reads): https://github.com/mrdoob/three.js/issues/34227
- Babel (
_arrayWithHolesfast path vs custom iterators on array-backed Proxies): link to follow in a comment
Steps to reproduce
- Bare RN 0.81.4 app (Hermes, new arch) +
react-native-webgpu0.8.2 +three0.185.1 - Render any scene containing a
THREE.InstancedMeshwithWebGPURenderer - First frame throws
TypeError: Cannot read property 'instanceMatrix' of undefined
A toolchain-only demonstration (no device needed): run @react-native/babel-preset over const fn = ([a]) => a; and observe the _slicedToArray output; feed it an array-backed Proxy with a custom Symbol.iterator in its get trap and no index handling — native semantics return the element, transformed semantics return undefined.
React Native Version
0.81.4
Affected Platforms
Runtime: Android (verified on device: Android 15, Hermes release bundle, Dawn/Vulkan). iOS untested but the transform is platform-independent.
Output of npx @react-native-community/cli info
Not attached — the report is toolchain-level (@react-native/babel-preset 0.81.4, @babel/plugin-transform-destructuring 7.29.7, @babel/runtime 7.29.7); happy to add on request.
Hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Hướng nghiên cứu
Bắt đầu trong packages/react-native-babel-preset/src/configs/main.js, đặc biệt là danh sách plugin luôn được bật quanh dòng 122, và tái hiện phép biến đổi bằng ví dụ Proxy được hỗ trợ bởi array trong issue. So sánh các mẫu cấu hình Hermes và non-Hermes đã có; được xem là hoàn tất khi preset либо tránh được sự khác biệt về ngữ nghĩa đối với Hermes, hoặc ghi lại một lý do đã được xác nhận để giữ lại phép biến đổi, đồng thời hành vi của toolchain được bao phủ bởi một test phù hợp.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Đánh giá
- Công nghệ
- javascript, react-native, three.js
- Lĩnh vực
- build-system, mobile, tooling
- Loại issue
- Lỗi
- Độ khó
- 4/5
- Thời gian dự kiến
- 3-5 ngày
- Mức độ hoạt động
- Sôi nổi
- Độ rõ ràng
- Khá rõ ràng
- Mức phù hợp với người mới
- 55/100