Failed to compile: 'MTLLoader' is not exported from 'three' (React)

Hello Friends!

this is my first post and first of all thanks freeCodeCamp for all the support :slight_smile:

My first thread is about an error message I got in react. The whole project is standing still because I can not figure out what I did wrong…

It has something to do with three js as the error message shows:

Failed to compile

./src/components/ThreeJsObject.jsAttempted import error: ‘MTLLoader’ is not exported from ‘three’ (imported as ‘THREE’).

Is anyone able to help me figure out the issue here?

If you need more information, please let me know.

Thanks a lot!!

Can we see ThreeJsObject.js?

Or better yet, can you put your project in a repo?

Actually I never uploaded a repository and first I need to learn how to manage a GitHub Profile. However I will upload it tomorrow, but for now I show you the ThreeJsObject.js code here:

import React, { Component } from 'react';

import './ThreeJsObject.css';
import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
import * as dat from 'dat.gui';
import { PointLightHelper } from 'three';
import { OBJLoader } from './resources/threejs/r127/examples/jsm/loaders/OBJLoader.js';
import { MTLLoader } from './MTLLoader.js';


OBJLoader(three);

class ThreeJsObject extends Component {
    constructor(props) {
        super(props)
    }

    render () {
        return (
        <canvas className='webgl'></canvas>
    )
    }

