0

I'm trying to import a local .obj to be loaded with THREE.OBJLoader().load() function, I know it works because when I pass a non-local URL (for example 'http://downloadOBJfromHere.com') it loads it perfectly, my main problem is that that way everytime I load it, it has to download the obj and it takes ages.

I'm doing server side rendering with React.

import * as THREE from 'three';
import * as OBJLoader from 'three-obj-loader';
import obj from '../../../assets/obj/scene.obj';

In ComponentDidMount():

const loader = new THREE.OBJLoader();
        loader.load( obj,
            object => {
                scene.add(object);
            },
            xhr => {
                console.log( ( xhr.loaded / xhr.total * 100 ) + '% loaded' );
            },
            error => {
                console.log("Error! ", error);
            }
        );

When I do this I get the error in the Chrome console:

Unexpected line: '<!doctype html><html lang="en" data-reactroot="" data-reactid="1" data-react-checksum="1415239080"><head data-reactid="2"><meta charset="utf-8" data-reactid="3"/><meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0" data-reactid="4"/><title data-reactid="5">TITLE</title><link rel="stylesheet" href="/client/style.css" data-reactid="6"/></head><body data-reactid="7"><div id="root" data-reactid="8"><!-- react-empty: 1 --></div><script type="text/javascript" src="/client/vendor.js" data-reactid="9"></script><script type="text/javascript" src="/client/client.js" data-reactid="10"></script></body></html>'

(Keep in mind that with the URL it loads fine). It shows me the root html that is served.

So I'm guessing it has to do with some webpack config for importing files, I'm using file-loader to load .obj files:

This is part of my webpack config:

const paths = {
  source: path.join(__dirname, '../source'),
  javascript: path.join(__dirname, '../source/js'),
  images: path.join(__dirname, '../source/assets/img'),
  svg: path.join(__dirname, '../source/assets/svg'),
  obj: path.join(__dirname, '../source/assets/obj'),
  build: path.join(__dirname, '../build'),
};

const rules = [
  {
    test: /\.mtl$/,
    loader: 'mtl-loader'
  },
  { test: /\.obj$/,
    loader: 'file-loader',
    include: paths.obj
  },
  {
    test: /\.(png|gif|jpg|svg)$/,
    include: paths.images,
    use: [{
      loader: 'file-loader',
      options: {
        name: 'client/assets/[name]-[hash].[ext]',
      }
    }]
  }
];

EDIT Added images loader to show how I serve images.

Here's part of my server config

const app = express();
const hostname = 'localhost';
const port = 8080;

app.use('/client', express.static('build/client'));

app.use((req, res) => {
  const { persistor, store } = configureStore();
  const context = {};

  const appHtml = ReactDOMServer.renderToString(
    <Provider store={ store }>
      <PersistGate persistor={ persistor }>
        <StaticRouter location={ req.url } context={ context }>
            <App />
        </StaticRouter>
      </PersistGate>
    </Provider>
  );

  const serverHtml = getServerHtml(appHtml, 'dehydratedState');
  if (context.url) {
    res.redirect(301, context.url);
  } else {
    res.status(context.status || 200).send(serverHtml);
  }
});

app.listen(port, err => callback);
LuisEgan
  • 952
  • 2
  • 13
  • 28
  • That should work but you need to have a server running locally that actually serves static resources. It's hard to tell based on the snippets you provide here... – Felipe Jan 18 '18 at 08:05
  • I edited to add the server config, where it app.use('/client', express.static('build/client')); shouldn't that be enough? – LuisEgan Jan 19 '18 at 01:24
  • Where are you running the app? Is it deployed in the cloud, in which case you need to load the obj in the client anyway or does it run locally, in which case you would load from the build dir and it should be quick... If your client cannot find the resource then you should check the network tab in your browser developer tools to find out from where it attempts to load it. – Felipe Jan 19 '18 at 08:58

1 Answers1

5

I figured it out.

In the webpack config I changed the .obj loader, from 'file-loader' to 'url-loader'

const rules = [
  {
    test: /\.mtl$/,
    loader: 'mtl-loader'
  },
  { test: /\.obj$/,

// CHANGE HERE
    loader: 'url-loader',

    include: paths.obj
  },
  {
    test: /\.(png|gif|jpg|svg)$/,
    include: paths.images,
    use: [{
      loader: 'file-loader',
      options: {
        name: 'client/assets/[name]-[hash].[ext]',
      }
    }]
  }
];

Note: I also had a problem importing a script called OutlinePass (for THREE.js) that doesn't exist in npm, I managed to import it this way:

const script = document.createElement("script");
        script.src = require('!!url-loader!../../../assets/webgl/js/OutlinePass.js');
        script.async = true;
        document.body.appendChild(script);

the script itself didn't work but I managed to import it (what we are talking about here :) )

LuisEgan
  • 952
  • 2
  • 13
  • 28