在部署到Heroku时出现“找不到模块”错误

12

我正在使用React制作一个应用程序,并在之后将其部署到Heroku。在本地主机上一切都很顺利,没有任何错误,webpack也没有编译错误。我已经在Heroku上设置了环境变量。

然而,当我将其部署到Heroku时,我得到一个空白屏幕和控制台中的以下错误(我已经正确地引入了TodoApi并尝试了各种方式 - import等,在本地主机上没有问题):

我已经尝试了几天来解决这个问题,所以非常感谢任何帮助。

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)

这是我的webpack和package.json文件:
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);

2
TodoApi是一个外部包吗? - Cjmarkham
1
我在几年前遇到了这个问题,当时尝试在 Heroku 上使用 Node.js 的 MongoDB 驱动程序,因此这并不是一个特定于模块的问题。但我从未找到答案,最终不得不改用 DigitalOcean。 - Peter G
1
你的本地主机基于哪个操作系统? - Dez
2
你尝试过删除本地的 node 模块并重新安装它们吗?这样你就可以在本地复制了。 - mrsq
1
一个可能的提示。Windows不区分大小写,而Heroku区分大小写。如果您尝试使用大写字母要求TodoApi包,请小心。我不知道是否有任何npm包名称带有大写字母。我认为不会,因为在后续版本中,您必须将软件包名称转换为小写。 - Dez
显示剩余2条评论
3个回答

1
问题就是它所说的那样。TodoApi。
在本地它能够工作,因为TodoApi可能在你的“node_modules”目录下。(你没有在index.html中包含它吧?)问题在于它没有打包到部署包中。这就是为什么它不能工作的原因。
首先,不知道你是否注意到了,你在modulesDirectories下包含了node_modules,然后在module.loaders下又将其排除了。幸运的是,它没有被包括进去,否则你仍然会构建失败,哈哈。此外,你可以直接删除modulesDirectories,永远不要认为将node_modules包含在任何目录中是个好主意。;)
我会做以下操作来带来一些结构,这样你就可以清楚地看到包含了什么以及没有包含什么。在你的webpack顶部定义一些绝对目录:
// Absolute directories
const root    = (...dir) => path.resolve(__dirname, ...dir);
const lib     = root('lib'),
      src     = root('src'), // or 'app'
      project = root('.');

你可以确定分配了哪个目录,并且这样阅读更加容易。 然后设置你的入口文件。

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

并在模块输出下更改它:

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

我总是将上下文设置为我的src目录,这意味着就目前而言,webpack认为src是顶级目录。删除entry下的其他内容。
在您的构建尚未工作时,我还会注释掉Uglify插件,以排除可能创建自己错误的内容。
安装webpack-bundle-analyzer。
npm i --save-dev webpack-bundle-analyzer

把它加到你的 Webpack 插件中,就像这样:

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

这将在构建后打开一个漂亮的图形化视图,其中一个块需要提到“TodoApi”,然后你就可以了。如果你首先添加BundleAnalyzerPlugin而不改变你的代码,那么你会发现TodoApi可能没有在里面。


1
很多用于开发的模块都在你的依赖项中,应该放在devDependencies中(例如* -loader、test、sass等)。你真的应该清理并检查你正在使用的内容。一个良好的清晰结构和代码风格将为你节省大量时间来修复问题... - therebelcoder

0

我认为你的问题在于webpack配置文件中的resolve部分。当你部署到Heroku时,resolve.modulesDirectories似乎无法正确地完成其工作。我觉得使用resolve.root来配置解析'./app/components'和'./app/api'更有意义,而不是使用resolve.modulesDirectories。因此,请尝试以下resolve配置,可能会在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']
}

-1

您正在使用 TodoApi,但是该包在您的 package.json 中不存在

在您的 TodoList.jsx 组件中

var TodoApi = require("TodoApi");

快速查看存储库显示该包不存在于任何地方。


我稍后已经包含了它,但问题仍然存在,所以应用程序在本地主机上运行正常,只有当我将其部署到Heroku时才会出现这种情况。我已经编辑了帖子并包含了我的当前TodoList组件。因此,TodoApi只是api文件夹中的一个jsx文件。 - Smithy
1
好的,那么问题在于您需要指定到 TodoApi 的路径。var TodoApi = require('../api/TodoApi') - Cjmarkham
谢谢,但是我已经尝试了所有变体,包括导入和从不同的路径中导入,似乎这不是问题。如果出现错误的路径,我想应用程序会立即在本地主机上崩溃.... 我也认为我应该尝试阶段1和最新的babel预设,但我总是得到相同的错误。我最好的猜测是它与Heroku或者它如何读取路径有关,也许它对npm模块的处理方式与本地机器不同...? - Smithy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接