    componentDidMount () {
        const textureLoader = new THREE.TextureLoader ()

        // Threejs 3DObject Code 

        const normalTexture = textureLoader.load('./static/textures/NormalMap.png')

        // Debug
        
        const gui = new dat.GUI()

        // Canvas
        const canvas = document.querySelector('canvas.webgl')

        // Scene
        const scene = new THREE.Scene()



        // Obj 3D Object Loader

        var MTLLoader = new THREE.MTLLoader();
        MTLLoader.setPath("../public/threejs/")
        MTLLoader.load("../public/threejs/among-us.mtl", function (material) {
            material.preload()
            
            var OBJLoader = new THREE.OBJLoader();
            OBJLoader.setMaterials(material);
            OBJLoader.setPath("../public/threejs");
            OBJLoader.load("among-us.obj", function (object) {
                scene.add(object);
                object.position.y -=60;
            });
        });


        /*
        {
            const objLoader = new OBJLoader();
            objLoader.load('../public/threejs/among-us.obj', (root) => {
              scene.add(root);
            });
          }
        */

        // Materials

        const material = new THREE.MeshStandardMaterial()
        material.metalness= 0.2
        material.metalness= 38.81
        material.normalMap= normalTexture
        material.color = new THREE.Color(0x3333ff)

        gui.add(material, 'metalness').min(0).max(100).step(0.01)


        // Mesh

        const sphere = new THREE.Mesh(geometry,material)
        scene.add(sphere)

        // Light 01

        const pointLight1 = new THREE.PointLight(0xffffff, 2.1)
        pointLight1.position.set(-0,92,0.53,1.39)
        pointLight1.intensity = 1

        scene.add(pointLight1)

        const light1 = gui.addFolder('Light 1')

        light1.add(pointLight1.position, 'x').min(-3).max(3).step(0.01)
        light1.add(pointLight1.position, 'y').min(-3).max(3).step(0.01)
        light1.add(pointLight1.position, 'z').min(-3).max(3).step(0.01)
        light1.add(pointLight1, 'intensity').min(0).max(10).step(0.01)

        const light1Color = {
            color: 0xc9c9c9
        }

        light1.addColor(light1Color, 'color')
            .onChange(() => {
            pointLight1.color.set(light1Color.color)
            })
        

        // Light 02

        const pointLight2 = new THREE.PointLight(0x3333ff, 1.1)
        pointLight2.position.set(0.8,0,0.73)
        pointLight2.intensity = 10

        scene.add(pointLight2)

        const light2 = gui.addFolder('Light 2')

        light2.add(pointLight2.position, 'x').min(-3).max(3).step(0.01)
        light2.add(pointLight2.position, 'y').min(-3).max(3).step(0.01)
        light2.add(pointLight2.position, 'z').min(-3).max(3).step(0.01)
        light2.add(pointLight2, 'intensity').min(0).max(10).step(0.01)

        const light2Color = {
            color: 0xff84
        }

        light2.addColor(light2Color, 'color')
            .onChange(() => {
            pointLight2.color.set(light2Color.color)
            })


        // Light 03

        const pointLight3 = new THREE.PointLight(0x00ff99, 1.1)
        pointLight3.position.set(3,-3,-0.13)
        pointLight3.intensity = 10

        scene.add(pointLight3)

        const light3 = gui.addFolder('Light 3')

        light3.add(pointLight3.position, 'x').min(-3).max(3).step(0.01)
        light3.add(pointLight3.position, 'y').min(-3).max(3).step(0.01)
        light3.add(pointLight3.position, 'z').min(-3).max(3).step(0.01)
        light3.add(pointLight3, 'intensity').min(0).max(10).step(0.01)

        const light3Color = {
            color: 0xff00c6
        }

        light3.addColor(light3Color, 'color')
            .onChange(() => {
            pointLight3.color.set(light3Color.color)
            })


        const pointLightHelper = new THREE.PointLightHelper(pointLight3, 1)
        scene.add(pointLightHelper)

        /**
         * Sizes
         */
        const sizes = {
            width: window.innerWidth,
            height: window.innerHeight
        }

        window.addEventListener('resize', () =>
        {
            // Update sizes
            sizes.width = window.innerWidth
            sizes.height = window.innerHeight

            // Update camera
            camera.aspect = sizes.width / sizes.height
            camera.updateProjectionMatrix()

            // Update renderer
            renderer.setSize(sizes.width, sizes.height)
            renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
        })

        /**
         * Camera
         */
        // Base camera
        const camera = new THREE.PerspectiveCamera(75, sizes.width / sizes.height, 0.1, 100)
        camera.position.x = 0
        camera.position.y = 0
        camera.position.z = 2
        scene.add(camera)

        // Controls
        // const controls = new OrbitControls(camera, canvas)
        // controls.enableDamping = true

        /**
         * Renderer
         */
        const renderer = new THREE.WebGLRenderer({
            canvas: canvas,
            alpha: true
        })
        renderer.setSize(sizes.width, sizes.height)
        renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))

        /**
         * Animate
         */

        document.addEventListener('mousemove', onDocumentMouseMove)

        let mouseX = 0;
        let mouseY = 0;

        let targetX = 0;
        let targetY = 0;

        const windowX = window.innerWidth / 2;
        const windowY = window.innerHeight / 2;

        function onDocumentMouseMove(event) {
            mouseX = (event.clientX - windowX)
            mouseY = (event.clientY - windowY)
        }

        const updateSphere = (event) => {
            sphere.position.y = window.scrollY * .001
        }
            

        window.addEventListener('scroll', updateSphere);


        const clock = new THREE.Clock()

        const tick = () =>
        {

            targetX = mouseX * .002
            targetY = mouseY * .002

            const elapsedTime = clock.getElapsedTime()

            // Update objects
            sphere.rotation.y = .5 * elapsedTime

            sphere.rotation.y += .5 * (targetX - sphere.rotation.y)
            sphere.rotation.x += .05 * (targetY - sphere.rotation.x)
            sphere.position.z += -.05 * (targetY - sphere.rotation.x)

            // Update Orbital Controls
            // controls.update()

            // Render
            renderer.render(scene, camera)

            // Call tick again on the next frame
            window.requestAnimationFrame(tick)
        }

        tick()
    }


}



// Loading


export default ThreeJsObject;

I’ve edited your post for readability. When you enter a code block into a forum post, please precede it with a separate line of three backticks and follow it with a separate line of three backticks to make it easier to read.

You can also use the “preformatted text” tool in the editor (</>) to add backticks around text.

