Lazy Loading GLB Files on as-needed basis?

Hi everyone,

I’m working on a 3D streetwear fashion editor. The way I have set up my scene is to build a ModelProvider that renders the required glb model onto the scene.

Like this:

<Canvas>
  <PerspectiveCamera… />
  <OrbitControls… />
  <ModelProvider model={modelName} />
</Canvas>

We only ever display one model at a time. When a different model is selected, the old one will stop showing.

import { Model as HoodieBoxy } from '../public/products/hoodies/boxy'
import { Model as HoodieOversized } from '../public/products/hoodies/oversize'
import { Model as HoodieRegular } from '../public/products/hoodies/regular'

const ModelProvider = (props) => {
  switch (props.model) {
    case 'hoodies-boxy':
	  return <HoodieBoxy {...props} />
    case 'hoodies-oversized':
      return <HoodieOversized {...props} />
    case 'hoodies-regular':
      return <HoodieRegular {...props} />

    case 'sweaters-boxy':
      return <SweaterBoxy {...props} />
    case 'sweaters-oversized':
      return <SweaterOversized {...props} />
    case 'sweaters-regular':
      return <SweaterRegular {...props} />
  …
}

The models themselves look like this:

export function Model(props) {
  const { nodes, materials } = useGLTF('/products/hoodies/boxy.glb')

  return ( /* meshes here */ )
}

useGLTF.preload('/products/hoodies/boxy.glb')

This has been working well, but we’re now up to 26 models and, running a Lighthouse check, I noticed that all of them are always loaded in the background, leading to what Google calls “enormous network payloads”.

Models from the same type can be switched in the UI, i.e. if I view a Regular Hoodie, I can click “Boxy” and the model will be swapped to a Boxy one.
But there is no way to go from Hoodie to Sweater without first going back to the product grid and choosing a new category. So I wouldn’t mind the “adjacent” models to be preloaded, but doing it with all 26 is way too much.

My initial idea was to lazy-load the models (like this: const HoodieRegular = React.lazy(() => import('../public/products/hoodies/regular'))), but this seems to be causing problems (next-dev.js:24 Warning: lazy: Expected the result of a dynamic import() call. Instead received: [object Module]).

I also tried a very similar approach with dynamically importing the modules, but with similarly poor results, so I have the impression that both of these approaches go into the completely wrong direction to begin with.

I was wondering if there was a best practice for such cases, i.e. to only import the models that are actually required.

Thanks for your help!
Daniel