randal
randal

Reputation: 1362

express is not fetching react build folder

I'm trying to deploy a react + express app, but locally npm start does not fetch the react build that is within the client folder.

I have already done a react build, so a build folder does exist within the client folder.

folder structure

enter image description here

full folder structure

enter image description here

main.js

import 'dotenv/config';
import cors from 'cors';
import express from 'express';
import logger from 'morgan';
import path from 'path';
import bodyParser from 'body-parser';
import cookieParser from 'cookie-parser';
import userRoute from './routes/users';
import imageRoute from './routes/images';
import passport from 'passport';
import session from 'express-session';
import './config/passport';
import knex from 'knex';
import config from './knexfile'
import KnexSessionStore from 'connect-session-knex';
const knexSession = KnexSessionStore(session);
const myKnex = knex(config.development);
const store = new knexSession({
  knex:myKnex,
  // tablename:'sessions'
})

const app = express();

app.use(cors({
  origin:process.env.ALLOW_ORIGIN,
  preflightContinue: false,
  credentials: true,
  allowedHeaders: 'X-Requested-With, Content-Type, Authorization',
  methods: 'GET, POST, PATCH, PUT, POST, DELETE, OPTIONS',
  exposedHeaders: ['Content-Length', 'X-Foo', 'X-Bar'],
}))


app.use(logger('dev'));
// For React Stuff if need be
app.use(express.static(path.join(__dirname, 'public')));
app.use(express.static(path.join(__dirname, 'build')));
app.use(cookieParser());
app.use(bodyParser.json());
// you need body parser urlencoded so passport will not give a Missing Credentials error
app.use(session({
  store: store, 
  saveUninitialized: false,
  resave:false,
  cookie: {   maxAge: 30 * 24 * 60 * 60 * 1000 },  // 30 days
  secret : process.env.JWT_SECRET,

}));

app.use(passport.initialize());
app.use(passport.session());
app.use(bodyParser.urlencoded({ extended:false})); 
app.get('/', (req, res) => {
  res.send('Hello World!');
});
app.use('/users', userRoute);
app.use('/images', imageRoute);
// app.use('/images', imageRoute);
// app.use('/comments', imageRoute);
app.use(() => (req, res, next)  =>{
  res.locals.user = req.user; // This is the important line
  // req.session.user = user
  console.log(res.locals.user);
  next();
});

app.use('/', function (req, res, next) {
  var n = req.session.views || 0
  req.session.views = ++n
  res.end(n + ' views')
  console.log(n);
})

//build mode
app.use(express.static(path.join(__dirname, 'client/build')));
// if(process.env.NODE_ENV === 'production') {
  app.use(express.static(path.join(__dirname, 'client/build')));
  //
  app.get('*', (req, res) => {
    res.sendfile(path.join(__dirname = 'client/build/index.html'));
  })
// }
//build mode
app.get('*', (req, res) => {
  res.sendFile(path.join(__dirname+'/client/public/index.html'));
})


// module.parent prevents the 
// Node / Express: EADDRINUSE, Address already in use error when unit testing
if(!module.parent){
  app.listen(process.env.PORT, () =>
    console.log(`Example app listening on port ${process.env.PORT}!`),
  );
 }

export default app;

package.json

