diff --git a/.github/workflows/create-react-server.yml b/.github/workflows/create-react-server.yml index 0f52b534..3ff4b5c5 100644 --- a/.github/workflows/create-react-server.yml +++ b/.github/workflows/create-react-server.yml @@ -95,7 +95,7 @@ jobs: test-results: name: Test Results 📊 needs: test-create - if: always() + if: always() && needs.test-create.result != 'skipped' runs-on: ubuntu-latest steps: - name: Checkout diff --git a/examples/react-three/App.jsx b/examples/react-three/App.jsx new file mode 100644 index 00000000..e4af30a5 --- /dev/null +++ b/examples/react-three/App.jsx @@ -0,0 +1,37 @@ +import ThreeScene from "./ThreeScene"; + +export default function App() { + return ( + + + + + React Three Fiber + React Server + + + +
+

React Three Fiber + @lazarv/react-server

+ +

+ A rotating cube rendered with @react-three/fiber inside a React + Server Component tree. +

+
+ + + ); +} diff --git a/examples/react-three/ThreeScene.jsx b/examples/react-three/ThreeScene.jsx new file mode 100644 index 00000000..06bfdada --- /dev/null +++ b/examples/react-three/ThreeScene.jsx @@ -0,0 +1,35 @@ +"use client"; + +import { useRef } from "react"; +import { Canvas, useFrame } from "@react-three/fiber"; + +function RotatingBox() { + const meshRef = useRef(null); + + useFrame((_, delta) => { + if (meshRef.current) { + meshRef.current.rotation.x += delta * 0.5; + meshRef.current.rotation.y += delta * 0.8; + } + }); + + return ( + + + + + ); +} + +export default function ThreeScene() { + return ( + + + + + + ); +} diff --git a/examples/react-three/package.json b/examples/react-three/package.json new file mode 100644 index 00000000..ef8ec0ae --- /dev/null +++ b/examples/react-three/package.json @@ -0,0 +1,21 @@ +{ + "name": "@lazarv/react-server-example-react-three", + "private": true, + "description": "@lazarv/react-server React Three Fiber example application", + "keywords": [], + "license": "ISC", + "author": "", + "scripts": { + "dev": "react-server ./App.jsx", + "build": "react-server build ./App.jsx", + "start": "react-server start" + }, + "dependencies": { + "@lazarv/react-server": "workspace:^", + "@react-three/fiber": "^9.5.0", + "three": "^0.171.0" + }, + "devDependencies": { + "@types/three": "^0.171.0" + } +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 461b131f..c1ec5548 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -482,7 +482,7 @@ importers: version: 6.3.4 ts-jest: specifier: ^29.1.0 - version: 29.2.5(@babel/core@7.28.5)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.5))(jest@29.7.0(@types/node@20.17.11)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.11.21)(@types/node@20.17.11)(typescript@5.7.2)))(typescript@5.7.2) + version: 29.2.5(@babel/core@7.29.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.29.0))(jest@29.7.0(@types/node@20.17.11)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.11.21)(@types/node@20.17.11)(typescript@5.7.2)))(typescript@5.7.2) ts-loader: specifier: ^9.4.3 version: 9.5.1(typescript@5.7.2)(webpack@5.97.1(@swc/core@1.11.21)) @@ -621,6 +621,22 @@ importers: specifier: ^15.6.6 version: 15.6.6(react@19.2.1) + examples/react-three: + dependencies: + '@lazarv/react-server': + specifier: workspace:^ + version: link:../../packages/react-server + '@react-three/fiber': + specifier: ^9.5.0 + version: 9.5.0(@types/react@19.2.2)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(three@0.171.0) + three: + specifier: ^0.171.0 + version: 0.171.0 + devDependencies: + '@types/three': + specifier: ^0.171.0 + version: 0.171.0 + examples/remote: dependencies: '@lazarv/react-server': @@ -4097,6 +4113,31 @@ packages: '@radix-ui/rect@1.1.1': resolution: {integrity: sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==} + '@react-three/fiber@9.5.0': + resolution: {integrity: sha512-FiUzfYW4wB1+PpmsE47UM+mCads7j2+giRBltfwH7SNhah95rqJs3ltEs9V3pP8rYdS0QlNne+9Aj8dS/SiaIA==} + peerDependencies: + expo: '>=43.0' + expo-asset: '>=8.4' + expo-file-system: '>=11.0' + expo-gl: '>=11.0' + react: '>=19 <19.3' + react-dom: '>=19 <19.3' + react-native: '>=0.78' + three: '>=0.156' + peerDependenciesMeta: + expo: + optional: true + expo-asset: + optional: true + expo-file-system: + optional: true + expo-gl: + optional: true + react-dom: + optional: true + react-native: + optional: true + '@remirror/core-constants@2.0.2': resolution: {integrity: sha512-dyHY+sMF0ihPus3O27ODd4+agdHMEmuRdyiZJ2CCWjPV5UFmn17ZbElvk6WOGVE4rdCJKZQCrPV2BcikOMLUGQ==} @@ -4952,6 +4993,9 @@ packages: '@tsconfig/node16@1.0.4': resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} + '@tweenjs/tween.js@23.1.3': + resolution: {integrity: sha512-vJmvvwFxYuGnF2axRtPYocag6Clbb5YS7kLL+SO/TeVFzHqDIWrNKYtcsPMibjDx9O+bu+psAy9NKfWklassUA==} + '@tybys/wasm-util@0.10.1': resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} @@ -5140,6 +5184,11 @@ packages: peerDependencies: '@types/react': ^19.2.0 + '@types/react-reconciler@0.28.9': + resolution: {integrity: sha512-HHM3nxyUZ3zAylX8ZEyrDNd2XZOnQ0D5XfunJF5FLQnZbHHYq4UWvW1QfelQNXv1ICNkwYhfxjwfnqivYB6bFg==} + peerDependencies: + '@types/react': '*' + '@types/react-transition-group@4.4.11': resolution: {integrity: sha512-RM05tAniPZ5DZPzzNFP+DmrcOdD0efDUxMy3145oljWSl3x9ZV5vhme98gTxFrj2lhXvmGNnUiuDyJgY9IKkNA==} @@ -5161,12 +5210,18 @@ packages: '@types/stack-utils@2.0.3': resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} + '@types/stats.js@0.17.4': + resolution: {integrity: sha512-jIBvWWShCvlBqBNIZt0KAshWpvSjhkwkEu4ZUcASoAvhmrgAUI2t1dXrjSL4xXVLB4FznPrIsX3nKXFl/Dt4vA==} + '@types/superagent@8.1.9': resolution: {integrity: sha512-pTVjI73witn+9ILmoJdajHGW2jkSaOzhiFYF1Rd3EQ94kymLqB9PjD9ISg7WaALC7+dCHT0FGe9T2LktLq/3GQ==} '@types/supertest@6.0.2': resolution: {integrity: sha512-137ypx2lk/wTQbW6An6safu9hXmajAifU/s7szAHLN/FeIm5w7yR0Wkl9fdJMRSHwOn4HLAI0DaB2TOORuhPDg==} + '@types/three@0.171.0': + resolution: {integrity: sha512-oLuT1SAsT+CUg/wxUTFHo0K3NtJLnx9sJhZWQJp/0uXqFpzSk1hRHmvWvpaAWSfvx2db0lVKZ5/wV0I0isD2mQ==} + '@types/unist@2.0.10': resolution: {integrity: sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA==} @@ -5176,6 +5231,9 @@ packages: '@types/use-sync-external-store@0.0.6': resolution: {integrity: sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==} + '@types/webxr@0.5.24': + resolution: {integrity: sha512-h8fgEd/DpoS9CBrjEQXR+dIDraopAEfu4wYVNY2tEPwk60stPWhvZMf4Foo5FakuQ7HFZoa8WceaWFervK2Ovg==} + '@types/yargs-parser@21.0.3': resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} @@ -5369,6 +5427,9 @@ packages: '@webassemblyjs/wast-printer@1.14.1': resolution: {integrity: sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==} + '@webgpu/types@0.1.69': + resolution: {integrity: sha512-RPmm6kgRbI8e98zSD3RVACvnuktIja5+yLgDAkTmxLr90BEwdTXRQWNLF3ETTTyH/8mKhznZuN5AveXYFEsMGQ==} + '@wolfy1339/lru-cache@11.0.2-patch.1': resolution: {integrity: sha512-BgYZfL2ADCXKOw2wJtkM3slhHotawWkgIRRxq4wEybnZQPjvAp71SPX35xepMykTw8gXlzWcWPTY31hlbnRsDA==} engines: {node: 18 >=18.20 || 20 || >=22} @@ -7601,6 +7662,11 @@ packages: resolution: {integrity: sha512-RKYVTCjAnRthyJes037NX/IiqeidgN1xc3j1RjFfECFp28A1GVwK9nA+i0rJPaHqSZwygLzRnFlzUuHFoWWy+Q==} engines: {node: '>=6'} + its-fine@2.0.0: + resolution: {integrity: sha512-KLViCmWx94zOvpLwSlsx6yOCeMhZYaxrJV87Po5k/FoZzcPSahvK5qJ7fYhS61sZi5ikmh2S3Hz55A2l3U69ng==} + peerDependencies: + react: ^19.0.0 + jackspeak@3.4.0: resolution: {integrity: sha512-JVYhQnN59LVPFCEcVa2C3CrEKYacvjRfqIQl+h8oi91aLYQVWRYbxjPcv1bUiUy/kLmQaANrYfNMCO3kuEDHfw==} engines: {node: '>=14'} @@ -8348,6 +8414,9 @@ packages: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} + meshoptimizer@0.18.1: + resolution: {integrity: sha512-ZhoIoL7TNV4s5B6+rx5mC//fw8/POGyNxS/DZyCJeiZ12ScLfVwRE/GfsxwiTkMYYD5DmK2/JXnEVXqL4rF+Sw==} + methods@1.1.2: resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==} engines: {node: '>= 0.6'} @@ -9550,6 +9619,15 @@ packages: react: '>=16.6.0' react-dom: '>=16.6.0' + react-use-measure@2.1.7: + resolution: {integrity: sha512-KrvcAo13I/60HpwGO5jpW7E9DfusKyLPLvuHlUyP5zqnmAPhNc6qTRjUQrdTADl0lpPpDVU2/Gg51UlOGHXbdg==} + peerDependencies: + react: '>=16.13' + react-dom: '>=16.13' + peerDependenciesMeta: + react-dom: + optional: true + react@0.0.0-experimental-ab18f33d-20260220: resolution: {integrity: sha512-hnphlgmXP0DIbbWz/c0mMfxFsb+qQ6gCMbE6IyvbGz55ay1DgfYKD0YtKfWUOs2cktp4LmDM5+5ewGw9LSfiCg==} engines: {node: '>=0.10.0'} @@ -10229,6 +10307,11 @@ packages: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} + suspend-react@0.1.3: + resolution: {integrity: sha512-aqldKgX9aZqpoDp3e8/BZ8Dm7x1pJl+qI3ZKxDN0i/IQTWUwBx/ManmlVJ3wowqbno6c2bmiIfs+Um6LbsjJyQ==} + peerDependencies: + react: '>=17.0' + svg-parser@2.0.4: resolution: {integrity: sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==} @@ -10323,6 +10406,9 @@ packages: thread-stream@2.7.0: resolution: {integrity: sha512-qQiRWsU/wvNolI6tbbCKd9iKaTnCXsTwVxhhKM6nctPdujTyztjlbUkUTUymidWcMnZ5pWR0ej4a0tjsW021vw==} + three@0.171.0: + resolution: {integrity: sha512-Y/lAXPaKZPcEdkKjh0JOAHVv8OOnv/NDJqm0wjfCzyQmfKxV7zvkwsnBgPBKTzJHToSOhRGQAGbPJObT59B/PQ==} + three@0.183.1: resolution: {integrity: sha512-Psv6bbd3d/M/01MT2zZ+VmD0Vj2dbWTNhfe4CuSg7w5TuW96M3NOyCVuh9SZQ05CpGmD7NEcJhZw4GVjhCYxfQ==} @@ -11133,6 +11219,24 @@ packages: zod@4.1.12: resolution: {integrity: sha512-JInaHOamG8pt5+Ey8kGmdcAcg3OL9reK8ltczgHTAwNhMys/6ThXHityHxVV2p3fkw/c+MAvBHFVYHFZDmjMCQ==} + zustand@5.0.11: + resolution: {integrity: sha512-fdZY+dk7zn/vbWNCYmzZULHRrss0jx5pPFiOuMZ/5HJN6Yv3u+1Wswy/4MpZEkEGhtNH+pwxZB8OKgUBPzYAGg==} + engines: {node: '>=12.20.0'} + peerDependencies: + '@types/react': '>=18.0.0' + immer: '>=9.0.6' + react: '>=18.0.0' + use-sync-external-store: '>=1.2.0' + peerDependenciesMeta: + '@types/react': + optional: true + immer: + optional: true + react: + optional: true + use-sync-external-store: + optional: true + zwitch@2.0.4: resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} @@ -11633,21 +11737,45 @@ snapshots: '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 + '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.27.1 + optional: true + '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.28.5)': dependencies: '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 + '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.27.1 + optional: true + '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.28.5)': dependencies: '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 + '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.27.1 + optional: true + '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.28.5)': dependencies: '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 + '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.27.1 + optional: true + '@babel/plugin-syntax-import-assertions@7.27.1(@babel/core@7.29.0)': dependencies: '@babel/core': 7.29.0 @@ -11658,16 +11786,34 @@ snapshots: '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 + '@babel/plugin-syntax-import-attributes@7.26.0(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.27.1 + optional: true + '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.28.5)': dependencies: '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 + '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.27.1 + optional: true + '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.28.5)': dependencies: '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 + '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.27.1 + optional: true + '@babel/plugin-syntax-jsx@7.24.7(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 @@ -11688,41 +11834,89 @@ snapshots: '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 + '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.27.1 + optional: true + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.28.5)': dependencies: '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.27.1 + optional: true + '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.28.5)': dependencies: '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 + '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.27.1 + optional: true + '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.28.5)': dependencies: '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 + '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.27.1 + optional: true + '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.28.5)': dependencies: '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 + '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.27.1 + optional: true + '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.28.5)': dependencies: '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 + '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.27.1 + optional: true + '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.28.5)': dependencies: '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 + '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.27.1 + optional: true + '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.28.5)': dependencies: '@babel/core': 7.28.5 '@babel/helper-plugin-utils': 7.27.1 + '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.27.1 + optional: true + '@babel/plugin-syntax-typescript@7.24.7(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 @@ -14907,6 +15101,26 @@ snapshots: '@radix-ui/rect@1.1.1': {} + '@react-three/fiber@9.5.0(@types/react@19.2.2)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(three@0.171.0)': + dependencies: + '@babel/runtime': 7.26.7 + '@types/webxr': 0.5.24 + base64-js: 1.5.1 + buffer: 6.0.3 + its-fine: 2.0.0(@types/react@19.2.2)(react@19.2.1) + react: 19.2.1 + react-use-measure: 2.1.7(react-dom@19.2.1(react@19.2.1))(react@19.2.1) + scheduler: 0.27.0 + suspend-react: 0.1.3(react@19.2.1) + three: 0.171.0 + use-sync-external-store: 1.6.0(react@19.2.1) + zustand: 5.0.11(@types/react@19.2.2)(react@19.2.1)(use-sync-external-store@1.6.0(react@19.2.1)) + optionalDependencies: + react-dom: 19.2.1(react@19.2.1) + transitivePeerDependencies: + - '@types/react' + - immer + '@remirror/core-constants@2.0.2': {} '@remix-run/router@1.17.0': {} @@ -15624,6 +15838,8 @@ snapshots: '@tsconfig/node16@1.0.4': {} + '@tweenjs/tween.js@23.1.3': {} + '@tybys/wasm-util@0.10.1': dependencies: tslib: 2.8.1 @@ -15837,6 +16053,10 @@ snapshots: dependencies: '@types/react': 19.2.2 + '@types/react-reconciler@0.28.9(@types/react@19.2.2)': + dependencies: + '@types/react': 19.2.2 + '@types/react-transition-group@4.4.11': dependencies: '@types/react': 19.2.2 @@ -15865,6 +16085,8 @@ snapshots: '@types/stack-utils@2.0.3': {} + '@types/stats.js@0.17.4': {} + '@types/superagent@8.1.9': dependencies: '@types/cookiejar': 2.1.5 @@ -15877,12 +16099,23 @@ snapshots: '@types/methods': 1.1.4 '@types/superagent': 8.1.9 + '@types/three@0.171.0': + dependencies: + '@tweenjs/tween.js': 23.1.3 + '@types/stats.js': 0.17.4 + '@types/webxr': 0.5.24 + '@webgpu/types': 0.1.69 + fflate: 0.8.2 + meshoptimizer: 0.18.1 + '@types/unist@2.0.10': {} '@types/unist@3.0.2': {} '@types/use-sync-external-store@0.0.6': {} + '@types/webxr@0.5.24': {} + '@types/yargs-parser@21.0.3': {} '@types/yargs@17.0.33': @@ -16202,6 +16435,8 @@ snapshots: '@webassemblyjs/ast': 1.14.1 '@xtuc/long': 4.2.2 + '@webgpu/types@0.1.69': {} + '@wolfy1339/lru-cache@11.0.2-patch.1': {} '@xtuc/ieee754@1.2.0': {} @@ -16485,6 +16720,20 @@ snapshots: transitivePeerDependencies: - supports-color + babel-jest@29.7.0(@babel/core@7.29.0): + dependencies: + '@babel/core': 7.29.0 + '@jest/transform': 29.7.0 + '@types/babel__core': 7.20.5 + babel-plugin-istanbul: 6.1.1 + babel-preset-jest: 29.6.3(@babel/core@7.29.0) + chalk: 4.1.2 + graceful-fs: 4.2.11 + slash: 3.0.0 + transitivePeerDependencies: + - supports-color + optional: true + babel-plugin-istanbul@6.1.1: dependencies: '@babel/helper-plugin-utils': 7.27.1 @@ -16527,12 +16776,39 @@ snapshots: '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.28.5) '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.28.5) + babel-preset-current-node-syntax@1.1.0(@babel/core@7.29.0): + dependencies: + '@babel/core': 7.29.0 + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.29.0) + '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.29.0) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.29.0) + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.29.0) + '@babel/plugin-syntax-import-attributes': 7.26.0(@babel/core@7.29.0) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.29.0) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.29.0) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.29.0) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.29.0) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.29.0) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.29.0) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.29.0) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.29.0) + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.29.0) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.29.0) + optional: true + babel-preset-jest@29.6.3(@babel/core@7.28.5): dependencies: '@babel/core': 7.28.5 babel-plugin-jest-hoist: 29.6.3 babel-preset-current-node-syntax: 1.1.0(@babel/core@7.28.5) + babel-preset-jest@29.6.3(@babel/core@7.29.0): + dependencies: + '@babel/core': 7.29.0 + babel-plugin-jest-hoist: 29.6.3 + babel-preset-current-node-syntax: 1.1.0(@babel/core@7.29.0) + optional: true + bail@2.0.2: {} balanced-match@1.0.2: {} @@ -18679,6 +18955,13 @@ snapshots: iterare@1.2.1: {} + its-fine@2.0.0(@types/react@19.2.2)(react@19.2.1): + dependencies: + '@types/react-reconciler': 0.28.9(@types/react@19.2.2) + react: 19.2.1 + transitivePeerDependencies: + - '@types/react' + jackspeak@3.4.0: dependencies: '@isaacs/cliui': 8.0.2 @@ -19653,6 +19936,8 @@ snapshots: merge2@1.4.1: {} + meshoptimizer@0.18.1: {} + methods@1.1.2: {} micromark-core-commonmark@2.0.1: @@ -21095,6 +21380,12 @@ snapshots: react: 19.2.1 react-dom: 19.2.1(react@19.2.1) + react-use-measure@2.1.7(react-dom@19.2.1(react@19.2.1))(react@19.2.1): + dependencies: + react: 19.2.1 + optionalDependencies: + react-dom: 19.2.1(react@19.2.1) + react@0.0.0-experimental-ab18f33d-20260220: {} react@19.2.1: {} @@ -22021,6 +22312,10 @@ snapshots: supports-preserve-symlinks-flag@1.0.0: {} + suspend-react@0.1.3(react@19.2.1): + dependencies: + react: 19.2.1 + svg-parser@2.0.4: {} symbol-observable@4.0.0: {} @@ -22135,6 +22430,8 @@ snapshots: dependencies: real-require: 0.2.0 + three@0.171.0: {} + three@0.183.1: {} throttle-debounce@5.0.2: {} @@ -22203,7 +22500,7 @@ snapshots: ts-interface-checker@0.1.13: {} - ts-jest@29.2.5(@babel/core@7.28.5)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.28.5))(jest@29.7.0(@types/node@20.17.11)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.11.21)(@types/node@20.17.11)(typescript@5.7.2)))(typescript@5.7.2): + ts-jest@29.2.5(@babel/core@7.29.0)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.29.0))(jest@29.7.0(@types/node@20.17.11)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.11.21)(@types/node@20.17.11)(typescript@5.7.2)))(typescript@5.7.2): dependencies: bs-logger: 0.2.6 ejs: 3.1.10 @@ -22217,10 +22514,10 @@ snapshots: typescript: 5.7.2 yargs-parser: 21.1.1 optionalDependencies: - '@babel/core': 7.28.5 + '@babel/core': 7.29.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - babel-jest: 29.7.0(@babel/core@7.28.5) + babel-jest: 29.7.0(@babel/core@7.29.0) ts-loader@9.5.1(typescript@5.7.2)(webpack@5.97.1(@swc/core@1.11.21)): dependencies: @@ -22923,4 +23220,10 @@ snapshots: zod@4.1.12: {} + zustand@5.0.11(@types/react@19.2.2)(react@19.2.1)(use-sync-external-store@1.6.0(react@19.2.1)): + optionalDependencies: + '@types/react': 19.2.2 + react: 19.2.1 + use-sync-external-store: 1.6.0(react@19.2.1) + zwitch@2.0.4: {} diff --git a/test/__test__/apps/react-three.spec.mjs b/test/__test__/apps/react-three.spec.mjs new file mode 100644 index 00000000..f7d6b017 --- /dev/null +++ b/test/__test__/apps/react-three.spec.mjs @@ -0,0 +1,21 @@ +import { join } from "node:path"; + +import { hostname, page, server, waitForHydration } from "playground/utils"; +import { expect, test } from "vitest"; + +process.chdir(join(process.cwd(), "../examples/react-three")); + +test("react-three load", async () => { + await server("./App.jsx"); + await page.goto(hostname); + await page.waitForLoadState("networkidle"); + await waitForHydration(); + + expect(await page.title()).toBe("React Three Fiber + React Server"); + expect(await page.textContent("h1")).toContain("React Three Fiber"); + + // @react-three/fiber mounts a element when the client component renders + const canvas = page.locator("canvas"); + await canvas.waitFor({ state: "visible", timeout: 10000 }); + expect(await canvas.count()).toBe(1); +}); diff --git a/test/vitestGlobalSetup.mjs b/test/vitestGlobalSetup.mjs index a19ad683..8ff3d40f 100644 --- a/test/vitestGlobalSetup.mjs +++ b/test/vitestGlobalSetup.mjs @@ -9,7 +9,13 @@ export async function setup({ provide }) { browserServer = await chromium.launchServer({ headless: !process.env.REACT_SERVER_DEBUG, args: process.env.CI - ? ["--no-sandbox", "--disable-setuid-sandbox"] + ? [ + "--no-sandbox", + "--disable-setuid-sandbox", + "--enable-webgl", + "--use-gl=swiftshader", + "--ignore-gpu-blocklist", + ] : undefined, }); provide("wsEndpoint", browserServer.wsEndpoint());