7

I've been struggling with importing example modules from three.js, I have used next.js (a server-side react framework) in my project with a custom server in express. My server code looks like this -

const express = require('express'); const next = require('next'); const favicon = require('serve-favicon'); var path = require('path'); let fs = require('fs') const dev = process.env.NODE_ENV !== 'production'; const nextApp = next({ dev }); nextApp.prepare() .then(() => { let server = express(), options = {}, PORT = 3000, app = express() if (dev) { // DEVELOPMENT /// // DEVELOPMENT /// } else { // PRODUCTION /// options = { ...options } // PRODUCTION /// } server.use(favicon(path.join(__dirname, "/favicon.ico"))) server.get('/', (req, res) => { const actualPage = '/'; nextApp.render(req, res, actualPage); }); server.get('*', (req, res) => { const actualPage = '/not-found'; nextApp.render(req, res, actualPage); // return handle(req, res) }); server.listen((PORT), (err) => { if (err) throw err console.log('>> Ready on ' + PORT) }) }) .catch((ex) => { console.error(ex.stack) process.exit(1) }) 

I basically ran a npx create-next-app and configured a custom express server in my next.js project for dynamic routing as you can see in the code above.

Then, I used three.js to create a scene in a home component which is imported and rendered in my App.js file. My home.js component looks like this -

import React, { useState, useEffect } from 'react' import * as THREE from 'three' import { TrackballControls } from 'three/examples/jsm/controls/TrackballControls' import "../src/assets/sass/home.scss" const X = () => { let parent, renderer, scene, camera, TrackballControls useEffect(() => { // renderer renderer = new THREE.WebGLRenderer() renderer.setSize( window.innerWidth, window.innerHeight ) document.body.appendChild( renderer.domElement ) // scene scene = new THREE.Scene() // camera camera = new THREE.PerspectiveCamera( 40, window.innerWidth / window.innerHeight, 1, 100 ) camera.position.set( 20, 20, 20 ) // controls controls = new TrackballControls( camera ) controls.minDistance = 5 controls.maxDistance = 250 controls.enableDamping = true; // an animation loop is required when either damping or auto-rotation are enabled controls.dampingFactor = 0.05; // axes // scene.add(new THREE.AxisHelper( 20 )) // geometry let geometry = new THREE.SphereGeometry( 2, 8, 6, 0, 6.3, 0, 3.1) // material let material = new THREE.MeshBasicMaterial({ wireframe: true, wireframeLinewidth: 1 }) let sphere = new THREE.Mesh( geometry, material ) // parent parent = new THREE.Object3D() scene.add( parent ) scene.add( sphere ) function animate() { requestAnimationFrame( animate ) parent.rotation.z += 0.01 controls.update() renderer.render( scene, camera ) } animate() } ,[]) return <div></div> } export default X 

Now here's the problem I'm facing - I'm importing an example module from three.js called TrackballControls which is not exactly inside the core three module, but in a folder outside it as you can see from the path - 'three/examples/jsm/controls/TrackballControls.js'. You can see more here - Importing es6 modules separately . But somehow, it's not working. It's throwing an error like

this

I tried doing the same thing using a simple create-react-app, the import totally works!! So I know there is a problem with my server side code, and I am assuming it's a webpack related issue. But I don't really have any idea about webpack. Someone please help me, for it will be highly appreciated!

Here's my next.config.js file if it helps -

const withSASS = require('@zeit/next-sass') const { parsed: localEnv } = require('dotenv').config() const webpack = require('webpack') // const path = require('path') function HACK_removeMinimizeOptionFromCssLoaders(config) { console.warn( 'HACK: Removing `minimize` option from `css-loader` entries in Webpack config', ) config.module.rules.forEach(rule => { if (Array.isArray(rule.use)) { rule.use.forEach(u => { if (u.loader === 'css-loader' && u.options) { delete u.options.minimize } }) } }) } module.exports = withSASS( { webpack(config) { HACK_removeMinimizeOptionFromCssLoaders(config) config.plugins.push(new webpack.EnvironmentPlugin(localEnv)) return config } }) 
1
  • I tried your approach to include github.com/tradingview/lightweight-charts but could not progress well, if time permits, can you please post an example with lightweight-charts. Apart from the above request, thanks for posting your findings. It helped with understanding of the issue i'm facing. Commented Jul 19, 2020 at 17:25

1 Answer 1

4

I know there's no one here to see this but I'm posting my solution if someone comes across this issue in the future. So here's what I figured out -

I haven't mentioned in my question that I was using a SSR (server side render) react framework called next.js. The import works perfectly fine with a pure react app. But in server side frameworks, the import related stuff should be done inside the useEffect (or componentDidMount) along with the rest of the threejs stuff. So I dynamically imported it like this -

let dynamicallyImportPackage = async () => { let TrackballControls await import('three/examples/jsm/controls/TrackballControls') // you can now use the package in here .then(module => { TrackballControls = module.TrackballControls }) .catch(e => console.log(e)) return TrackballControls } 

then, I used it in my useEffect like so -

let TrackbackControls = await dynamicallyImportPackage() // controls controls = new TrackbackControls(camera, container) controls.minDistance = 5 controls.maxDistance = 250 

Arigato Gosaimasu!

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.