TypeError by creating react app?

Hello guys,

I yesterday I was able to create my react babylon app with react-scripts. After updating babylon to 4.1.0 I receive the following error:

./node_modules/babylonjs/babylon.js
TypeError: /git/proconf_sa/node_modules/babylonjs/babylon.js: Property left of ForInStatement expected node to be of a type [“VariableDeclaration”,“LVal”] but instead got null

Any idea what the problem could be? I updated from version 3.1.0-alpha3.7.

Thanks.

EDIT:

It works after downgrading babylonjs as well as babylonjs-loaders to 3.1.0. Why am I not able to use the newest version?

It might be related to the version of typescript. You should try to update it ???

Would be great to know if using the es6 modules (@babylonjs/core) solved this (as then your ts version will be including it, instead of having the webpack-compiled version), thou i am not sure it will really help.

Are you using babylon extensively in the app? would you be able to share the (Babylon) code you are using?

I am using the latest version of typescript “3.8.3” globally.

Unfortunately my app won’t start with importing core modules. Here is my babylon code:

import React, { Component } from 'react'
import { TweenMax, Power2 } from "gsap"
import {
  Scene,
  Engine, 
  ArcRotateCamera,
  Vector3,
  HemisphericLight,
  Color3,
  Tools,
  Texture,
  MeshBuilder,
  StandardMaterial,
  SceneLoader
} from 'babylonjs'
import 'babylonjs-loaders'

class Scene3d extends Component {

  constructor(props) {
    super(props)
    this.moveCamera = this.moveCamera.bind(this)
    this.changeColor = this.changeColor.bind(this)
    this.myInput = React.createRef()
    this.state = {}
  }

  models = {
    standard: {
      name: "crate"
    },
    second: { 
      name: "bike"
    },
    third: { 
      name: "test"
    }
  }

  colors = {
    red: new Color3(0.5137, 0, 0),
    blue: new Color3(0, 0, 0.5137),
    green: new Color3(0.290, 0.741, 0.674),
    yellow: new Color3(0.968, 0.717, 0.2),
    black: new Color3(0, 0, 0),
    white: new Color3(1, 1, 1),
    grey: new Color3(0.5, 0.5, 0.5)
  }

  materials = {
    white_wood: {
      path: "/models/crate/white_wood.png"
    },
    brown_wood: {
      path: "/models/crate/Wooden Crate_Crate_BaseColor.png"
    },
    new_brown_wood: {
      path: "/models/crate/Wood_Bamboo_Medium.jpg"
    },
    metal: {
      path: "/models/crate/_Metal_Embossed_1.jpg"
    }
  }

  moveCamera = e => {
    TweenMax.to(this.camera, 1, {
        alpha: e.detail.alpha, 
        beta: e.detail.beta,
        radius: e.detail.radius, 
        ease: Power2.easeOut,
    })
  }

  changeModel = e => {
    if (Object.keys(this.models[e.detail.model]).includes("meshes") && e.detail.model !== this.props.productConfig.model) {
      this.models[this.props.productConfig.model].meshes.map(meshId => {
        return this.scene.getMeshByID(meshId).setEnabled(false)
      })
      this.models[e.detail.model].meshes.map(meshId => {
        return this.scene.getMeshByID(meshId).setEnabled(true)
      })
    } else if (!Object.keys(this.models[e.detail.model]).includes("meshes")) {
      this.models[this.props.productConfig.model].meshes.map(meshId => {
        return this.scene.getMeshByID(meshId).setEnabled(false)
      })
      this.addModel(e.detail.model)
    }
  }

  changeMaterial = e => {
    if (!this.materials[e.detail.material].isLoaded) {
      this.materials[e.detail.material].texture = new Texture(this.materials[e.detail.material].path)
      this.materials[e.detail.material].isLoaded = true
    }
    
    e.detail.meshIds.map(meshId => {
      return this.scene.getMeshByID(meshId).material.diffuseTexture = this.materials[e.detail.material].texture
    })
  }

  changeColor = e => {
    e.detail.meshIds.map(meshId => {
      return TweenMax.to(this.scene.getMeshByID(meshId).material.diffuseColor, 1, {
        r: this.colors[e.detail.color].r,
        g: this.colors[e.detail.color].g,
        b: this.colors[e.detail.color].b
      })
    })
  }

  changeSize = e => {
    e.detail.meshIds.map(meshId => {
      if (e.detail.size.x) {
        this.scene.getMeshByID(meshId).scaling.x = e.detail.size.x
      }
      if (e.detail.size.z) {
        this.scene.getMeshByID(meshId).scaling.z = e.detail.size.z
      }
      if (e.detail.size.y) {
        this.scene.getMeshByID(meshId).scaling.y = e.detail.size.y
      }
      return true
    })
  }

  onResizeWindow = () => {
    if (this.engine) {
      this.engine.resize()
    }
  }
  
  setEngine = () => {
    this.engine = new Engine(this.stage)
  }

  setScene = () => {
    this.scene = new Scene(this.engine)
  }

  setCamera = () => {
    this.camera = new ArcRotateCamera("default camera", Tools.ToRadians(200), Tools.ToRadians(70), 15, new Vector3(0, 2.5, 0), this.scene);
    this.camera.attachControl(this.stage, true)
    this.camera.lowerAlphaLimit = Tools.ToRadians(.00001)
    this.camera.upperAlphaLimit = Tools.ToRadians(360)
    this.camera.upperBetaLimit = Tools.ToRadians(80)
    this.camera.lowerRadiusLimit = 5
    this.camera.upperRadiusLimit = 20
    this.camera.wheelPrecision = 100
  }

  setLight = () => {
    new HemisphericLight('light1', new Vector3(0, 1, 0), this.scene)
  }

  setSceneEnvironment = state => {
    this.loadGround(state)
    this.setSceneBackground(state)
  }

  loadGround = state => {
    var grassMaterial = new StandardMaterial("grass", this.scene)
    grassMaterial.diffuseTexture = new Texture('textures/grass.jpg', this.scene)

    let ground = MeshBuilder.CreateGround('ground', { width: 1000, height: 1000 }, this.scene, true)
    ground.material = grassMaterial

    if (!state) {
      ground.setEnabled(false)
    }
  }

  setSceneBackground = state => {
    if (state) {
      this.scene.clearColor = new Color3(0.53, 0.81, 0.92)
    } else {
      this.scene.clearColor = new Color3(1, 1, 1)
    }
  }

  toggleEnv() {
    const ground = this.scene.getMeshByID("ground")

    if (ground && ground._isEnabled) {
      TweenMax.to(this.scene.clearColor, .5, {
        r: 1,
        g: 1,
        b: 1
      })
      TweenMax.to(ground.material, .5, {
        alpha: 0
      })
      ground.setEnabled(false)
    } else if (ground && ground._isEnabled === false) {
      ground.setEnabled(true)
      TweenMax.to(ground.material, .5, {
        alpha: 1
      })
      TweenMax.to(this.scene.clearColor, 1, {
        r: 0.53,
        g: 0.81,
        b: 0.92
      })
    }
  }

  loadEnvToggler = () => {
    const ground = this.scene.getMeshByID("ground")
    
    const envToggler = document.createElement("button")
    envToggler.className = "env_toggler"
    envToggler.innerText = ground ? ground._isEnabled ? "Hintergrund deaktivieren" : "Hintergrund aktivieren" : null
    envToggler.onclick = e => {
      this.toggleEnv()
      e.target.innerText = ground ? ground._isEnabled ? "Hintergrund deaktivieren" : "Hintergrund aktivieren" : null
    }
    document.body.appendChild(envToggler)
  }

  loadInitialSetup = model => {
    var initialMeshes = []
    this.scene.meshes.map(mesh => {
      return initialMeshes.push(mesh.id)
    })

    this.models.initialSetup = {}
    this.models.initialSetup.meshes = initialMeshes

    SceneLoader.Append("/models/" + this.models[model].name + "/", this.models[model].name + ".babylon", this.scene, scene => {
      const initialMeshes = this.models.initialSetup.meshes
      var activeMeshes = []
      this.scene.meshes.map(mesh => {
        return activeMeshes.push(mesh.id)
      })
      const meshes = activeMeshes.filter(mesh => !initialMeshes.includes(mesh))
      this.models[model].meshes = meshes

      this.setDefaultConfiguration(meshes)
      this.setSceneEnvironment(false)
      this.loadEnvToggler()
    })
  }

  addModel = model => {
    SceneLoader.Append("/models/" + this.models[model].name + "/", this.models[model].name + ".babylon", this.scene, () => {
      this.setSceneEnvironment()

      var oldActiveMeshes = []
      Object.keys(this.models).map(oldModel =>
        oldModel !== model ? oldActiveMeshes.push(this.models[oldModel].meshes) : null
      )
      var totalOldActiveMeshes = [].concat.apply([], oldActiveMeshes)

      const activeMeshes = []
      this.scene.meshes.map(mesh => {
        return activeMeshes.push(mesh.id)
      })

      const meshes = activeMeshes.filter(mesh => !totalOldActiveMeshes.includes(mesh))
      this.models[model].meshes = meshes

      this.setDefaultConfiguration(meshes)
    })
  }

  setDefaultConfiguration = meshes => {
    this.changeMaterial({ detail: {
      meshIds: meshes,
      material: this.props.productConfig.material
    }})

    this.changeColor({ detail: {
      meshIds: meshes,
      color: this.props.productConfig.color
    }})

    this.changeSize({ detail: {
      meshIds: meshes,
      size: {
        x: this.props.productConfig.width,
        z: this.props.productConfig.length,
        y: this.props.productConfig.height
      }
    }})
  }

  componentDidMount() {
    this.setEngine()
    this.setScene()
    this.setCamera()
    this.setLight()
    this.setSceneEnvironment()

    window.addEventListener('resize', this.onResizeWindow)
    window.addEventListener('move-camera', this.moveCamera)
    window.addEventListener('change-model', this.changeModel)
    window.addEventListener('change-material', this.changeMaterial)
    window.addEventListener('change-color', this.changeColor)
    window.addEventListener('change-size', this.changeSize)

    this.loadInitialSetup(this.props.productConfig.model)

    this.engine.runRenderLoop(() => { 
      this.scene.render()
    })

    this.setBodyHeight()
  }

  setBodyHeight = () => {
    this.setState({ bodyHeight: this.stage.width }, () => {
      this.engine.resize()
    })
  }

  render() {
    return (
      <canvas className="scene" style={{ height: this.state.bodyHeight }} ref={ el => this.stage = el}></canvas>
      
    )
  }
}

export default Scene3d

I tried your code on my machine setting up a project with TS and React and after a lot of tiny fixed typos around typings it is all ok for me :frowning: I am totally unable to repro your case.

Would it be possible for you to share your project on github ?

1 Like

I appreciate your help. I shared the project with you on github. Thank you!

I just downloaded your code npm install and than npm run build -> ALL GOOD

Then I tried npm start and I can see the full app running.

I can not seem to repro locally :frowning: What procedure are you following ?

1 Like

I am seeing a random error here which is due to the window globals not being set before the page loads:

window.ressourceConf = ressourceConf
window.modelConf = modelConf
window.initialModel = “standard”

is called after setDefaultConfig

This prevents the app to start but all the packages and wiring looks good :slight_smile:

That’s the weird thing. The error only appears when you try yarn build. It’s no problem to start the app. Please try to build it.

Yes, this error appears sometimes but it works after reloading the page. It’s only for development anyway. In production I will pass the data via nodejs and there the error never occurs.

Ok, so what issue should I look into ?

You don’t receive an error if you try yarn build? I can’t build the app because of this.

And I don’t receive this error with Babylon js 3.2 or less.

I ll give it another try but i was not.

Thank you. Please let me know if you can reproduce the error.

It looks all good to me :frowning:

Okay, that’s weird. It has to be a local problem on my end then. I will try to solve this. If I can find a solution I will post it here. Thank you!

Try to clone back the project you shared with me on a separate folder just in case there are any issues in the node_modules ?

Unfortunately it doesn’t work with cloning the project to a new folder too.

I have no idea what it could be then as your project works totally ok for me :frowning:

What os and versions of node/ts are you using ???

Yes, it’s weird.

I am using mac mojave, node 13.8 and tsc 3.8.3.