简体   繁体   中英

“Cannot find module” error on Heroku when deploying

So, I am making an app with React, and I am deploying it to Heroku afterwards. Everything works great in localhost and without any errors, and webpack also compiles with no errors. I have set env variales on Heroku as well.

However, when I deploy it to Heroku I get a blank screen and this error in console(I am requiring TodoApi properly and have tried various ways - import etc., it works in localhost with no issues):

I am trying to figure out it for days, so any help is much appreciated.

Uncaught Error: Cannot find module "TodoApi"
    at bundle.js:20
    at Object.<anonymous> (bundle.js:20)
    at t (bundle.js:1)
    at Object.<anonymous> (bundle.js:20)
    at t (bundle.js:1)
    at Object.<anonymous> (bundle.js:3)
    at Object.<anonymous> (bundle.js:3)
    at t (bundle.js:1)
    at Object.<anonymous> (bundle.js:1)
    at t (bundle.js:1)

Here are my webpack and package.json files:

var webpack = require('webpack');
var path = require('path');
var envFile = require('node-env-file');

process.env.NODE_ENV = process.env.NODE_ENV || 'development';

try {
    envFile(path.join(__dirname, 'config/' + process.env.NODE_ENV + '.env'));
} catch(e) {

}

module.exports = {
  entry: [
    'script!jquery/dist/jquery.min.js',
    'script!foundation-sites/dist/js/foundation.min.js',
    './app/app.jsx'
  ],
  externals: {
      jquery: 'jQuery'
  },
  plugins: [
      new webpack.ProvidePlugin({
          '$': 'jquery',
          'jQuery': 'jquery'
      }),
      new webpack.optimize.UglifyJsPlugin({
          compressor: {
              warnings: false
          }
      }),
      new webpack.DefinePlugin({
        'process.env': {
          NODE_ENV: JSON.stringify(process.env.NODE_ENV),
          API_KEY: JSON.stringify(process.env.API_KEY),
          AUTH_DOMAIN: JSON.stringify(process.env.AUTH_DOMAIN),
          DATABASE_URL: JSON.stringify(process.env.DATABASE_URL),
          STORAGE_BUCKET: JSON.stringify(process.env.STORAGE_BUCKET),
          MESSAGING_SENDER_ID: JSON.stringify(process.env.MESSAGING_SENDER_ID)
        }
      })
  ],
  output: {
    path: __dirname,
    filename: './public/bundle.js'
  },
  resolve: {
    root: __dirname,
    modulesDirectories: [
        'node_modules',
        './app/components',
        './app/api'
    ],
    alias: {
        app: 'app',
        applicationStyles: 'app/styles/app.scss',
        actions: 'app/actions/actions.jsx',
        reducers: 'app/reducers/reducers.jsx',
        configureStore: 'app/store/configureStore.jsx'
    },
    extensions: ['', '.js', '.jsx']
  },
  module: {
    loaders: [
      {
        loader: 'babel-loader',
        query: {
          presets: ['react', 'es2015', 'stage-0']
        },
        test: /\.jsx?$/,
        exclude: /(node_modules|bower_components)/
      }
    ]
  },
  devtool: process.env.NODE_ENV === 'production' ? undefined : 'cheap-module-eval-source-map'
};


{
  "name": "reactapp",
  "version": "1.0.0",
  "description": "ReactApp",
  "main": "index.js",
  "scripts": {
    "test": "NODE_ENV=test karma start",
    "build": "webpack",
    "start": "npm run build && node server.js"
  },
  "author": "John Smith",
  "license": "MIT",
  "dependencies": {
    "axios": "^0.16.0",
    "babel-core": "^6.5.1",
    "babel-loader": "^6.2.2",
    "babel-preset-es2015": "^6.5.0",
    "babel-preset-react": "^6.5.0",
    "babel-preset-stage-0": "^6.5.0",
    "css-loader": "^0.23.1",
    "deep-freeze-strict": "^1.1.1",
    "expect": "^1.20.2",
    "express": "^4.13.4",
    "firebase": "^3.9.0",
    "foundation-sites": "^6.3.1",
    "jquery": "^2.2.1",
    "moment": "^2.18.1",
    "node-env-file": "^0.1.8",
    "node-sass": "^4.5.2",
    "react": "^0.14.7",
    "react-addons-test-utils": "^0.14.6",
    "react-dom": "^0.14.7",
    "react-redux": "^5.0.4",
    "react-router": "^2.0.0",
    "redux": "^3.6.0",
    "redux-mock-store": "^1.2.3",
    "redux-thunk": "^2.2.0",
    "sass-loader": "^6.0.3",
    "script-loader": "^0.6.1",
    "style-loader": "^0.13.0",
    "uuid": "^3.0.1",
    "webpack": "^1.12.13"
  },
  "devDependencies": {
    "karma": "^0.13.22",
    "karma-chrome-launcher": "^0.2.3",
    "karma-mocha": "^0.2.2",
    "karma-mocha-reporter": "^2.2.3",
    "karma-sourcemap-loader": "^0.3.7",
    "karma-webpack": "^1.8.1",
    "mocha": "^2.5.3"
  }
}

