Nathan Jones
Nathan Jones

Reputation: 28

express.static() only works when run locally

For some reason when I run my express server on my machine it it serves the static files in my build folder without any problem, but when I deploy on Heroku I'm getting the following 404 error:

HTTP404: NOT FOUND - The server has not found anything matching the requested URI (Uniform Resource Identifier).
GET - http://playcheckerswithme.herokuapp.com/

Here's my directory structure:

.
├──index.js
├──webpack.config.js
├──package.json
├──.gitignore
├──node_modules
|  ├── ...
|
├──src
|  ├──assets
|  |  ├──index.html
|  |  ├──images
|  |  |  ├──...
|  |
|  ├──components
|  |  ├──...
|  |
|  ├──reducers
|     ├──...
|
├──build
   ├──index.html
   ├──bundle.js
   ├──images
      ├──...

And here's index.js:

var express = require('express');
var app = express();
var http = require('http').Server(app);

app.use(express.static(__dirname + '/build'))

http.listen(process.env.PORT || 3000, function(){
  console.log(`listening on port: ${process.env.PORT || '3000'}`);
});

app.use(express.static(__dirname + '/build')) should be serving all static files in my build folder, but it seems that in production it isn't working correctlly. Any ideas?

Edit -

For extra context here are my package.json and webpack.config.js files

package.json

{
  "name": "Checkers",
  "version": "1.0.0",
  "description": "react + redux + express environment for a checkers app",
  "private": true,
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "webpack-server": "webpack-dev-server --hot --progress --colors",
    "start": "node build/index.js"
  },
  "keywords": [],
  "author": "Nathan Jones",
  "devDependencies": {
    "autoprefixer-loader": "^3.1.0",
    "babel-core": "^6.3.21",
    "babel-loader": "^6.2.0",
    "babel-preset-es2015": "^6.3.13",
    "babel-preset-react": "^6.3.13",
    "babel-preset-stage-0": "^6.3.13",
    "copy-webpack-plugin": "^4.0.1",
    "file-loader": "^0.10.0",
    "react-hot-loader": "^1.2.8",
    "source-map-loader": "^0.1.5",
    "url-loader": "^0.5.7",
    "webpack": "^1.11.0",
    "webpack-dev-server": "^1.10.1"
  },
  "dependencies": {
    "express": "^4.15.2",
    "react": "^15.4.2",
    "react-dom": "^15.4.2",
    "react-redux-utilities": "^1.0.7"
  }
}

webpack.config.js

var { resolve } = require('path');
var webpack = require('webpack');

var ExtractTextPlugin = require('extract-text-webpack-plugin');
var CopyWebpackPlugin = require('copy-webpack-plugin');

function getEntrySources(sources) {
  if (process.env.NODE_ENV !== 'production') {
    sources.push('webpack-dev-server/client?http://localhost:8080');
    sources.push('webpack/hot/only-dev-server');
  }
  return sources;
}

module.exports = {
  entry: getEntrySources(['./src/app.js']),
  
  output: {
    filename: 'bundle.js',
    path: resolve(__dirname, 'build'),
    publicPath: '/'
  },
  
  devtool: 'source-map',
  
  devServer: {
    inline: true,
    hot: true,
    contentBase: resolve(__dirname, 'build'),
    publicPath: '/'
  },
  
  module: {
    preLoaders: [
      {
        test: /\.jsx?$/,
        exclude: /node_modules/,
        loader: 'source-map'
      }
    ],
    loaders: [
      {
        test: /\.jsx?$/,
        exclude: /node_modules/,
        loaders: ['react-hot', 'babel-loader?presets[]=es2015,presets[]=react,presets[]=stage-0'],
      },
      {
        test: /\.scss$/,
        loader: ExtractTextPlugin.extract(
          'style-loader',
          'css-loader?sourceMap!autoprefixer?browsers=last 3 versions!sass-loader?sourceMap'
        )
      },
      {
        test: /\.(ttf|otf|eot|svg|woff(2)?)(\?[a-z0-9]+)?$/, 
        loader: 'file-loader?name=fonts/[name].[ext]'
      },
      {
        test: /\.(png|jpg|jpeg)$/,
        loader: 'url-loader'
      }
    ]
  },

  plugins: [
    new webpack.HotModuleReplacementPlugin(),
    new CopyWebpackPlugin([{from: 'src/assets/', force: true}], {copyUnmodified: true})
  ]
};

Upvotes: 1

Views: 2500

Answers (2)

idbehold
idbehold

Reputation: 17168

Your npm "start" script is "node build/index.js" which means that __dirname would be pointing to <project-root>/build. You need to change your build/index.js file to use this instead since it's already in the build folder:

if (__dirname.slice(-6) === '/build') { // For production
  app.use(express.static(__dirname))
} else { // For development
  app.use(express.static(__dirname + '/build'))
}

Upvotes: 1

mcek
mcek

Reputation: 490

Try remove slash:

app.use(express.static(__dirname + 'build'));

or use path module:

var express = require('express');
var path = require('path');
var app = express();
var http = require('http').Server(app);

app.use(express.static(path.join(__dirname, 'build')));

http.listen(process.env.PORT || 3000, function(){
  console.log(`listening on port: ${process.env.PORT || '3000'}`);
});

Upvotes: 0

Related Questions