Proper path to import models

Hello

I’ve had some trouble in the past loading images/models into my scene, mostly as the path resolves with 404s every time.

I was wondering what the best practices were for storing these images. I was putting them in a static folder outside of my src directory, but I’m not sure if this is part of my issue. Also, should urls resolve from the src directory downwards? Any help on this wold be greatly appreciated as I dont know why my urls cant be found. Im using a react/webpack setup so maybe I need to set up a path in my webpack?

Sorry I’m not able to share my code, but just some general pointers would be handy.

Many thanks

Steve

This depends on your build process quite a bit. With a simple static server it’s very easy, with Webpack there might be some configuration involved. I usually try to us a static directory for models and images (easier), but src/ is also a totally fine option (and requires more config). I don’t know Webpack super well but if you can share your Webpack config others might be able to help more.

Sure, thank you:

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { getIfUtils, removeEmpty } = require('webpack-config-utils');
const webpack = require('webpack');

const env = process.env.APP_DEBUG === 'true' ? 'development' : 'production';
const { ifDevelopment } = getIfUtils(env);

module.exports = {
  mode: 'development',
  entry: path.join(__dirname, 'src', 'index.js'),
  output: {
    path: path.resolve(__dirname, 'dist'),
  },
  module: {
    rules: [
      {
        test: /\.js$|jsx/,
        exclude: /node_modules/,
        loader: 'babel-loader',
        options: {
          presets: [
            '@babel/preset-env',
            '@babel/preset-react',
          ],
          plugins: removeEmpty([
            '@babel/plugin-proposal-class-properties',
            '@babel/plugin-proposal-optional-chaining',
            ifDevelopment('react-hot-loader/babel'),
          ]),
        },
      },
      {
        test: /\.css$/i,
        use: ['style-loader', 'css-loader'],
      },
      {
        test: /\.(png|jp(e*)g|svg|gif)$/,
        use: ['file-loader'],
      },
      {
        test: /\.svg$/,
        use: ['@svgr/webpack'],
      },
      {
        test: /\.glsl$/,
        use: ['webpack-glsl-loader'],
      },
      {
        test: /\.(glb|gltf)$/,
        use:
          [{
            loader: 'file-loader',
            options: {
              outputPath: 'assets/models/',
            },
          }],
      },
    ],
  },
  resolve: {
    alias: {
      'react-dom': '@hot-loader/react-dom',
    },
    extensions: ['*', '.js', '.jsx'],
  },
  plugins: removeEmpty([
    new HtmlWebpackPlugin({
      template: path.join(__dirname, 'src', 'index.html'),
    }),
    ifDevelopment(new webpack.HotModuleReplacementPlugin()),
  ]),
};

Just a follow up on this, I was trying to use a URL directly in a drei loader, so useGLTF('../../myUrl').

Instead I needed to import my urls first and call that variable from the loader, so:

import myModel from '../../myUrl'
...
const { nodes, materials } = useGLTF(myModel)

Not sure if that’s the right thing to do but it’s working.

generally there are two ways. it should be the same in all module environments. also keep in mind, three loaders expect urls. they will fetch the file internally.

import via url-loader, relative path

:+1: file can reside within /src, relative paths only!
:+1: it’s type safe because it’s a compile time effort, it cannot fail you
:+1: files will be bundle split and processed via loaders
:+1: better cache control

:-1: some people consider this not-so-good because web-standards

import fileUrl from './file.ext'

load(fileUrl)

plain url, absolute path

:+1: files must reside in /public, easy
:+1: some people consider this better because web-standards

:-1: file can not reside within /src, path cannot be relative (./ or ../)
:-1: not type safe, it can fail and you won’t know until you run into it
:-1: harder cache control

load("/file.ext")
1 Like

You can use URL and import.meta to load from a relative URL in an es6 module and follow web standards. A number of bundlers including webpack support this now, I believe.

const url = new URL( './file.gltf', import.meta.url );
new GLTFLoader()
  .loadAsync( url )
  .then( result => { ... } );
2 Likes

thanks both, they’re super helpful answers!