var React = require('react');
var { connect } = require('react-redux');
import Todo from 'Todo';
var TodoApi = require('TodoApi');

export var TodoList = React.createClass ({
    render: function() {
        var { todos, showCompleted, searchText } = this.props;
        var renderTodos = () => {
            var filteredTodos = TodoApi.filterTodos(todos, showCompleted, searchText);

            if(filteredTodos.length === 0) {
                return (
                    <p className="container__message">No tasks</p>
                );
            }
            return filteredTodos.map((todo) => {
                return (
                    //add unique key prop to keep track of individual components
                    <Todo key={todo.id} {...todo} />
                );
            });
        };
        return (
            <div>
                {renderTodos()}
            </div>
        );  
    }
});

export default connect(
    (state) => {
        return state;
    }
)(TodoList);

You are requiring TodoApi but this package doesn't exist in your package.json

In your TodoList.jsx Component

var TodoApi = require("TodoApi");

A quick look through the repo shows that the package doesn't exist anywhere.

I think your problem lies in resolve part of your webpack configuration file. It seems resolve.modulesDirectories doesn't do it job correctly when you deploy to Heroku. I feel it make more sense to configure resolving your './app/components' and './app/api' with resolve.root instead of resolve.modulesDirectories . So try out following resolve configuration and probably it will work with Heroku.

resolve: {
    root: [
        __dirname,
        path.resolve(__dirname, "app/components"),
        path.resolve(__dirname, "app/api")
    ],
    modulesDirectories: [ 'node_modules' ],
    alias: {
        app: 'app',
        applicationStyles: 'app/styles/app.scss',
        actions: 'app/actions/actions.jsx',
        reducers: 'app/reducers/reducers.jsx',
        configureStore: 'app/store/configureStore.jsx'
    },
    extensions: ['', '.js', '.jsx']
}

The problem is exactly what it says. The TodoApi.

Locally it will work because the TodoApi is probably in your "node_modules" directory. (You didn't include it locally in your index.html did you?) The problem is that it is not packed into the deployment package. That's why it doesn't work.

First, don't know if you noticed but you (wan't to) include node_modules under modulesDirectories and later under module.loaders you exclude it again. Luckily for you it didn't include, otherwise you would still be building, lol. Besides that you can just delete the modulesDirectories passage. And don't ever think it's a good idea to include node_modules as a directory into anything. ;)

I would do the following to bring some structure, so you can clearly see what is included and what not. At the top of you webpack define some absolute directories:

// Absolute directories
const root    = (...dir) => path.resolve(__dirname, ...dir);
const lib     = root('lib'),
      src     = root('src'), // or 'app'
      project = root('.');

This you know for sure what directory is assigned and it reads easier. Then set your entry-file.

const entry   = root('app/app.jsx'); 

And change it under module exports:

root: src,
context: src,
entry: entry,
...

I always set the context to my src directory, that means that so far webpack is concerned src is the top directory. Remove the other stuff under entry.

I would also comment out the Uglify plugin while you don't have the build working yet, just to exclude stuff that can create error's of their own.

Install the webpack-bundle-analyzer .

npm i --save-dev webpack-bundle-analyzer

And add it to your webpack plugins like this:

      new BundleAnalyzerPlugin({
        analyzerMode: 'server',
        analyzerHost: 'localhost',
        analyzerPort: 9002,
        reportFilename: 'report.html',
        openAnalyzer: true,
        // Log level. Can be 'info', 'warn', 'error' or 'silent'.
        logLevel: 'info'
      })

This will open a nice graphical view of your package after the build. One of the blocks needs to mention "TodoApi" and then you're good. If you first add the BundleAnalyzerPlugin without changing your code, then you can see that the TodoApi probably isn't in there.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM