簡體   English   中英

從 create-react-app 轉換為 NextJS,ThreeJS 的問題

[英]Converting from create-react-app to NextJS, problem with ThreeJS

我在反應中有一個工作的 3d model 查看器,我現在正在嘗試將其移植到 Next。 我需要 GLTFLoader 和 OrbitControls 這給了我反應的問題,我像這樣加載:

import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'

不能這樣做,因為接下來我會收到此錯誤:

SyntaxError: Cannot use import statement outside a module
This error happened while generating the page. Any console logs will be displayed in the terminal window.
Source

.next\server\pages\index.js (1:0) @ Object.three/examples/jsm/loaders/GLTFLoader

> 1 | module.exports = require("three/examples/jsm/loaders/GLTFLoader");

然后我嘗試使用三標准庫並從那里導入控件和加載器。 同樣的錯誤。 然后我嘗試使用 require('') 來導入它,但我又遇到了同樣的錯誤。 我在google上發現了一些幾乎類似的問題,但沒有容易理解的解決方案。

完整代碼:

 import * as THREE from 'three' import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader' import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js' // import Model3d from '../assets/centered.gltf' // import Model3d from '../assets/3dmodel.gltf' import D3d from '../assets/images/3d.svg' import React from 'react' // let GLTFLoader // let OrbitControls const VisA = () => { // GLTFLoader = require('three/examples/jsm/loaders/GLTFLoader').GLTFLoader // OrbitControls = require('three/examples/js/controls/OrbitControls') //.OrbitControls const { useRef, useEffect } = React const mount = useRef(null) const hitbox = useRef(null) const controls = useRef(null) useEffect(() => { let width = mount.current.clientWidth let height = mount.current.clientHeight let frameId const scene = new THREE.Scene() const camera = new THREE.PerspectiveCamera(75, width / height, 0.1, 1000) const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true }) const loader = new GLTFLoader() const camcontrols = new OrbitControls(camera, hitbox.current) // loader.load(Model3d, function (gltf) { loader.load('./3dmodel/3dmodel.gltf', function (gltf) { gltf.scene.scale.set(14, 14, 14) var box = new THREE.Box3().setFromObject(gltf.scene) var center = new THREE.Vector3() box.getCenter(center) gltf.scene.position.sub(center) scene.add(gltf.scene) }) const hemiLight = new THREE.HemisphereLight(0xffeeb1, 0x80820, 20) const light2 = new THREE.DirectionalLight(0xfdeee1, 20) const spotLight = new THREE.SpotLight(0xfdeee1, 4) const spotLight2 = new THREE.SpotLight(0xfdeee1, 4) scene.add(hemiLight) scene.add(spotLight) scene.add(spotLight2) light2.position.set(10, -50, 500) scene.add(light2) scene.rotation.y = -1.65 camera.position.z = 4 // scene.add(cube) // renderer.setClearColor('#FFFFFF') renderer.setSize(width, height) const renderScene = () => { renderer.render(scene, camera) } const handleResize = () => { width = mount.current.clientWidth height = mount.current.clientHeight renderer.setSize(width, height) camera.aspect = width / height camera.updateProjectionMatrix() renderScene() } const animate = () => { spotLight.position.set( camera.position.x + 10, camera.position.y + 10, camera.position.z + 10 ) spotLight2.position.set( camera.position.x - 10, camera.position.y - 10, camera.position.z - 10 ) renderScene() frameId = window.requestAnimationFrame(animate) } const start = () => { if (.frameId) { frameId = requestAnimationFrame(animate) } } const stop = () => { cancelAnimationFrame(frameId) frameId = null } mount.current.appendChild(renderer.domElement) window,addEventListener('resize'. handleResize) start() controls,current = { start. stop } return () => { stop() window,removeEventListener('resize'. handleResize) mount.current.removeChild(renderer,domElement) } }, []) return ( <div className="relative flex items-center justify-center w-full h-full " ref={mount} // onClick={() => setAnimating(!isAnimating)} > <div className="absolute w-full h-full"> <D3d className="w-10 h-10 mt-10 text-gray-800 fill-current " /> </div> <div className="absolute w-3/5 h-4/5" ref={hitbox}></div> </div> ) } export default VisA

問題

您正在導入以 ESM 格式編寫的模塊,當 NextJS 嘗試在服務器端呈現您的代碼節點時,您的代碼節點不理解 ESM——Node.js 通常需要 CJS(CommonJS)。

解決方案

這取決於。

1.你想讓你的代碼使用three在服務器端運行嗎?

(這假設three可以在節點中運行,我不能說一種或另一種)

我認為這里有幾個選擇:

a)使用與 Node.js 和瀏覽器兼容的three版本。 掃了一眼這個問題,可以考慮試試三通(我沒用過)。

b)自定義您的 Webpack 行為以將這three代碼捆綁並轉譯為服務器的 CJS。 就個人而言,我不建議將此作為第一步。 自定義 Webpack 很快就會變得非常復雜,在 NextJS 中這樣做會帶來額外的復雜性。

2.使用three修改您的代碼以僅在客戶端運行。

使用動態導入 從那個參考:

您可能並不總是希望在服務器端包含一個模塊。 例如,當模塊包含僅在瀏覽器中工作的庫時。

附加反饋

請注意,上面的答案是概念性的。 如果您能夠通過存儲庫提供復制,或者我可以提供更具體的解決方案。

在 Mcy 的幫助下,我發現在我的情況下添加動態導入是最簡單的。 這很簡單,我沒有更改我從 react 獲得的查看器組件中的任何內容,並在 pages/index.js 上加載了該組件:

 import dynamic from 'next/dynamic' const Dynamic3dViewr = dynamic(() => import('../components/Viewer3d.js'), { ssr: false, })

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM