Search code examples
reactjsherokuwebpacknetlify

Trouble getting Heroku App to run but I can get it to run locally


Says that webpack compiled successfully when I enter git push heroku main but when I check heroku logs --tail it shows that my build failed and the link to my app goes to the default initial heroku page.

I've tried updating my webpack.config.js by adding

  resolve: {
    extensions: ['.js', '.jsx'],
  },

And then removing all my extensions on my actual React components like so

Before:
import SearchContainer from './SearchContainer.jsx';
import Promoted from './Promoted.jsx';
import Products from './Products.jsx';
After:
import SearchContainer from './SearchContainer';
import Promoted from './Promoted';
import Products from './Products';

I've also double-checked my files for case sensitivity multiple times, making sure to re-add the files on git using the below command and back checked that everything matched:

git rm -rf --cached .
git add .

Really stumped on this. A link to my application is here. A similar thing happened when I tried to deploy on Netlify. Everything works locally and then crashes when running on the sites. I switched to Heroku after attempting to debug Netlfiy for most of the day. If anyone has a solution for any either I'd really appreciate it. Below is the error message I get from Netlify, which might be helpful debugging what's happening with Heroku since Heroku isn't descriptive in its build fail output.

7:14:01 PM: ERROR in main
7:14:01 PM: Module not found: Error: Can't resolve 'babel-loader' in '/opt/build/repo'
resolve 'babel-loader' in '/opt/build/repo'
7:14:01 PM:   Parsed request is a module
7:14:01 PM:   using description file: /package.json (relative path: .opt/build/repo)
7:14:01 PM:     resolve as module
7:14:01 PM:       /opt/build/repo/node_modules doesn't exist or is not a directory
      /opt/build/node_modules doesn't exist or is not a directory
      /opt/node_modules doesn't exist or is not a directory
      /node_modules doesn't exist or is not a directory
7:14:01 PM: webpack 5.30.0 compiled with 1 error in 54 ms
7:14:01 PM: assets by status 670 bytes [cached] 1 asset
7:14:01 PM: ERROR in main
7:14:01 PM: Module not found: Error: Can't resolve './client/src/index' in '/opt/build/repo'
resolve './client/src/index' in '/opt/build/repo'
7:14:01 PM:   using description file: /package.json (relative path: .opt/build/repo)
7:14:01 PM:     Field 'browser' doesn't contain a valid alias configuration
    using description file: /package.json (relative path: .opt/build/repo/client/src/index)
7:14:01 PM:       no extension
7:14:01 PM:         Field 'browser' doesn't contain a valid alias configuration
        /opt/build/repo/client/src/index doesn't exist
      .js
7:14:01 PM:         Field 'browser' doesn't contain a valid alias configuration
        /opt/build/repo/client/src/index.js doesn't exist
      .jsx
7:14:01 PM:         Field 'browser' doesn't contain a valid alias configuration
        /opt/build/repo/client/src/index.jsx doesn't exist
      as directory
7:14:01 PM:         /opt/build/repo/client/src/index doesn't exist
7:14:01 PM: webpack 5.30.0 compiled with 1 error in 11 ms
7:14:06 PM: Build exceeded maximum allowed runtime

Solution

  • Several things that I would recommend:

    1. build command has a --watch option. The watcher might be needed for your local development but it is not on the server. It just hangs in the build pipeline and potentially times-out the build. Have two webpack configs (from one common one); one for development and one for production (server):

    webpack.common.config.js:

    const path = require('path');
    
    module.exports = {
      entry: './client/src/index',
      output: {
        filename: 'bundle.js',
        path: path.resolve(__dirname, './client/dist'),
        publicPath: '/'
      },
      resolve: {
        modules: ['node_modules'],
        extensions: ['.js', '.jsx'],
      },
      module: {
        rules: [
          {
            test: /\.(js|jsx)$/,
            exclude: /node_modules/,
            use: {
              loader: 'babel-loader',
              options: {
                presets: ['@babel/preset-env', '@babel/preset-react'],
              },
            },
          },
        ],
      },
    };
    

    webpack.development.config.js:

    const CommonWebpack = require('./webpack.common.config');
    
    module.exports = {
      ...CommonWebpack,
      watch: true,
      mode: 'development',
      devtool:'inline-source-map'
    };
    

    webpack.production.config.js:

    const CommonWebpack = require('./webpack.common.config');
    
    module.exports = {
      ...CommonWebpack,
      watch: false,
      mode: 'production',
      devtool: false,
    };
    

    Have a separate command with the watch for local development. For example:

    "scripts": {
      "test": "echo \"Error: no test specified\" && exit 1",
      "start": "nodemon server",
      "build": "webpack --config webpack.production.config.js",
      "client-development": "webpack --config webpack.development.config.js"
    }
    
    1. No need for nodemon on the server, change your Procfile to
    web: node server/index.js
    
    1. The express app has a hardcoded PORT of 3000. Heroku assigns each app a PORT (via the run environment) according its own internal systems. Change the listen to:
    const PORT = process.env.PORT || 3000;
    app.listen(PORT, () => {
      console.log(`listening on port ${PORT}!`);
    });