{
  "name": "somethingapp",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "client-install": "npm install --prefix client",
    "test": "./node_modules/.bin/mocha --watch --require @babel/register",
    "server": "nodemon --exec babel-node main.js",
    "client": "cd ./client && npm start ",
    "start": "babel-node main.js",
    "startdev": "concurrently --kill-others  \"npm run client\" \"npm run server\" ",
    "migrate": "babel-node node_modules/.bin/knex migrate:latest",
    "rollback": "babel-node node_modules/.bin/knex migrate:rollback ",
    "seed": "babel-node node_modules/.bin/knex seed:run",
    "heroku-postbuild": "NPM_CONFIG_PRODUCTION=false npm install --prefix client && npm run build --prefix client",
    "build": "concurrently \"cd client && npm run build\" \"npm build \""
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "bcrypt": "^3.0.6",
    "body-parser": "^1.19.0",
    "bookshelf": "^0.14.2",
    "bookshelf-validate": "^2.0.3",
    "chai-http": "^4.3.0",
    "cloudinary": "^1.14.0",
    "concurrently": "^4.1.0",
    "connect-multiparty": "^2.2.0",
    "connect-session-knex": "^1.4.0",
    "cookie-parser": "^1.4.4",
    "cors": "^2.8.5",
    "dotenv": "^8.0.0",
    "dump-die": "^1.0.0",
    "express": "^4.17.0",
    "express-session": "^1.16.1",
    "express-validator": "^5.3.1",
    "jsonwebtoken": "^8.5.1",
    "knex": "^0.16.5",
    "morgan": "^1.9.1",
    "multer": "^1.4.1",
    "multiparty": "^4.2.1",
    "passport": "^0.4.0",
    "passport-github": "^1.1.0",
    "passport-google-oauth": "^2.0.0",
    "passport-google-oauth20": "^2.0.0",
    "passport-jwt": "^4.0.0",
    "passport-local": "^1.0.0",
    "path": "^0.12.7",
    "pg": "^7.11.0",
    "validator": "^11.0.0",
    "var_dump": "^1.0.5"
  },
  "devDependencies": {
    "@babel/cli": "^7.4.4",
    "@babel/core": "^7.4.5",
    "@babel/node": "^7.4.5",
    "@babel/preset-env": "^7.4.5",
    "@babel/register": "^7.4.4",
    "chai": "^4.2.0",
    "mocha": "^6.1.4",
    "nodemon": "^1.19.0",
    "reify": "^0.19.1",
    "request": "^2.88.0"
  }
}

client/package.json

{
  "name": "client",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@material-ui/core": "^4.0.1",
    "axios": "^0.18.0",
    "jsonwebtoken": "^8.5.1",
    "jwt-decode": "^2.2.0",
    "moment": "^2.24.0",
    "react": "^16.8.6",
    "react-dom": "^16.8.6",
    "react-github-login": "^1.0.3",
    "react-google-login": "^5.0.4",
    "react-images-upload": "^1.2.6",
    "react-redux": "^7.0.3",
    "react-router-dom": "^5.0.0",
    "react-scripts": "3.0.1",
    "react-social-login-buttons": "^2.3.1",
    "react-thunk": "^1.0.0",
    "redux": "^4.0.1",
    "redux-thunk": "^2.3.0"
  },
  "scripts": {
    "start": "PORT=3001 react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject",
    "heroku-postbuild": "npm run build"
  },
  "eslintConfig": {
    "extends": "react-app"
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  },
  "devDependencies": {
    "enzyme": "^3.10.0",
    "enzyme-adapter-react-16": "^1.14.0",
    "enzyme-to-json": "^3.3.5",
    "redux-devtools-extension": "^2.13.8",
    "redux-mock-store": "^1.5.3"
  },
  "jest": {
    "snapshotSerializers": [
      "enzyme-to-json/serializer"
    ]
  }
}

Upvotes: 2

Views: 1131

Answers (1)

John Ruddell
John Ruddell

Reputation: 25842

It looks like you are trying to expose the build folder in a few different places in the code.

You should drop app.use(express.static(path.join(__dirname, 'build'))); as that path is invalid. Further down inside main.js you are doing the correct path, but your production if block is obsolete and can potentially mess up the paths again. So you can remove that as well.

Aka translate this

//build mode
app.use(express.static(path.join(__dirname, 'client/build')));
// if(process.env.NODE_ENV === 'production') {
  app.use(express.static(path.join(__dirname, 'client/build')));
  //
  app.get('*', (req, res) => {
    res.sendfile(path.join(__dirname = 'client/build/index.html'));
  })
// }
//build mode
app.get('*', (req, res) => {
  res.sendFile(path.join(__dirname+'/client/public/index.html'));
})

to this

//build mode
app.use(express.static(path.join(__dirname, 'client/build')));
app.get('*', (req, res) => {
  res.sendFile(path.join(__dirname, '/client/public/index.html'));
})

Upvotes: 2

Related Questions