See this post to find the backtick on your keyboard.
Note: Backticks (`) are not single quotes (’).

I just recognised it afterwards and tried to format it, but you were faster :slight_smile:

Yeah, it’s cool, we all have to figure out the formatting when we start out here.

OK, and what does three.js look like? What is it exporting?

Hmm actually it was already a few months ago since I started this project and now I can not remember everything. I just can find a three.js file in node_modules… I guess I installed the three.js lib via node package manager…

I lost the clearity for the peoject, because this was my first react app. I will try to make a repo, because the structure is quite simple to analyse for a more experienced developer I guess. I would love to continue the project but damn I stuck here…

I just tried to upload the app to GitHub, but I recognised that even the compressed file is 180mb large, but I am just able to upload 25mb. Something is going wrong here, how can I handle that?

I very appreciate some help!!

When you upload to gihub, make sure your node_modules are in the .gitignore. If you have media files, you make want to consider excluding those too, if they are very big.

1 Like

I excluded the node_modules folder, but the file size was still to large so I deleted some video files. The code and component structure is still the same and I hope you can have an eye on the code.

Actually I wonder how you can put the app together as it was when the node_modules and the dependencies are not there anymore. Do you use the list of dependencies (from the package.json file) to install the node_modules again as it was before?

Here is the link: nakazoomi/create-react-app · GitHub

Please let me know if something went wrong, then I will upload it again…

I very appreciate your help, this means a lot to me!!

Yes. And the lock file makes sure you get the exact versions.

I’ll try to take a look at what you have later today.

1 Like

The repo you uploaded is empty.

Never really used three.js but you are calling MTLLoader on THREE, should you not just be using MTLLoader as the constructor?

You have:

import { MTLLoader } from './MTLLoader.js';

var MTLLoader = new THREE.MTLLoader();

So instead:

var MTLLoader = new MTLLoader();

It also looks like you can chain the method calls without saving the instance if you want:

new MTLLoader()
  .setpath()
  .load()

Docs

1 Like

@kevinSmith:
Sorry there was an issue with the upload. I watched a few tutorials and uploaded again, therefore I deleted node_modules folder and the video and image files. The structure is available now. Here is the new link: New Repo

@lasjorg:
I am not sure if I just need to use MTLLoader as the constructor. However I changed the line as you showed me, but the error is still there.

General Information:

This error started when I tried to import an .obj file (3d Object) into my project by using MTLLoader. Most of the code was created by following a tutorial. After the error appears I tried to delete the three js file to start from scratch, but then other error messages started to show up so I got stuck…

Question about the react folder structure:

When I deleted the image and video files to reduce the project size, I recognised that the media files are located in two folders the public and the build folder. Why are these files located in two folders? What is the purpose of these two folders?

Thank you!!

What is the tutorial you are following and is it using just the browser? Where did you get the MTLLoader.js file from?

I can get it to compile if I import like so.

import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader';
import { MTLLoader } from 'three/examples/jsm/loaders/MTLLoader';

And use it like this.


const _MTLLoader = new MTLLoader();
_MTLLoader.setPath('../public/threejs/');
_MTLLoader.load('../public/threejs/among-us.mtl', function (material) {
  material.preload();

  const _OBJLoader = new OBJLoader();
  _OBJLoader.setMaterials(material);
  _OBJLoader.setPath('../public/threejs');
  _OBJLoader.load('among-us.obj', function (object) {
    scene.add(object);
    object.position.y -= 60;
  });
});

And also comment out the undefined stuff (geometry is undefined so all the sphere code as well). There is also nothing in the public/threejs folder so that is about as far as I can test anything.


re: folders


As an aside, I would suggest you learn git and GitHub when you have the time. There are a ton of tutorials.

2 Likes

@lasjorg Thanks a lot for your help and also for the links, I already watched the github tutorial. Sorry for the late reply, I got sick…

I followed multiple tutorials and mixed it together the way I need it. The last tutorial was a three.js tutorial from skillshare link to the tutorial. The teacher provided a link to the MTLLoader.js file link to the mtlloader file on Github.

I did the correction as you wrote in your answer and I also comment out the geometry but I went from one error to another. This is the first error, which shows that the geometry is not defined:

After I comment out the geometry I got this error:

To clarify the whole thing quickly, I uploaded a new repo which includes the 3d objects (.obj file). That´s where I got stuck, I tried to import a 3d object as an obj file with the OBJLoader (Object Loader) and the MTLLoader (Material Loader). I guess that the error appeared because the tutorial example was not a react project, so probably I need another Loader specially for react?

Here is the link: New repo with .obj file

In case you can not solve the issue, it would be great if you can delete everything which is related to the error message so that I am able to start the three.js object import from zero again. I already tried it myself but there is always an error message showing up and now I lost the clarity…

Actually I would be very happy when I am just able to open the project without an error, then I will deep dive into the development again. At the moment I am just frustrating because I spend so much time figuring out the problem :sob:

I highly appreciate some help!!

Thanks a lot :slight_smile:

The error message is pretty clear about it. You commented out the updateSphere function but left the event listener that uses it.

I can get it to compile, but I don’t see anything. I can’t tell you why because I don’t know the lib and have never used it.

1 Like

@lasjorg You are the hero of the day!! Thanks :smiley:

Finally I got it to compile, I did not saw the rendered website since a few months… I got so confused that I think I need to start again to kick this damn silicon ass!!

Thanks for this supporting community!

1 Like