简体   繁体   中英

Could not load gltf scene in deployed Nextjs app

I try to load a gltf model into my next app and it works well in local environment but when I deploy to vercel, the deployed app says:

Application error: a client-side exception has occurred (see the browser console for more information)

In the console:

Failed to load resource: the server responded with a status of 404 ()

Error: Could not load /Skull/scene.gltf: fetch for "..." responded with 404: )

My gltf model component looks like this:

import { useGLTF } from '@react-three/drei'
import { useFrame } from '@react-three/fiber'
import gsap from 'gsap'
import {  useEffect, useState } from 'react'

export default function SkullScene () {
  const gltf = useGLTF("/Skull/scene.gltf")
  const [isRotatable, setIsRotatable] = useState(false)

  useEffect(() => {
    gltf.scene.scale.set(800,800,800)
    gltf.scene.rotation.set(0.3,0,0)
    gltf.scene.position.set(0,0,0)
    if(gltf.scene){
      gsap.to(gltf.scene.scale, { duration:10, x: '-=750', y:'-=750', z:"-=750", delay: 2})
    }
    setTimeout(()=>setIsRotatable(true),13000)
  },[gltf.scene])

  useFrame(()=>{
    if(isRotatable){
      gltf.scene.rotation.y += 0.003
    }
  })

  return (
      <primitive object={gltf.scene}/>
  )
}

The One that rendering the model:

import React, { lazy, useState } from 'react'
import { useThree } from '@react-three/fiber'
import dynamic from "next/dynamic";

const SkullScene = dynamic(() => import("./SkullScene"), {
  ssr: false,
});

// const SkullScene = lazy(() => import("./SkullScene"));


const BannerScene = () => {
  const { viewport } = useThree()

  return (
    <group scale={viewport.width / 550}>
      <SkullScene/>
    </group>
  )
}

export default BannerScene;

And my Banner:

import { Canvas } from "@react-three/fiber";
import { lazy, Suspense } from "react";

const BannerScene = lazy(() => import("./BannerScene"));

export const Banner = () => (
    <div className="h-screen w-full relative text-gray-50 bg-gradient-radial from-[#f7c160]/10 via-transparent to-transparent">
      <Suspense fallback={"loading"}>
          <Canvas id='canvas' camera={{ fov: 75, near: 0.1, far: 1000, position: [0, 0, 180] }}>
            <ambientLight />
            <directionalLight position={[-10, 20, 5]} intensity={2} color="#b8912f"/>
            <directionalLight position={[10, 20, 10]} intensity={2} color="#b8912f"/>
            <BannerScene/>
          </Canvas>
      </Suspense>
    </div>
)

I tried with lazyy import, next/dynamic but none of them worked. Again, in local dev environment everything works fine. I tried a webpack config also:

/** @type {import('next').NextConfig} */
const nextConfig = {
  reactStrictMode: true,
  // swcMinify: true,
  webpack (config, options) {
    config.module.rules.push({
      test: /\.(glb|gltf)$/,
      use: {
        loader: 'file-loader',
      }
    })
    return config
  }
}

module.exports = nextConfig

Honestly I don't really know how webpack works but it didn't help.

Hope someone knows a solution!

You can't use relative urls in production unless importing or requiring them beforehand.
Try import modelSrc from '/Skull/scene.gltf' , then directly use it in your code like const gltf = useGLTF(modelSrc) .

What worked in my case is (this solution will also work for useTexture):

import { useGLTF } from '@react-three/drei'
import { useFrame } from '@react-three/fiber'
import gsap from 'gsap'
import {  useEffect, useState } from 'react'

import SkullGLTF from "@/public/Skull/scene.gltf"

export default function SkullScene () {
    const gltf = useGLTF(SkullGLTF.src)
    const [isRotatable, setIsRotatable] = useState(false)

    ....
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM