Search code examples
javascriptreactjstensorflownetlify

TypeError: Cannot call a class as a function after deploying to Netlify?


Hello I am trying to deploy a web app to Netlify. It uses the COCO SSD model for object recognition in the frontend, which is purposeful. The web app works perfectly fine on localhost but once I deploy to Netlify I get this error:

detector.js:47 TypeError: Cannot call a class as a function
    at r (classCallCheck.js:3)
    at new t (tensor.ts:266)
    at t.value (engine.ts:736)
    at i (tensor_ops_util.ts:75)
    at i (tensor.ts:55)
    at Module.p (io_utils.ts:223)
    at t.value (graph_model.ts:139)
    at t.<anonymous> (graph_model.ts:119)
    at c (runtime.js:63)
    at Generator._invoke (runtime.js:293)

I have never had this problem before and find it very odd, this is my code for implementation of the COCO SSD model and the class.

import React from 'react';
import Lottie from 'react-lottie';
import * as cocoSsd from '@tensorflow-models/coco-ssd';
import '@tensorflow/tfjs';

class Detector extends Component {
  constructor(props) {
    super(props);

    this.state = {
      count: 0,
      list: ['person','laptop','scissors','mouse', 'spoon', 'keyboard',],
      isStopped: true,
    }
  } 
  videoRef = React.createRef();

  componentDidMount() {
    if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
      //getting camera permission code removed for readability
      const modelPromise = cocoSsd.load();
      Promise.all([modelPromise, webCamPromise])
        .then(values => {
          this.detectFrame(this.videoRef.current, values[0]);
        })
        .catch(error => {
          console.error(error);
        });
    }
  }

  detectFrame = (video, model) => {
    model.detect(video).then(predictions => {
      this.checkPredictions(predictions);
      requestAnimationFrame(() => {
        this.detectFrame(video, model);
      });
    });
  };

  checkPredictions = predictions => {
    predictions.forEach(prediction => {
      if(prediction.class === this.state.list[0]) {
        const tempL = this.state.list;
        const tempC = this.state.count + 1;
        tempL.shift();
        this.setState({list: tempL, count: tempC, isStopped: false});
      }
    });
  };

  render() {
    return (
      <div>
        //removed for readability
      </div>
    );
  }
}

export default Detector;

Solution

  • It looks like webpack has picked the field (the built file) of @tensorflow/tfjs in case of production mode which ends up the problem.

    But we can specify this field manually which describes here https://webpack.js.org/configuration/resolve/#resolvemainfields

    In order to do it, you just simply switch to use react-app-rewired where we can customize webpack configuration. Here is the steps:

    • Install
    npm i -D react-app-rewired
    
    • Create the override config file at the root repo config-overrides.js with following content:
    module.exports = function override(config, env) {
      if (process.env.NODE_ENV === 'production')
      {
        config.resolve.mainFields = ['main'];
      }
      return config;
    }
    
    • Switch to use react-app-rewired script by replacing the react-scripts commands:
    "scripts": {
      "start": "react-app-rewired start",
      "build": "react-app-rewired build",
      // ...  
    },
    

    Finally, you can run npm build and serve your built content to test it. That's it!